webpack 配置之 输出文件 Output

6335 4 年前
output 配置如何输出最终想要的代码。即使可以存在多个入口起点,但也只需指定一个输出配置

webpack 中配置中 output 属性的最低要求是,将它的值设置为一个对象,里面包含一系列配置项,指示 webpack 如何去输出、以及在哪里输出你的的资源。

output.filename

filename属性,决定打包好的资源输出到 output.path 选项指定目录位置的文件名,如果只输出一个文件,可以把 filename 属性写成静态不变的名称。

module.exports = {
  output:"bundle.js"
}

但是,当有多个入口起点、代码拆分或插件从而创建多个输出文件时,应该使用模板变量来为每个输出赋予不同的名称。

使用入口名称:

module.exports = {
  entry:{
    index:"./src/a.js",
	main:"./src/b.js"
  },
  output:{
    filename:"[name].bundle.js"
  }
}

上面配置里,输出文件中的 [name] 指代入口起点键值对里的键,即:indexmain。从而输出的文件名分别为index.bundle.jsmain.bundle.js

使用内部 chunk id:

filename: "[id].bundle.js"

使用 hash 生成

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

使用 chunk 内容的 hash:

filename: "[chunkhash].bundle.js"

webpack输出文件名有如下内置的模板变量:

模板 描述
[hash] 模块标识符(module identifier)的 hash
[chunkhash] chunk 内容的 hash
[name] 模块名称
[id] 模块标识符(module identifier)
[query] 模块的 查询参数,例如,文件名 ? 后面的字符串

注意,这些变量虽用于文件名,但是你还是可以使用像 "js/[name]/bundle.js" 这样的文件夹结构。

[hash][chunkhash] 的长度可以使用 [hash:16]来指定(默认为20)。或者,通过指定output.hashDigestLength 在全局配置长度。

hash & chunkhash & contenthash

hashwebpack在打包时会生成一个唯一的标识符来指代本次打包过程。相同编译打包过程中的模块共有这个标识符,也就是说同一打包过程产出的产物的hash值都是一样的。

chunkhash:指的是webpack根据每个chunk生成的标识符。不同的chunkchunkhash不同,当每个chunk所依赖的模块内容改变后,打包出来的chunkhash会发生变化。没做修改的chunkchunkhash值不变。

contenthash:根据文件内容来定义的标识符,如果一个js文件里面引入了css文件,修改了js,但没修改css,想让css的打包不变能继续利用缓存。我们使用mini-css-extract-plugin插件。

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/main.[contenthash:7].css'
    })
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader"
        ]
      }
    ]
  }
}

output.chunkFilename

chunk是指webpack在進行模块的依赖分析時,代码分割出来的代码块。

output.chunkFilename 配置没有入口起点的 Chunk 输出时的文件名称(代码拆分或插件等),只用于指定在运行过程中(runtime)生成的 Chunk 在输出时的文件名称。chunkFilename 支持和 filename 一致的内置模板变量。

