【webpack 从入门到使用】打包模式 & 输入输出

136 阅读3分钟

说明

  1. 这套笔记是对于 webpack 5.x 进行阐述的。(webpack <= 4 用法稍有不同)

打包模式

概述:

提供 mode 配置选项,告知 webpack 使用相应模式的内置优化。

string = 'production': 'none' | 'development' | 'production'

基本使用:

用法一:在 webpack.config.js 的文件中指定 mode

const config = {
	mode: 'production',
  // ...
};

module.exports = config;

用法二:在终端命令中指定

webpack --mode=development

配置可选项:

选项描述
development会将 DefinePluginprocess.env.NODE_ENV 的值设置为 development. 为模块和 chunk 启用有效的名。
production会将 DefinePluginprocess.env.NODE_ENV 的值设置为 production。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePluginFlagIncludedChunksPluginModuleConcatenationPluginNoEmitOnErrorsPluginTerserPlugin
none不使用任何默认优化选项

webpack 的输入输出

输入:

入口 (entry) 是 webpack 打包前必须要知道的入口文件信息, webpack 会通过entry知道项目需要打包的文件入口以及对应的 JS 模块(chunk)

通常情况下,一个页面对应一个 entry 入口。在 SPA 中我们使用 单文件入口打包,在 MPA 中我们使用 多文件入口打包

单文件入口打包:

通常情况下,单文件入口打包, 配置方式如下:

  1. 使用简写:
const config = {
  mode: 'production',
  entry: './src/index.js',
  // ...
};

module.exports = config;
  1. 使用完整写法:
const config = {
  mode: 'production',
  entry: {
    main: './src/index.js'
  },
  // ...
};

module.exports = config;

多文件入口打包:

多文件入口,我们可以使用以下的方式:

  1. 使用数组导入入口,模块会按照数组的顺序依次打包
const config = {
  mode: 'production',
  entry: ['./src/index.js', './src/detail.js'],
  // ...
};

module.exports = config;
  1. 使用对象导入多入口(用法:entry: { <entryChunkName> string | [string] } | {}
const config = {
  mode: 'production',
  entry: ['./src/index.js', './src/detail.js'],
  // ...
};

module.exports = config;

注意

  • 使用对象语法打包多入口时,配置出口也需要配置对应的出口 [name].js (此时不能为 bundle.js)
  • 对象语法会比较繁琐。然而,这是应用程序中定义入口的最可扩展的方式。

配置补充

image.png

注意:

  • runtimedependOn 不应在同一个入口上同时使用
  • dependOn不能是循环引用的,下面的例子也会出现错误

输出:

outputwebpack.config.js 配置的必填项,它包括了一组选项,指示 webpack 如何去输出、以及在哪里输出你的 bundleasset 和其他你所打包或使用 webpack 载入的任何内容。

output 的配置非常多,这里列举一些常用的配置,完整配置请参考:webpack 中文文档-output配置

本文挑一些最常用的配置来讲一下,如下图表格所示:

image.png

output.filename

output.filename 决定了每个输出 bundle 的名称。这些 bundle 将写入到 output.path 选项指定的目录下。

  • 在单文件入口的打包情况下,output.filename使用静态名称进行配置:
const config = {
  // ...
  output: {
    filename: 'bundle.js',
    // ...
  },
  // ...
};

module.exports = config;
  • 在多文件入口的打包情况下,output.filename使用动态名称进行配置:
const config = {
  // ...
  output: {
    filename: '[name].bundle.js',
    // ...
  },
  // ...
};

module.exports = config;
const config = {
  // ...
  output: {
    filename: '[id].bundle.js',
    // ...
  },
  // ...
};

module.exports = config;
const config = {
  // ...
  output: {
    filename: '[contenthash].bundle.js',
    // ...
  },
  // ...
};

module.exports = config;
const config = {
  // ...
  output: {
    filename: '[id]-[name]-[contenthash].bundle.js',
    // ...
  },
  // ...
};

module.exports = config;

output.path

output.path用于配置 output 目录对应一个 绝对路径(建议使用 path.resolve 或者 path.join 方法连接的路径了,直接传入相对路径会报错)。

const path = require('path');

module.exports = {
  // ...
  output: {
    path: path.resolve(__dirname, 'dist'),
    // ...
  },
  // ...
};

output.chunkFilename

output.chunkFilename 决定了非初始(non-initial)chunk 文件的名称。

注意:

  1. output.filename 不同, output.chunkFilname 是可变的 (基于 HTTP 请求)。因此,需要在 webpack 构建时,将 chunk id 的值对应映射到占位符(如 [name] [chunkhash])。
  2. output.chunkFilname做完映射之后会增加文件大小,并且在任何 chunk 的占位符值修改后,都会使 bundle 失效。
  3. 默认使用 [id].js 或从 output.filename 中推断出的值([name] 会被预先替换为 [id] 或 [id].)。
module.exports = {
  //...
  output: {
    //...
    chunkFilename: '[id].js',
  },
};
module.exports = {
  //...
  output: {
    chunkFilename: (pathData) => {
      return pathData.chunk.name === 'main' ? '[name].js' : '[name]/[name].js';
    },
  },
};

output.asyncChunks

output.asyncChunks用于创建按需加载的异步 chunk。

module.exports = {
  //...
  output: {
    //...
    asyncChunks: true,
  },
};

output.clean

output.clean用于清除之前输出在 output 下的内容。(webpack5 新增)

module.exports = {
  //...
  output: {
    clean: true, // 在生成文件之前清空 output 目录
  },
};
module.exports = {
  //...
  output: {
    clean: {
      dry: true, // 打印而不是删除应该移除的静态资源
    },
  },
};
// 配置方式一
module.exports = {
  //...
  output: {
    clean: {
      keep: /ignored/dir//,
    },
  },
};
// ------------------------------------------------------------------------------- //

// 配置方式二
module.exports = {
  //...
  output: {
    clean: {
      keep(asset) {
        return asset.includes('ignored/dir');
      },
    },
  },
};