三石的webpack.config.js(output篇)

677 阅读5分钟

本章为 output 专栏,参考 output详细配置

这里只介绍常用的

1. filename

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

对于单个入口起点,filename 通常是一个静态名称

module.exports = {
  //...
  output: {
    filename: 'bundle.js',
  },
};

entry 设置了多入口、或代码拆分或各种插件创建多个 bundle,此时若还采用上述静态命名,结果就会产生多个 bundle.js 导致报错。

解决方式就是使用替换方式,来赋予每个 bundle 一个唯一的名称

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

不同层面,可替换的内容不一样: 替换模板

2. chunkFilename

它的取值与 filename 相同,但主要是它俩的区分

  • filename 对应于 entry 里面的输入文件,经过webpack 打包后输出文件的文件名
  • chunkFilename 指未被列在 entry 中,却又需要被打包出来的 chunk 文件的名称。一般来说,这个 chunk 文件指的就是要懒加载的代码

注意,这些文件名需要在运行时根据 chunk 发送的请求去生成。因此,需要在 webpack runtime 输出 bundle 值时,将 chunk id 的值对应映射到占位符(如 [name] 和 [chunkhash])。这会增加文件大小,并且在任何 chunk 的占位符值修改后,都会使 bundle 失效

3. path

webpack 输出文件的绝对路径

4. module

以模块类型输出 JavaScript 文件。由于此功能还处于实验阶段,默认禁用;如果需要使用,一定要开启experiments.outputModule

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

5. publicPath

官方:选项指定在浏览器中所引用的「此输出目录对应的公开 URL」,对于按需加载(on-demand-load)或加载外部资源(external resources)(如图片、文件等)来说,output.publicPath 是很重要的选项,如果指定了一个错误的值,则在加载这些资源时会收到 404 错误。

看不懂是吧?我也看不懂

通俗:主要用来转换url中的相对路径的。publicPath 并不会对生成文件的路径造成影响,主要是对你的页面里面引入的资源的路径做对应的补全,常见的就是css文件里面引入的图片。配置了此项,webpack在打包时才能根据配置动态修改uri中的相对值,相当于给你的uri加一个 publicPath 前缀!默认前缀是 /

如果在编译时,不知道最终输出文件的 publicPath 是什么地址,则可以将其留空,并且在运行时通过入口起点文件中的 __webpack_public_path__ 动态设置

publicPath举例讲解
publicPath举例讲解2

对资源使用 CDN 和 hash 的复杂示例

module.exports = {
  //...
  output: {
    path: '/home/proj/cdn/assets/[fullhash]',
    publicPath: 'https://cdn.example.com/assets/[fullhash]/',
  },
};

区分不同mode下的publicPath

publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath

6. asyncChunks

创建按需加载的异步 chunk

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

7. globalObject

默认为 window。 当输出为 library 时,尤其是当 library.type 为 'umd'时,此选项将决定使用哪个全局对象来挂载 library。为了使 UMD 构建在浏览器和 Node.js 上均可用,应将 output.globalObject 选项设置为 'this'

8. library

输出一个库,为你的入口做导出

  • library.name指定库的名称
  • library.type指定库暴露的方式
  • library.export指定哪一个导出应该被暴露为一个库
  • library.auxiliaryComment在 UMD 包装器中添加注释
  • library.umdNamedDefine

export

替代 output.libraryExport
默认为 undefined,将会导出整个(命名空间)对象。可以配置成 string 或 string[]

module.exports = {
  output: {
    library: {
      name: 'MyLibrary',
      type: 'var',
      export: 'default',
    },
  },
};

入口起点的默认导出将会被赋值为库名称:

// 如果入口有一个默认导出
var MyLibrary = _entry_return_.default;

type

替代 output.libraryTarget
这个参数是用来确定你的bundle中,模块组织是遵循的什么规范

type选项

  1. 赋值成commonjs
module.exports = {
  // …
  output: {
    library: {
      name: 'MyLibrary',
      type: 'commonjs',
    },
  },
};

入口起点的返回值 将使用 output.library.name 赋值给 exports 对象。顾名思义,这是在 CommonJS 环境中使用。

// webpack内部赋值
exports['MyLibrary'] = _entry_return_;

