Webpack笔记

字数 1640 · 2019-08-08

#webpack

Get Start

1
2
npm init -y
npm install webpack webpack-cli --save-dev

https://webpack.js.org/

Concepts

Entry

An entry point indicates which module webpack should use to begin building out its internal dependency graph.

By default its value is ./src/index.js

Output

The output property tells webpack where to emit the bundles it creates and how to name these files.

Resolve

1
2
3
4
5
6
7
8
9
10
11
const path = require('path');
module.exports = {
  //...
  resolve: {
    // configuration options
    alias: {
      '@': path.resolve(__dirname, 'src')
    },
  },
};

Loaders

Out of the box, webpack only understands JavaScript and JSON files. Loaders allow webpack to process other types of files and convert them into valid modules that can be consumed by your application and added to the dependency graph.

1
2
3
4
5
6
7
8
module.exports = {
  // ...
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  }
};

Plugins

Perform a wider range of tasks like bundle optimization, asset management and injection of environment variables.

Mode

By setting the mode parameter to either development, production or none, you can enable webpack’s built-in optimizations that correspond to each environment. The default value is production.

Stats

1
2
3
4
5
module.exports = {
  //...
  stats: 'verbose'
};

Browser Compatibility

webpack supports all browsers that are ES5-compliant (IE8 and below are not supported). webpack needs Promise for import() and require.ensure(). If you want to support older browsers, you will need to load a polyfill before using these expressions.

webpack.config.js

1
2
3
4
5
6
7
8
9
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
};
1
npx webpack --config webpack.config.js

Debugging

1
2
3
4
5
npm install --global node-nightly
# Now, we'll need to run it once to finish the installation
node-nightly 
# break on the first statement of the script
node-nightly --inspect-brk ./node_modules/webpack/bin/webpack.js

Bootstrap

1
node_modules/webpack/bin/webpack.js

node_modules/webpack-cli/bin/cli.js:

1
2
3
const runCLI = require('../lib/bootstrap');
// ...
runCLI(rawArgs);

node_modules/webpack-cli/lib/bootstrap.js:

1
2
3
const WebpackCLI = require('./webpack-cli');
const cli = new WebpackCLI();
const result = await cli.run(parsedArgsOpts, core);

node_modules/webpack-cli/lib/webpack-cli.js

1
2
3
4
5
createCompiler(options) {
  compiler = webpack(options);
}
const compiler = this.createCompiler(this.compilerConfiguration);
compiler.run((error, stats) => {});

node_modules/webpack/lib/index.js
node_modules/webpack/lib/webpack.js
node_modules/webpack/lib/Compiler.js

1
2
3
4
5
6
run(callback) {
  const run = () => {
    this.compile(onCompiled);
  };
  run();
}

Loaders

A loader is a node module that exports a function. This function is called when a resource should be transformed by this loader. The given function will have access to the Loader API using the this context provided to it.

When a single loader is applied to the resource, the loader is called with only one parameter – a string containing the content of the resource file.

The loader is expected to give back one or two values. The first value is a resulting JavaScript code as string or buffer. The second optional value is a SourceMap as JavaScript object.

When multiple loaders are chained, it is important to remember that they are executed in reverse order – either right to left or bottom to top depending on array format.

Plugins

A webpack plugin is a JavaScript object that has an apply method.

1
2
3
4
5
6
7
8
9
10
11
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';

class ConsoleLogOnBuildWebpackPlugin {
  apply(compiler) {
    compiler.hooks.run.tap(pluginName, compilation => {
      console.log('The webpack build process is starting!!!');
    });
  }
}

module.exports = ConsoleLogOnBuildWebpackPlugin;

SplitChunksPlugin

Compiler Hooks

Watching

The Compiler supports watching which monitors the file system and recompiles as files change.

Hooks

lifecycle hooks are exposed by the compiler and can be accessed as such:

1
2
3
compiler.hooks.someHook.tap('MyPlugin', (params) => {
  /* ... */
});

Depending on the hook type, tapAsync and tapPromise may also be available.

Tapable

https://github.com/webpack/tapable

The best practice is to expose all hooks of a class in a hooks property:

1
2
3
4
5
6
7
8
9
class Car {
	constructor() {
		this.hooks = {
			accelerate: new SyncHook(["newSpeed"]),
			brake: new SyncHook(),
			calculateRoutes: new AsyncParallelHook(["source", "target", "routesList"])
		};
	}
}

Other people can now use these hooks:

1
2
3
const myCar = new Car();
// It's required to pass a name to identify the plugin/reason.
myCar.hooks.brake.tap("WarningLampPlugin", () => warningLamp.on());

The class declaring these hooks need to call them:

1
2
3
this.hooks.accelerate.call(newSpeed);
this.hooks.calculateRoutes.promise(source, target, routesList).then((res) => {});
this.hooks.calculateRoutes.callAsync(source, target, routesList, err => {});

Hook types:

Basic, Waterfall, Bail, Loop

Additionally, hooks can be synchronous or asynchronous.

Sync, AsyncSeries, AsyncParallel

Hook interface:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
interface Hook {
	tap: (name: string | Tap, fn: (context?, ...args) => Result) => void,
	tapAsync: (name: string | Tap, fn: (context?, ...args, callback: (err, result: Result) => void) => void) => void,
	tapPromise: (name: string | Tap, fn: (context?, ...args) => Promise<Result>) => void,
	intercept: (interceptor: HookInterceptor) => void
}

interface Tap {
	name: string,
	type: string
	fn: Function,
	stage: number,
	context: boolean,
	before?: string | Array
}