webpack 的基本概念

Published on
1690 Words
Authors

webpack 是一个现代 JavaScript 应用程序的静态模块打包工具。 当 webpack 处理应用程序时,它会将一切资源都看作是模块,不管是代码资源如 JS、CSS 等,还是非代码资源如图片、字体等,这些模块之间是会存在依赖关系的。 从入口开始,它会递归地构建一个依赖关系图,其中包含应用程序所需的每个模块,然后将这些模块打包成一个或多个bundle。

webpack-modules

在 webpack 中,entry、output、loader、plugins 和 mode 等配置项决定了如何构建依赖关系图。我们首先了解一下它们的基本概念。

基本配置项

entry

webpack 是根据入口文件找到它的所有依赖,而依赖又会有新的依赖,从而不断的加入到依赖关系图中。

在我们常见的项目中,如果是单页应用,那么入口一般只有一个;如果是多个页面的项目,那么经常是一个页面会对应一个构建入口,即具有多个入口。 在 webpack 的配置文件中使用 entry 用来指定打包入口,支持两种配置方式:单入口、多入口。

单入口

只有一个入口时,entry 是一个字符串。

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

多入口

有多个入口时,entry 是一个对象。

module.exports = {
  entry: {
    app: './src/app.js',
    admin: './src/admin.js',
  },
}

output

output 用来指定将构建结果输出到具体的磁盘目录与文件名。即使可以存在多个 entry 起点,但只能指定一个 output 配置。

可以看上面给出的 webpack 官网图片右侧,构建结果包含 JS、CSS、图片等静态资源文件。

单入口

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.join(__dirname, 'dist'),
  },
}

多入口

entry 是可以有多个入口的,但 output 只会有一个,此时是通过占位符来确保文件名的唯一。

module.exports = {
  entry: {
    app: './src/app.js',
    search: './src/search.js',
  },
  output: {
    filename: '[name].js', // 通过占位符确保⽂件名称的唯⼀
    path: path.join(__dirname, 'dist'),
  },
}

loaders

其实,webpack 原生只支持 JS 和 JSON 两种文件类型,而对于其他类型的文件,诸如 jsx/tsx 等语法糖、css(包括 less, sass, stylus 等)、图片、字体等文件,webpack 并不知道它们是什么。 此时,需要通过 loaders 去支持 webpack 处理其它文件类型,把它们转换成有效的模块,webpack 在解析时才可以将它们添加到依赖关系图中。

Loader 本身是一个函数,接受源文件作为参数,返回转换的结果。

使用方式

在 webpack 配置文件中,loaders 的位置是放在 module.rules 数组中,其中 test 指定文件的匹配规则,use 指定使用的 loader 名称。

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
  },
  module: {
    rules: [{ test: /\.txt$/, use: 'raw-loader' }],
  },
}

常用的 loaders

官方推荐的常用 loader 列表见:

类型名称描述
语法转换babel-loader将 ES6、ES7 等 JS 新特性的语法转换为 ES5
ts-loader将 TS 文件转换成 JS 文件
样式css-loader支持 .css 文件的加载和解析
less-loader将 less 文件转换成 css
sass-loader将 sass/scss 文件转换成 css
style-loader将 css 添加到 DOM 的内联样式标签 style 里
stylus-loader将 stylus 文件转换成 css
postcss-loader用 postcss 来处理 CSS
其他文件file-loader解析图片、字体等
url-loader和 file-loader 类似,但是当文件小于设定的limit时可以返回一个 Data Url
raw-loader将文件以字符串形式导入
其他thread-loader多进程打包 JS 和 CSS

plugins

plugins 是用来增强 webpack 的功能,通常是⽤于 bundle ⽂件的优化、资源管理和环境变量注⼊等。它们是作⽤于整个构建过程的。

使用方式

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html’
    })
  ]
};

常见的 plugins

官方推荐的常用 loader 列表见:

名称描述
CopyWebpackPlugin将文件或文件夹拷贝到构建的输出目录
HtmlWebpackPlugin创建 html 文件去承载输出的 bundle,一个页面对应一个 HtmlWebpackPlugin,多个页面时需要在 plugins 数组中添加多个配置
TerserPluginJS 文件压缩

已废弃的著名 plugins

  1. CommonsChunkPlugin

其作用是将 chunks 相同的模块代码提取成公共的 JS,在 webpack 4 中已经删除CommosChunksPlugin,改为 optimization.splitChunks 了,见 SplitChunksPlugin

module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks: 'async',
      minSize: 20000,
      minRemainingSize: 0,
      minChunks: 1,
      maxAsyncRequests: 30,
      maxInitialRequests: 30,
      enforceSizeThreshold: 50000,
      cacheGroups: {
        defaultVendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
          reuseExistingChunk: true,
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  },
}
  1. CleanWebpackPlugin

现已改为使用 output.clean 进行配置:

module.exports = {
  output: {
    filename: '[name].bundle.js',
    path: path.join(__dirname, 'dist'),
    clean: true,
  },
}

mode

在 webpack v4 中引入了 mode 的配置,设置 mode 后可以自动开启 webpack 内置的函数,达到在相应环境下的优化,实现零配置。 Mode ⽤来指定当前的构建环境是:production、development、none,默认值为 production。

选项描述
development将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development。
开启 NamedChunksPlugin 和 NamedModulesPlugin。
production会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production。
开启 FlagDependencyUsagePlugin,FlagIncludedChunksPlugin,ModuleConcatenationPlugin,NoEmitOnErrorsPlugin 和 TerserPlugin 。
none不使用任何默认优化选项

配置示例

webpack 默认的配置文件是 webpack.config.js,且可以在命令行通过 webpack --config 指定配置文件。

从 v4.0.0 开始,由于引入了 mode 可以开启默认的配置,webpack 可以不用再引入一个配置文件来打包项目。 然而,webpack 会假定项目的入口起点为 src/index.js,然后会在 dist/main.js 输出结果,并且在生产环境开启压缩和优化,如果跟你的项目不符合,大概率还是要自定义配置的。

module.exports = {
  entry: './src/index.js',    // 1.打包的入口文件,默认入口文件为 ./src/index.js
  // output: './dist/main.js',
  output: {                   // 2.打包的输出,默认输出文件为 ./dist/main.js
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  mode: 'production',         // 3.环境模式
  module: {
    rules: [                  // 4.loaders 的配置
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  },
  plugins: [                  // 5.plugins 的配置
    new HtmlWebpackPlugin({
      template: './src/index.html’
    })
  ]
};

使用 npm script 运行 webpack 即可。

{
    "name": "app",
    "version": "1.0.0",
    "main": "index.js",
    "scripts": {
        "build": "webpack"
    }
}