Modules

At this point, we haven’t really covered what makes Webpack different from any other task runner. This is where it gets special.

Out of the box, Webpack enables you to organize your JavaScript into modules: reusable, single-purpose JavaScript files that together form up your entire application. The idea is that each module does one thing and one thing well, and each module handles its own dependencies. If both module-a.js and module-b.js needed library-x, they both will ask for them:

import {something, otherThing} from 'library-x';

Webpack will figure everything out from there. For more info, read about ES6’s import.

Importing Your Own Modules

Let’s move the log message Hello World to its own module since it’s such a vital part of our app. We’ll move that to a new file we’ll name logger.js, and call it from app.js. So now we have 2 files:

┬—— js/
    ├—— app.js
    └—— logger.js
/**
 * @file app.js
 */
'use strict';

import log from 'logger';
console.log(log);
/**
 * @file logger.js
 */
var log = 'Hello World';
export default log; // This is important!

Look at your browser again: it’s already refreshed, and Hello World is still appearing in the console. That means you now have access to the log variable from js/logger.js. Note that we didn’t need to specify the .js extension; Webpack just assumed.

But it’s more than simply having access to logger.js; by importing it into app.js, we’re saying that logger.js is an essential part of our application, one that should be bundled and part of our production code when we deploy it. That’s the beauty of Webpack—we can have hundreds of modules installed locally while we develop that won’t make it to production unless they are critical to the function of app.js—our entry point. importing is how we declare that.

Importing from NPM

Of course, module splitting and dependency management is far more useful with vendor libraries than merely working with code you wrote yourself.

Let’s say we need to write a calendar module that depended on moment.js. To install moment, run:

yarn add --dev moment

Now we’ll create a new file in js/ folder named cal.js. We’ll write something like:

import moment from 'moment';

var dayOfWeek = moment().format('dddd');
export default dayOfWeek;

We’ll add that to app.js:

'use strict';

import log from './logger';
console.log(log);

import dayOfWeek from './cal'; // New line
console.log(dayOfWeek);        // New line

Now go back to your browser. You’ll see 2 lines in your console now:

Hello World
Friday // or whatever day your computer thinks it is

Webpack assumed you meant /node_modules/moment, and you didn’t have to configure anything.

You can install as many libraries as you’d like locally. The only modules that will be shipped with your production code are the libraries your code explicitly depends on.

Working Directories

You might want to eventually have separate directories for your source files so that your development flow isn’t inhibited or cluttered with minified production files you will never manually edit. Let’s restructure our app into a src/ directory for our source files, and a dist/ directory for our production assets (we’ll use those names, but you name them anything you’d like).

┬—— dist/
|   └—— js/
|       └—— app.bundle.js
├—— src/
|   ├—— js/
|   |   ├—— app.js
|   |   ├—— cal.js
|   |   └—— logger.js
|   └—— index.html
├—— package.json
└—— webpack.config.js

Even though our project structure has changed, we only have to make minor edits to webpack.config.js:

'use strict';

const webpack = require('webpack');

module.export = {
  context: __dirname + '/src',       // New line
  devServer: {
    contentBase: __dirname + '/src', // New line
  },
  entry: {
    app: './js/app.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: __dirname + '/dist/js',    // Changed to dist/js/
    publicPath: 'js',
  },
};

We only had to add 2 settings:

  1. context: this sets the root directory for entry
  2. devServer.contentBase: this tells Webpack Dev Server where to start serving localhost:8080 from (saves you from having to put /src in your URLs—that shouldn’t be in your code).

Now our development project is using the new structure, but our code has remained unchanged. This will keep our root directory clean as we expand our app, or this could be useful if changes were needed based on your backend server setup.

You’ll notice that although you can run both the webpack build command and webpack-dev-server with success, the dist/ directory doesn’t have any HTML in it. And we haven’t added any CSS, either. If you’re curious about how that works, feel free to jump ahead to the chapter on CSS or the chapter on HTML.

results matching ""

    No results matching ""