// 使用的js
require('MyLibrary').doSomething();

不设置 output.library.name 将导致入口起点返回的所有属性都被赋值给给定的对象;不检查现有的属性名

  1. 赋值成this
module.exports = {
  // …
  output: {
    library: {
      name: 'MyLibrary',
      type: 'this',
    },
  },
};

入口起点的返回值 将会被赋值给 this 对象下的 output.library.name 属性。this 的含义取决于你:

this['MyLibrary'] = _entry_return_;

// 在一个单独的脚本中
this.MyLibrary.doSomething();
MyLibrary.doSomething(); // 如果 `this` 为 window 对象
  1. 赋值成umd 这将在所有模块定义下暴露你的库, 允许它与 CommonJS、AMD 和作为全局变量工作
module.exports = {
  //...
  output: {
    library: {
      name: 'MyLibrary',
      type: 'umd',
    },
  },
};

最终的输出为:

(function webpackUniversalModuleDefinition(root, factory) {
  if (typeof exports === 'object' && typeof module === 'object')
    module.exports = factory();
  else if (typeof define === 'function' && define.amd) define([], factory);
  else if (typeof exports === 'object') exports['MyLibrary'] = factory();
  else root['MyLibrary'] = factory();
})(global, function () {
  return _entry_return_;
});

单entry

module.exports = {
  // …
  entry: './src/index.js',
  output: {
    library: 'MyLibrary',
  },
};

假设你在 src/index.js 的入口中导出了如下函数:

export function hello(name) {
  console.log(`hello ${name}`);
}

此时,变量 MyLibrary 将与你的入口文件所导出的文件进行绑定,下面是如何使用 webpack 构建的库的实现:

<script src="https://example.org/path/to/my-library.js"></script>
<script>
  MyLibrary.hello('webpack');
</script>

数组entry

module.exports = {
  // …
  entry: ['./src/a.js', './src/b.js'], // 只有在最后一个入口也就是 b.js 中导出的内容才会被暴露
  output: {
    library: 'MyLibrary',
  },
};

对象entry

module.exports = {
  // …
  entry: {
    a: './src/a.js',
    b: './src/b.js',
  },
  output: {
    filename: '[name].js',
    library: ['MyLibrary', '[name]'], // name is a placeholder here
  },
};

假设 a.js 与 b.js 导出名为 hello 的函数,这就是如何使用这些库的方法:

<script src="https://example.org/path/to/a.js"></script>
<script src="https://example.org/path/to/b.js"></script>
<script>
  MyLibrary.a.hello('webpack');
  MyLibrary.b.hello('webpack');
</script>

entry里配置library

  1. module.exports = {
      // …
      entry: {
        main: {
          import: './src/index.js',
          library: {
            // `output.library` 下的所有配置项可以在这里使用
            name: 'MyLibrary',
            type: 'umd',
            umdNamedDefine: true,
          },
        },
        another: {
          import: './src/another.js',
          library: {
            name: 'AnotherLibrary',
            type: 'commonjs2',
          },
        },
      },
    };
    

9. clean

对于 output 目录的清空配置,支持 boolean 或者 对象(dry/keep/function)

module.exports = {
  //...
  output: {
    clean: true, // 在生成文件之前清空 output 目录
  },
};
module.exports = {
  //...
  output: {
    clean: {
      keep: /ignored/dir//, // 保留 'ignored/dir' 下的静态资源
    },
  },
};

// 或者

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

也可以使用钩子函数

webpack.CleanPlugin.getCompilationHooks(compilation).keep.tap(
  'Test',
  (asset) => {
    if (/ignored/dir//.test(asset)) return true;
  }
);

10. Other

  1. scriptType 允许使用自定义 script 类型加载异步 chunk,例如 <script type="module" ...>

  2. sourceMapFilename 仅在 devtool 设置为 'source-map' 时有效,此选项会向硬盘写入一个输出文件

  3. sourcePrefix 修改输出 bundle 中每行的前缀。例如,可以加缩进'\t'增加美观,但这会增加代码量,我们一般还要压缩,所以一般都用不到这个

  4. chunkLoadTimeout chunk 请求到期之前的毫秒数,默认为 120000

Notice

  • 即使可以存在多个 entry 起点,但只能指定一个 output 配置