Webpack入门教程(15分钟)

webpack是一款打包工具(module bundler),模块化构建工具已成为现代JavaScript应用不可或缺的一部分。

webpack是一个开源捆绑器(bundler)和预处理器,能处理各种任务。

开发人员须在webpack、Gulp、Browserify、NPM脚本、Grunt等构建工具间做出选择。

虽然有许多这方面的深入比较,但这些工具都非常相似。

优缺点

优点:

非常适合单页应用程序。

接受require()和import模块语法。 允许更高级的代码拆分。 热加载能力使ReactVue.js 应用开发更方便。

缺点:

不适合web开发初学者。

非JS资源使用者感到困惑,如:CSS文件、图片。 文档不够友好。 更新速度快变化大,教程容易过时。

相关概念

从webpack v4.0.0开始,配置文件webpack.config.js不再是必需。

想要高度的灵活性,还得通过配置文件。

webpack四个核心概念:

entry

入口起点(entry point)告诉webpack从哪个文件(模块)开始打包。

通过在webpack配置属性entry,指定一个或多个入口起点。

默认为./src目录。

entry属性值可以是string | object | array :

module.exports = {
  entry: './path/to/my/entry/file.js'
};

{
  entry: {
    app: './src/app.js',
    search: './src/search.js'
 }
}

output

output属性告诉webpack将打包后的bundles文件输出到哪,及如何命名这些文件,默认输出到./dist目录。

const path = require('path');

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  }
};

示例中,第一行导入的path模块是Node.js核心模块,用于操作文件路径。

使用output.filename、output.path属性,告诉webpack bundle的名称及输出目录。

注:只能有一个输出目录。

filename占位符

filename接受占位符,提供更多灵活性。

filename: "bundle.js"

filename: "[name].bundle.js"

说明:使用入口名称。

filename: "[id].bundle.js"

说明:使用内部 chunk id。

filename: "[name].[hash].bundle.js"

说明:使用每次构建过程中,生成的唯一hash值。

filename: "[chunkhash].bundle.js"

说明:使用基于每个chunk内容的hashs值

更多选项参见output filename

loader

处理非javascript文件时(webpack只能理解JavaScript),需要借助loader。

loader能将各类文件转换为webpack能够处理的模块,然后,使用webpack的打包能力,对文件执行处理。

两个重要属性:

test 属性,标识要求被loader转换的文件。

use 属性,表示转换时应使用哪个loader。

const path = require('path');

const config = {
  output: {
    filename: 'my-first-webpack.bundle.js'
  },
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  }
};

module.exports = config;

示例中,为module对象定义了rules属性,包含两个必要属性:test 和 use。

告诉webpack编译器,在打包中解析require()/import语句时,若遇到'.txt'路径,先使用raw-loader进行转换。

更多详情参见webpack loaders

plugins

插件所包括的范围,从打包优化、压缩,到重新定义环境变量。

接口功能很多,能处理各种各样的任务。

使用一个插件只需require()它,然后,添加到plugins数组中。

多数插件都能通过选项(option)自定义。

在一个配置文件中多次使用同一个插件,使用new操作符创建实例。

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件

const config = {
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

module.exports = config;

webpack中插件使用较为简单。

具体参考用例

webpack 提供许多开箱可用的插件!

具体参见webpack插件列表

模式

webpack内置两种模式,不同模式对应不同内置优化。

生产环境

module.exports = {
  mode: 'production'
};

开发模式

module.exports = {
 mode: 'development'
};

具体优化参见webpack 模式

watch模式

启用watch模式后,webpack将监听文件的变化。

默认关闭:

watch: false

选项:

watchOptions: {
  aggregateTimeout: 300,
  poll: 1000
}

webpack externals

很多资源会在运行时(runtime)从外部获取,如:从CDN获取jQuery。

为了防止将这些外部资源打包,需要使用externals配置项。

externals: {
  jquery: 'jQuery'
}

剥离那些没有变化的依赖模块。

下面代码是可以正常运行的:

import $ from 'jquery';

$('.my-element').animate(...);

webpack targets

webpack针对不同的运行时环境提供多种构建目标(target)。

Node.js环境:

module.exports = {
  target: 'node'
};

多个Target:

var path = require('path');
var serverConfig = {
  target: 'node',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'lib.node.js'
  }
  //…
};

var clientConfig = {
  target: 'web', // 默认是 'web',可省略
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'lib.js'
  }
  //…
};
module.exports = [ serverConfig, clientConfig ];

webpack devtool

调试代码,需要有source map,devtool选项控制是否生成,及如何生成 source map。

选择一种source map格式增强调试。

不同值会影响到构建(build)、重新构建(rebuild)速度。

清理/dist目录

代码遗留问题,导致/dist目录相当杂乱。

webpack能生成文件,但是无法追踪到哪些文件是项目实际使用。

通常,推荐的做法是在每次构建前清理/dist目录。

clean-webpack-plugin是一个常用的管理插件。

npm install clean-webpack-plugin --save-dev

配置:

const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
    plugins: [
     new CleanWebpackPlugin(['dist'])      
    ]
};

热替换(hot module replacement)

模块热替换(HMR - Hot Module Replacement)在应用运行时执行模板替换、添加、删除操作,无需重新加载整个页面。

通过以下几种方式提升开发速度:

将重新加载页面时丢失的应用程序状态保留下来。

只更新变更内容。

调整样式,几乎相当于在浏览器调试器中更改样式。

开发过程中webpack-dev-server能够帮助快速开发应用。

通过webpack-dev-server选项,能使用多种方式改变其行为。

devServer: {
  contentBase: path.join(__dirname, "dist"),
  compress: true,
  port: 9000
}

服务器启动时,解析模块列表前会有一条消息:

http://localhost:9000/
webpack output is served from /build/
Content not from webpack is served from /path/to/dist/

通过Node.js API使用 dev-server,devServer中的选项将被忽略。

可将选项作为第二个参数传入: new WebpackDevServer(compiler, {...})。

Node.js API使用webpack-dev-server示例