默认使用 [id].js 或从 output.filename 中推断出的值([name] 会被预先替换为 [id][id].

module.exprots = {
  entry: {
        main:'./src/index.js',
        a:['./src/a.js','./src/c.js'],
    },
    output: {
        filename: "js/[name].[hash].js",
        path:path.resolve(__dirname,"./dist"),
        chunkFilename:'js/[name].[id].[chunkhash].js'
    }
}

output.path

output.path 配置输出文件存放的目录,必须是表示绝对路径的字符串。

const path = require('path')
module.exports = {
    //...
    entry: {
        main:'./src/index.js',
        a:['./src/a.js','./src/c.js'],
    },
    output: {
        filename: "js/[hash]/[name].js",
        path:path.resolve(__dirname,"./dist"),
        publicPath:"/",
        chunkFilename:'js/[name]/[id].[chunkhash].js'
    }
  //...
}

上面示范中,filenamechunkFilename不光指定文件名,其实可以解析目录结构的。

output.path支持且仅支持一个模板变量:[hash]

path:path.resolve(__dirname,".//[hash]dist"),

output.publicPath

在一个项目里可能会有一些构建出的资源需要异步加载/按需加载,在项目条件允许时,我们通常把静态资源(图片、js、css、视频等)存放入CDN。这时,output.publicPath 选项就非常重要了。

output.publicPath 配置发布到线上资源的 URL 前缀,是一个字符串。 默认值是空字符串 '',即使用相对路径。选项的值都会以 / 结束。

比如设置:

filename:'[name]_[chunkhash:8].js'
publicPath: 'https://cdn.example.com/assets/'

那么发布到线上的 HTML 在引入 JavaScript 文件时就需要:

<script src='https://cdn.example.com/assets/a_12345678.js'></script>

对于如下设置:

publicPath: "/assets/",
chunkFilename: "[id].chunk.js"

那么在请求此 chunk 时,类似:/assets/4.chunk.js

对于HTML加载图片可能会像这样输出:

<link href="/assets/spinner.gif" />

或者在加载 CSS 的一个图片时:

background-image: url(/assets/spinner.gif);

webpack-dev-server 也会默认从 publicPath 为基准,使用它来决定在哪个目录下启用服务,来访问 webpack 输出的文件。

output.publicPath支持且仅支持一个模板变量:[hash]

publicPath: "https://cdn.example.com/assets/", // CDN(总是 HTTPS 协议)
publicPath: "//cdn.example.com/assets/", // CDN (协议相同)
publicPath: "/assets/", // 相对于服务(server-relative)
publicPath: "assets/", // 相对于 HTML 页面
publicPath: "../assets/", // 相对于 HTML 页面
publicPath: "", // 相对于 HTML 页面(目录相同)

在编译时无法确定输出文件的 publicPath ,可以留空,然后在入口文件处使用自由变量 __webpack_public_path__,以便在运行时进行动态设置。

__webpack_public_path__ = myRuntimePublicPath

output.crossOriginLoading

该属性只适合于配置里设置了targetweb情况,Webpack 输出的部分代码块可能需要异步加载/按需加载,而这些异步加载是通过 JSONPHTML 中插入一个 <script src="url"></script> 标签来加载异步资源。output.crossOriginLoading本质就是来设置这个script标签的crossorigin属性。

  • crossOriginLoading: false : 禁用跨域加载(默认)
  • crossOriginLoading: "anonymous" - 不会带上用户的 Cookies 启用跨域加载
  • crossOriginLoading: "use-credentials" - 带上用户的 Cookies 启用跨域加载

output.libraryTarget

当用webpack构建一个能被其他模板引入使用的库时,用这些选项来配置如何把库暴露出来。此选项与分配给 output.library 的值一同使用。下面的所有示例,都假定将 output.library 的值配置为 MyLibrary

暴露为一个变量

var

这是output.libraryTarget默认值。

libraryTarget: "var"

当设置为var时,打包好的库里将入口文件的返回值赋予给output.library配置的变量名。

var MyLibrary = _entry_return_;

当使用var选项时,将 output.library 设置为空,会因为没有变量导致无法赋值。其打包后的文件内容直接为入口文件的返回值。

当引入这个库时,直接使用库名称即可

MyLibrary.doSomething();

assign

libraryTarget: "assign" - 这将产生一个隐含的全局变量,可能会潜在地重新分配到全局中已存在的值。打包好的库文件里库名没用使用var申明

MyLibrary = _entry_return_;

如果 MyLibrary 在作用域中未在前面代码进行定义,则你的 library 将被设置在全局作用域内。

当使用此选项时,将 output.library 设置为空,将产生一个破损的输出 bundle

对象上赋值暴露

将入口起点的返回值赋值给一个特定对象的属性下。对象为output.libraryTarget值,其属性为output.library的值。

如果 output.library 赋值为空字符串,则默认行为是,将入口起点返回的所有属性都赋值给output.libraryTarget设置的对象,通过如下代码片段:

(function(e, a) { for(var i in a) e[i] = a[i]; }(${output.libraryTarget}, _entry_return_)

注意,不设置 output.library 将导致由入口起点返回的所有属性,都会被赋值给给定的对象;这里并不会检查现有的属性名是否存在。

this

libraryTarget: "this" - 入口起点的返回值将分配给 this 的一个属性(此名称由 output.library 定义)下,this 的含义取决于你:

this["MyLibrary"] = _entry_return_;

// 在一个单独的 script……
this.MyLibrary.doSomething();
MyLibrary.doSomething(); // 如果 this 是 window

window

libraryTarget: "window" - 入口起点的返回值将使用 output.library 中定义的值,分配给 window 对象的这个属性下。

window["MyLibrary"] = _entry_return_;

window.MyLibrary.doSomething();

global

libraryTarget: "global" - 入口起点的返回值将使用 output.library 中定义的值,分配给 global 对象的这个属性下。

global["MyLibrary"] = _entry_return_;

global.MyLibrary.doSomething();

commonjs

libraryTarget: "commonjs" - 入口起点的返回值将使用 output.library 中定义的值,分配给 exports 对象。这个名称也意味着,模块用于 CommonJS 环境:

exports["MyLibrary"] = _entry_return_;

require("MyLibrary").doSomething();

commonjs2

libraryTarget: "commonjs2" - 入口起点的返回值将分配给 module.exports 对象。这个名称也意味着模块用于 CommonJS 环境:

module.exports = _entry_return_;

require("MyLibrary").doSomething();

注意,output.library 会被省略,因此对于此特定的 output.libraryTarget,无需再设置 output.library

CommonJS2 和 CommonJS 规范很相似,差别在于 CommonJS 只能用 exports 导出,而 CommonJS2 在 CommonJS 的基础上增加了 module.exports 的导出方式。

output.library

output.library 的值的作用,取决于output.libraryTarget 选项的值;注意,output.libraryTarget 的默认选项是 var,所以如果使用以下配置选项:

output: {
  library: "MyLibrary"
}

如果生成的输出文件,是在 HTML 页面中作为一个 script 标签引入,则变量 MyLibrary 将与入口文件的返回值绑定。

如果将数组作为 entry,那么只会暴露数组中的最后一个模块。如果将对象作为 entry,还可以使用数组语法暴露

output.libraryExport

配置通过libraryTarget那些模块将被暴露出来,默认值是一个命名空间或者是入口文件返回的默认模块,下面的示例演示了配置为libraryTarget: "var"时的效果,其实可以配置为任何其他选项。

libraryExport: "default" - 把入口起点默认的输出分配目标库:

// if your entry has a default export of `MyDefaultModule`
var MyDefaultModule = _entry_return_.default;

libraryExport: "MyModule" - 指定的模块被分配给目标库:

var MyModule = _entry_return_.MyModule;

libraryExport: ["MyModule", "MySubModule"]- 数组作为一个模块的路径来理解,并把这个模块分配给目标库:

var MySubModule = _entry_return_.MyModule.MySubModule;

像上面那样配置libraryExport,那么可以像下面这样来使用生成的库

MyDefaultModule.doSomething();
MyModule.doSomething();
MySubModule.doSomething();
© 2018邮箱:11407215#qq.comGitHub沪ICP备12039518号-6