大家好!我是萝卜,这一章跟大家介绍 webpack 4 常见的配置。

webpack.config.js配置文件

webpack 是可配置的模块打包工具,可以通过修改 webpack.config.js 的配置文件对 webpack 进行配置,webpack 的配置文件遵循 Nodejs 的 CommonJS 模块规范,可通过 require() 语法导入其他文件或者使用 Nodejs 内置的模块,其实 webpack.config.js 是一个 Nodejs 的模块。

一个简单的 webpack.config.js 例子

const path = require('path');

module.exports = {
  mode: 'development',
  entry: './entry.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'entry.bundle.js'
  }
};

上面例子中使用CommonJS的 require 引入 Nodejs 内置的 path 模块,然后通过 module.exports 将 webpack 的配置导出。

Tips: webpack 的配置是一个 Nodejs 模块,并不是 JSON 对象。

webpack 配置支持多种语言

webpack 不仅仅支持 js 配置,还支持 TypeScript 、CoffeeScript 甚至 JSX 语法的配置,但是不论使用什么语言,核心配置项是相同的,只不过是语法不同。除了配置文件的语法多样之外,对于配置的类型也是多样的,最常见的是作为一个对象来使用,除了对象,webpack 还支持函数、Promise 和多配置数组。

如何使用 webpack.config.js 配置文件

默认情况下,webpack 会查找执行目录下的 webpack.config.js 作为配置,如果需要指定某个配置文件,可以使用命令:

npx webpack --config webpack.config.js

或者在项目目录下运行

node ./node_modules/webpack/bin/webpack --config webpack.config.js

webpack 的核心概念

虽然 webpack 的功能强大且配置项多,但是只要理解了以下的几个核心概念,就能随心应手的使用它,webpack 有以下几个核心概念:

  • entry: 项目入口,webpack 执行构建的第一步将从 entry 开始,可抽象成输入。
  • module: 模块,在 webpack中一切皆模块,一个模块对应一个文件,模块不局限于js,也可以是 css、图片等。webpack 会从配置文件的 entry开始递归找出所有依赖的模块。
  • chunk: 代码块,一个 chunk 可以由多个模块组合而成,用于代码合并与分割。
  • loader: 模块转换器,用于将模块的原内容按照需求转换成新内容。
  • plugin: 扩展插件,在 webpack 构建流程中的特定时机注入扩展逻辑,可以完成 loader 完不成的任务。
  • output: 输出结果,在 webpack 经过一系列处理并得出最终想要的代码后输出结果。

webpack 的入口(entry)和输出(output)

webpack 是一个模块打包工具,能够从一个需要处理的 javascript 文件开始,构建一个依赖关系图(dependency graph),该图映射到了项目中每个模块,然后将这个依赖关系图输出到一个或者多个 bundle 中。
webpack 是从指定的入口文件(entry)开始,经过加工处理,最终按照 output 输出固定内容的 bundle。而这个加工处理的过程,就用到了 loader 和 plugin 两个工具,loader 是源代码的处理器,plugin 解决的是 loader 处理不了的事情。

entry 入口

webpack 的 entry 支持多种类型,包括字符串、对象、数组。从作用上说,包括单文件入口和多文件入口两种方式。

单文件入口

module.exports = {
  entry: 'path/index.js'
}

// 使用对象的方式
module.exports = {
  entry: {
    main: 'path/index.js'
  }
}

单文件入口可以快速创建一个只有单一文件入口的情况,但是相对简单,在扩展配置时灵活性较低。

module.exports = {
  mode: 'development',
  entry: ['./src/index1.js', './src/index2.js']
}

无论是字符串还是字符串数组的 entry ,实际上都是只有一个入口,但是在打包产出上会有差异:
如果直接是 string 的形式,那么 webpack 就是直接把该 string 指定的模块作为入口模块。
如果是数组的形式,那么 webpack 会自动生成另一个入口模块,并将数组中的每个元素指定的模块加载进来,并将最后一个模块的 module.exports 作为入口模块的 module.exports 导出。

多文件入口

多文件入口是使用对象语法来通过支持多个 entry ,多文件入口的对象语法相对于单文件入口,具有更高的灵活性,例如多页应用、页面模块化分离优化。

module.exports = {
  entry: {
    home: 'path/home.js',
    search: 'path/search.js',
    list: 'path/list.js'
  }
}

上面的语法将 entry 分成了 3 个独立的入口文件,这样会打包出来三个对应的 bundle。

Tips: 对于一个 html 页面,我推荐只用一个 entry ,通过统一入口,解析出来的依赖关系更方便管理和维护。

output 输出

webpack 的 output 是指定了 entry 对应文件编译打包后的输出 bundle 。output 的常用属性是:

  • path: 规定了打包后输出的 bundle 的存放路径。
  • filename: 这个是 bundle 的名称。
  • publicPath: 指定了一个在浏览器中被引用的 URL 地址。
Tips: 当不指定 output 的时候,默认输出到 dist/main.js,即 output.path 是
dist,output.filename 是 main。

一个 webpack 的配置,可以包含多个 entry ,但是只能有一个 output 。对于不同的 entry 可以通过 output.filename 占位符来区分。

module.exports = {
  entry: {
    home: 'path/home.js',
    search: 'path/search.js',
    list: 'path/list.js'
  },
  output: {
    filename: '[name].js',
    path: __dirname + '/dist'
  }
}

其中 [name] 就是占位符,它对应的是 entry 的 key (home、search、list)。
目前 webpack 支持的占位符有:

  • [hash] 模块标识符的 hash
  • [chunkhash] chunk 内容的 hash
  • [name] 模块名称
  • [id] 模块标识符
  • [query] 模块的 query,例如,文件名 ? 后面的字符串
  • [function] 一个 return 出一个 string 作为 filename 的函数

[hash] 和 [chunkhash] 的长度可以使用[hash:16] (默认为 20) 来指定,或者通过指定output.hashDigestLength 在全局配置长度,那么他们之间的区别是什么?

  • [hash]:是整个项目的 hash 值,其根据每次编译内容计算得到,每次编译之后都会生成新的 hash,即修改任何文件都会导致所有文件的 hash 发生改变;在一个项目中虽然入口不同,但是 hash 是相同的;hash 无法实现前端静态资源在浏览器上长缓存,这时候应该使用 chunkhash;
  • [chunkhash] :根据不同的入口文件(entry)进行依赖文件解析,构建对应的 chunk,生成相应的 hash;只要组成
    entry 的模块文件没有变化,则对应的 hash
    也是不变的,所以一般项目优化时,会将公共库代码拆分到一起,因为公共库代码变动较少的,使用 chunkhash 可以发挥最长缓存的作用;
  • [contenthash]:使用 chunkhash 存在一个问题,当在一个 JS 文件中引入了 CSS 文件,编译后它们的 hash
    是相同的。而且,只要 JS 文件内容发生改变,与其关联的 CSS 文件 hash 也会改变,针对这种情况,可以把 CSS 从 JS 中使用
    mini-css-extract-plugin 或 extract-text-webpack-plugin 抽离出来并使用
    contenthash。

[hash]、[chunkhash] 和 [contenthash] 都支持 [xxx:length] 语法。

Tips: 占位符是可以组合使用的,例如 [name]-[hash:8]

output.publicPath

我们构建出的静态资源文件都是通过 <script> 或者 <link> 标签进行加载的,而且这些静态资源文件都是需要部署在静态资源服务器或者 CDN 上,那么如何将这些静态资源文件放在不同的域名或者 CDN 上面呢?这时就要用到 output.publicPath 来进行配置:

module.exports = {
  output: {
    filename: '[name]_[chunkhash:8].js',
    publicPath: 'https://cdn.ezample.com/assets/'
  }
}

则输出:

<script src="https://cdn.ezample.com/assets/a_456456456.js"></script>

output.library 与 output.libraryTarget

我们在实际开发中总是需要去打包一些供团队其他小伙伴使用的库,这时就需要用到 output.library 与 output.libraryTarget,output.library 用来指定库的名称,output.libraryTarget 用来指定打包出来的规范,比如:commonjs2、amd、umd2等。

小结

这一章我们从 webpack 的配置文件 webpack.config.js 基本语法入手,讲解了配置的基本用法以及 mode、context、entry、output基础概念,希望能给大家带来一些帮助,如果想了解更多,请持续关注我的文章。


萝卜
12 声望0 粉丝

没事爱折腾