webpack3学习笔记

柔情只为你懂 2022-06-02 09:19 292阅读 0赞

webpack 是前端开发者一个跨不过去的编译工具。不过由于他的快速迭代,让很多同学在学一个版本的时候,下一个新版本就发布了,让人感觉非常蛋疼和无奈:

“我是谁,我在干嘛,我要做什么?”

不过,如果你已经掌握 webpack 比较老的版本,对于新版本的学习而言,应该只需要 0.5 天的工作量就可以完成。因为,其基本理念都是以 JS 为中心,增加的只是其辅助特性。

webpack 到目前为止已经走过了三个大版本,每个版本之间都,增加了非常多可用的特性,但是每个版本的具体配置项都有些差异,很容易让老版本用户形成依赖。现在 webpack 3 已经走到了 3.8 版本。现版本对于 webpack 2.x 的配置项来说,最突出的就是 loader 的写法的改变和内置了 webpack-dev-server 的特性。

所以,本文将带你全面了解一下 webpack 3.x 版本的新特性和一些常用的 webpack 3.x 的配置。

entry-入口 JS 配置

entry 选项主要用来定制 webpack 引用 JS 文件的主入口,它可以配置多个值来定义多个 JS 主文件入口。具体配置项为:

entry可以是三种值[string | object | array]

  • 字符串:如 entry:’./src/index.js’,字符串也可以是函数的返回值,如entry: () => ‘./demo’。
  • 数组形式,如[react,react-dom],可以把数组中的多个文件打包转换为一个chunk;

    entry: [“./app/entry1”, “./app/entry2”],

  • 对象形式,如果我们需要配置的是多页应用,或者我们要抽离出指定的模块做为公共代码,就需要采用这种形式了,属性名是占位符name的值,属性值可以是上面的字符串和数组,如下:

    // 值得注意的是入口文件有几个就会生成几个独立的依赖图谱。
    entry:{

    1. main:'./src/index.js',
    2. second:'./src/index2.js',
    3. vendor: ['react','react-dom'] // 将 react,react-dom 一起打包

    }

有时候,开发者还会利用 require.resolve(route) 来在 entry 中引入具体路径的文件。该方法只是用来作为路径模块的搜索,其返回的是指定文件的绝对路径名。解析机制有点类似,require(route)

  1. entry: [
  2. require.resolve('react-dev-utils/webpackHotDevClient'),
  3. require.resolve('./polyfills'), //返回 /Users/villainHR/Desktop/file/polyfills/index.js
  4. require.resolve('react-error-overlay'),
  5. 'src/index.js'
  6. ],

entry 还可以接受 function 返回的 string,array,object 值:

  1. entry: () => './demo'

context 上下文基础目录

context 用来设置 entry 和 loaders 的上下文索引依赖。默认情况下,entry 等参考的是当前目录(CWD)

  1. // 手动设置
  2. context: path.resolve(__dirname, "app")

通过,entry 设置的相对路径,会优先寻找 ./app 路径下的文件。

output-输出 JS 配置

基础配置项

output 里面又很多基本的配置项,基础配置项有:

  1. output:{
  2. path: path.join(__dirname,'./dist'),
  3. filename:'js/bundle-[name]-[hash].js',
  4. chunkFilename:'js/[name].chunk.js',
  5. chunkLoadTimeout: 12000,
  6. publicPath:'/dist/'
  7. }
  • path: 用来决定输出目录。通常结合 path.join/resolve() 设置绝对路径。
  • filename[alias: name]: 决定具体输出的文件名,上面 output 选项中,可以用到很多全局的占位符,比如:name、[hash] 等。
  • chunkFilename: 主要是用来对没在 entry 中定义的文件来设定具体的输出目录和文字的。常常用来按需的异步加载当中,例如:

    require.ensure([“modules/tips.jsx”], function(require) {

    1. var a = require("modules/tips.jsx");
    2. // ...

    }, ‘tips’);

这里,chunkFilename 就可以将 tips.jsx 具体输出为 js/tips.chunk.js。

  • publicPath:并不是用来输出打包路径,而是在 runtime 的时候,手动修改 src 引用路径的。常常配合 css/style/html-loader 来修改。例如,会将: src="picture.jpg" Re-writes ➡ src="/assets/picture.jpg" 。相当于,手动修改请求 url 的地址。
  • chunkLoadTimeout[Number]: 设置 webpack chunk 的请求超时时间。// TODO

上面也提到了,在 output 中会存在一起全局占位符,比如::name、[hash] 等。代表的含义为:

  • [id]:webpack给块分配的内部chunk id,如果你没有隐藏,你能在打包后的命令行中看到;
  • [hash]:每次构建过程中,生成的唯一 hash 值;(每次都变)
  • [chunkhash]: 依据于打包生成文件内容的 hash 值,内容不变,值不变;

hash 控制

在全局占位符中,有一个特殊的值 [hash]。我们可以在 webpack 中,针对 hash 输出做相关的控制。(这里会一并影响到 [chunkhash])

  • output.hashDigest: 具体输出 hash 的 encoding,有 ‘hex’, ‘latin1’ or ‘base64’。默认为 hex
  • output.hashDigestLength: 输出 hash 具体长度。默认为 20。
  • output.hashFunction: 引入文件的具体算法,默认为 md5。
  • output.hashSalt: 给 hash 加盐,很少用。

如果,有使用 ExtractTextWebpackPlugin 的话,它会通过 contenthash 选项,直接覆盖上面 4 个的 hash 选项。

自定义库的打包

在 webpack 中,如果想要自己写一个包并发布的话,就需要独立打包成为一个 library。这里,在 webpack 中有指定的配置项,和我们平常写的 webpack 打包项目不同。

独立打包一个库,常常会遇到应用外部库的事情,你可以选择大伯啊,也可以选择不打包。这里,除了 output 选项之外,还需要 externals 选项。下面内容主要对 output 里面内容做详解解释,而 externals 会放到后面进行讲解。

externals 主要是用来解决外部库打包问题,基本设置为:

  1. externals: {
  2. key: "value"
  3. },
  • value: 用来指明 外部库 通过全局(window,global)的方式暴露的模块名。例如:

    window.jQuery = {
    //xxx
    }

webapck 会直接处理 window 或者 global 对象进行模块化包裹。否则,则不会对指定模块进行 externals 处理。这点非常关键。

  • key: 具体指代,在经过 value 处理过后的外部库,能够在 webpack 通过 require 或者 import 的包名,例如:

    externals: {

    1. $: "jQuery"

    }

    // index.js

    var $ = require(“$”);

在 output 中主要有 4 个关键选项设置值:

  • output.library[String]: 用来设置通过,CDN 引入时的全局 Name。对于,require/import 引入的没影响(模块引入具体是根据具体代码中的 exports 来决定)
  • output.libraryExport: 限定通过模块具体暴露的接口。例如:

    libraryExport: [“MyModule”, “MySubModule”]; // 只能到处前面两个模块

最重要的模块输出选项应该是 libraryTarget ,它是用来决定模块以何种规范输出,在全局变量的 Name 是啥。其基本格式为:

  1. output.libraryTarget[String]: var | assign | this | window | global | commonjs | commonjs2 | amd | umd

上面那些全部是都是可选项值。这里先告诉大家,在现代 JS 的写法中,最后一个 umd 的选项是最常用的。如果你还是想通过 script 标签引入的话,则前面 5 个比较适合给你灵活自定义。当然, umd 选项也是适合的,不过灵活性差了点。

上面选项可以分为三种类型:

  • 全局变量型[var,assign]:用来表示模块导出,是直接在全局中定义变量。比如,jQuery 的 $</code>,不需要额外引入处理。</li><li style="line-height:1.7em; list-style-type:disc">对象绑定型[this,window,global,commonjs]:用来将导出的模块,绑定到具体的对象中。比如,jQuery 的 window[’$’],this[’$’] 这样的引入绑定。
  • 模块绑定型[commonjs2,amd,umd]: 需要通过,全局 require() 方法引入的模块。

libraryTarget 常常和 library 选项一起结合使用。下面内容,统一 library 设置为 Villainhr

  1. output.library: 'Villainhr'

接下来,我们具体一个一个来细分讲解一下:

全局变量型

var

  1. output.libraryTarget: 'var' // 默认值

在 js 脚本实际编译结果为:

  1. var Villainhr = _entry_return_;
  2. // In a separate script...
  3. Villainhr.doSomething();

通过 var 变量定义关键字来申明一个变量,将导出的模块直接复制过去。

assign

  1. output.libraryTarget: assign

编译结果为:

  1. Villainhr = _entry_return_;
  2. // In a separate script...
  3. Villainhr.doSomething();

这里,就直接全局绑定,如果前面已经定义过 Villainhr 则会默认覆盖。其实和 var 定义没啥区别。

对象绑定型

对象绑定则是直接通过 Object 的方法,将导出的模块直接绑定到具体对象:

this

  1. output.libraryTarget: "this"

编译结果为:

  1. this["Villainhr"] = _entry_return_;
  2. // In a separate script...
  3. this.Villainhr.doSomething();
  4. Villainhr.doSomething(); // if this is window

导出的模块,直接绑定在 this 上,在全局中直接使用 this.xxx 来进行模块调用。

window

  1. output.libraryTarget: "window"

编译结果为:

  1. window["Villainhr"] = _entry_return_;
  2. window.Villainhr.doSomething();
  3. // or
  4. Villainhr.doSomething();

这里就是通常的导出方案,直接将输出模块绑定到 window 对象上。其实也相当于 var 绑定,直接通过模块名使用。

global

  1. output.libraryTarget: "global"

编译结果为:

  1. global["Villainhr"] = _entry_return_;

直接通过 global 对象调用,这个通常用在 NodeJS 的环境。

commonjs

  1. output.libraryTarget: "commonjs"

编译结果为:

  1. exports["Villainhr"] = _entry_return_;
  2. require("Villainhr").doSomething();

在引用调用时,直接通过 require() 方法引入。

模块绑定型

模块绑定型有 commonjs2,amd,umd 这三个选项。他们具体的规范就是根据选项值对应的规范来的—— CommonJSAMD

commonjs2

编译结果为:

  1. module.exports = _entry_return_;

这和 commonjs 类似,不过遵循的是 commonjs2 的规范,是直接将其赋值到 module.exports 上的。具体使用还是需要 require() 引用:

  1. require("Villainhr").doSomething();

amd

编译结果为:

  1. define("Villainhr", [], function() {
  2. // main body
  3. });

这里通过 amd 异步加载的规范,来导出具体的文件模块。具体使用是通过 require 方法直接引入使用:

  1. require(['Villainhr'], function(Villainhr) {
  2. // xxx
  3. });

umd

这个模块标准应该属于最方便的一种,它实际上集合了 commonjs1/2,amd,this 的绑定方式。具体编译结果为:

  1. (function webpackUniversalModuleDefinition(root, factory) {
  2. if(typeof exports === 'object' && typeof module === 'object')
  3. module.exports = factory();
  4. else if(typeof define === 'function' && define.amd)
  5. define([], factory);
  6. else if(typeof exports === 'object')
  7. exports["Villainhr"] = factory();
  8. else
  9. root["Villainhr"] = factory();
  10. })(this, function() {
  11. //what this module returns is what your entry chunk returns
  12. });

这里其实一共有 4 个绑定,不过它会优先进行绑定选择,具体顺序是:

commonjs2 > AMD > commonjs > this

也就是 4 选一,如果已经通过 commonjs2 引入的话,则不能在通过其它方式使用。比如,this.Villainhr 这样是访问不到的。

module 编译设置

在 module 选项主要就是用设置 webpack 中常用的 loaders。通过 rules 规则来匹配具体应用的文件和 loaders。

noParse 防止预编译

noParse 主要用来设置相关的匹配规则,来防止 webpack loaders 对某些文件进行预编译。

基本设置为:

  1. noParse: RegExp | [RegExp] | function

通常,设置的值可以直接为:

  1. noParse: /jquery|lodash/
  2. // or
  3. noParse: function(content) {
  4. return /jquery|lodash/.test(content);
  5. }

这样,jquery 和 loadsh 就不会被 webpack 中的 loaders 捕获并编译了。

rules 设置匹配规则

module.rules 的选项具体是用来设置 loaders 匹配文件的规则。其基本接受类型为 [Array]。

  1. module: {
  2. rules: [{
  3. test: /\.js$/,
  4. exclude: /node_modules\/dist/,
  5. loader: 'babel-loader'
  6. }]
  7. },

rules 里面的每个对象都决定了 loaders 的具体类型以及 loaders 作用的具体文件。在 webpack3 中,继承了 webpack2 的基本限定功能,比如 excludeinclude 等,还额外加入了通过 query 匹配,以及多个 query 的 loader 匹配规则。

文件匹配

在每一条具体的 rule 里面,用来进行匹配文件的选项有:Rule.test, Rule.exclude, Rule.include, Rule.and, Rule.or, Rule.not。

上面三个对象其实挂载到的是 Rule.resource 对象上的,你可以直接写到 Rule 上,也可以写到 Rule.resource 上。这里简单起见,以 rule 为基准。他们的值统一都为 condition 。这个概念,是 webpack 匹配文件提出的。

condition

主要用来设置匹配文件的条件规则。可接受的值有:

  1. condition: [string | RegExp | function | array | object]
  • string: 匹配文件的绝对路径
  • RegExp: 匹配文件的正则
  • function: 参数为 input 的路径,根据返回的 boolean 来决定是否匹配。
  • array: 里面可以传入多个 condition 匹配规则。
  • object: 不常用,用来匹配 key。

接下来,我们来看一下 condition 在各个选项值中的具体实践。

test

test 用来匹配符合条件的 input。设置的值为:

  1. test: [condition]

最常用的还是直接写入正则:

  1. test: /\.jsx$/

include

和 test 一样,也是用来匹配符合条件的 input,主要用途是用来设置 依赖文件索引目录。在 include 中,通常设置 string 或者 array of strings。

  1. // 在 entry css 文件中,只能在 app/styles 以及 vendor/styles 中索引依赖文件
  2. {
  3. test: /\.css$/,
  4. include: [
  5. path.resolve(__dirname, "app/styles"),
  6. path.resolve(__dirname, "vendor/styles")
  7. ]
  8. }

exclude

设置依赖文件不会存在的目录。

实际上,上面三个命令是一起配合来提高编译速度的。因为默认情况下,webpack loaders 会对所有引入的文件进行 loader 编译,当然,对于 node_modules 里面成熟的库,我们没比较在进行额外的 loader 编译,直接将其 bundle 即可。

常用设置可以为:

  1. test: /\.js$/,
  2. loader: 'babel-loader',
  3. include: [
  4. path.resolve(__dirname, "app/src"),
  5. path.resolve(__dirname, "app/test")
  6. ],
  7. exclude: /node_modules/ // 排除编译 node_modules 中的文件

剩下的 ornot 也是用来设置规则,根据名字大家也可以猜出这两者的含义:

  • or[condition]:满足其中一种条件即可。例如: or: [/.*src\/index.*/,/.*abc.*/]
  • not[condition]:都不满足所有的条件。设置方法同上

query 匹配

query 匹配具体指的是匹配 url 中的 ? 后的字符串。当然,我们也可以在 test 中通过正则来写,不过,webpack3 既然已经提供了 query 的选项,我们也可以直接使用它的配置– resourceQuery

resourceQuery 用来设置匹配 query 的规则,接受的内容是 condition 。不过,一般直接设置 正则 或者 string 就行:

  1. // 匹配 query 含有 inline 的路径,例如:./villainhr.css?inline
  2. {
  3. test: /.css$/,
  4. resourceQuery: /inline/,
  5. use: 'url-loader'
  6. }

另外,如果你想对不同的 query 使用不同的 loader 话,可以直接使用 oneOf 配置。文件资源会默认找到 oneOf 中第一个匹配规则,来调用对应的 loader 处理。

  1. {
  2. test: /.css$/,
  3. oneOf: [
  4. {
  5. resourceQuery: /inline/, // villainHR.css?inline
  6. use: 'url-loader'
  7. },
  8. {
  9. resourceQuery: /external/, // villainHR.css?external
  10. use: 'file-loader'
  11. }
  12. ]
  13. }

loader 编译设置

在 webpack2 的时候,主要写法是根据 loadersloader 来进行设定的。不过,在 webpack3 该为根据文件来决定 loader 的加载。这其中,最大的特点就是,将 loaders 替换为了 rules。例如:

  1. module: {
  2. loaders: [
  3. {test: /\.css$/, loader: 'style-loader!css-loader'}
  4. ]
  5. }
  6. // 替换为:
  7. module: {
  8. rules: [
  9. {
  10. test: /\.css$/, use:[
  11. 'style-loader','css-loader'
  12. ]}
  13. ]
  14. }

按照规范, use 是用来实际引入 loader 的标签。在 webpack3 时代,还保留了 loader 字段,废除了 query 字段,其实可以在 use 中找到替代。

loader

用来定义具体使用的 loader,这里等同于: use:[loader]。

query

用来限定具体的 loader 使用的配置参数,例如 babel 的配置:

  1. test: /\.js$/,
  2. loader: 'babel-loader',
  3. query: {
  4. presets: ['es2015']
  5. }

不过,在 webpack3 中已经废弃了 query,使用 useoptions 选项:

  1. test: /\.js$/,
  2. use:[
  3. {
  4. loader: 'babel-loader',
  5. options:{
  6. presets: ['es2015']
  7. }
  8. }
  9. ]

resolve 模块解析路径

resolve 主要是用来解析具体入口文件中,引入依赖文件解析。例如,通过 import / require引入的文件:

  1. import foo from 'demo/test/villainhr.js')
  2. // or
  3. require('demo/test/villainhr.js')

在 webpack 中,提供了 3 种路径解析方式:

  • 相对路径:直接根据入口文件的路径,来对路径进行解析。相当于 path.resolve() 这个方法。

    import “../src/villainhr.js”; // 等同于 path.resolve(__dirname,’../src/villainhr.js’)

  • 绝对路径:根据 resolve.modules 设置的参考目录来进行解析。默认是根据 webpack 所在的目录。设置了之后,绝对路径的解析,只会在设置的参考目录中查找。

    modules: [path.resolve(__dirname, “src”), “node_modules”] // 设置绝对路径搜索目录

    import “/villainhr.js”; // 只会搜索 src/villainhr.js 以及 node_modules/villain.js 。

  • 模块路径:直接引入模块,路径前面不加任何修饰符号。例如: import "es5"; 。webpack 的模块解析规则比上面两个规则要复杂一点。因为还牵扯到 modulesaliasextensions 等。主要规则为:

    • 搜索 resolve.modules 定义的目录,如果有 alias 标签,则还会参考 alias 定义的模块路径
    • 检查引用的路径是文件

      • 检查文件是否存在,如果没有尾缀,则根据 resolve.extensions 定义的尾缀来索引。
    • 检查引用的路径是目录

      • 检查含有 package.json,根据 resolve.mainFields 定义的字段来索引文件。
      • 如果不含有 package.json,直接根据 resolve.mainFiles 来索引文件。
      • 具体文件解析,根据 resolve.extensions 来解决。

具体模块路径解析,可以参考如下:

  1. # /src/villain.js 存在
  2. import VR from 'villain';
  3. /** 搜索 /src、node_modules 目录,
  4. 找到 villain 文件,如果没有,
  5. 根据 extensions 添加尾缀查询。
  6. 找到 villain.js
  7. */
  8. # node_modules/es6 模块存在
  9. import VR from 'es6';
  10. /** 搜索 /src、node_modules 目录,
  11. 找到 es6 文件夹
  12. 查看 package.json 文件,
  13. 根据 mainFields 定义的字段索引 packjson,找到 main 字段定义的文件。
  14. */
  15. # src/demo/dev/index.js 存在
  16. import VR from 'ABC/dev';
  17. /** 根据 alias 定义的 ABC 查找,src/demo/ 目录下的文件
  18. 找到 dev 目录,里面没有 package.json 文件
  19. 根据 mainFiles 定义的文件名和 extensions 定义的尾缀找到 index.js 文件
  20. // webpack.config.js
  21. resolve:{
  22. alias: {
  23. ABC: path.resolve(__dirname, 'src/demo/')
  24. },
  25. modules: [path.resolve(__dirname, "src"), "node_modules"],
  26. mainFields: ["main"],
  27. mainFiles: ["index"],
  28. extensions: [".js", ".json"]
  29. }

设置模块索引目录

在 webpack 中,主要提供 aliasmodules 来进行索引目录的设置。

  • alias:设置导入路径的简便写法。如果你有大量的文件依赖路径非常长的话,除了使用 modules 设置参考路径之外,还可以根据 alias 来设置路径映射的 key。另外,它还提供了 $ 来进行文件的精确匹配,这个看看 文档 就行,感觉不常用。例如:

    alias: {
    Villainhr: path.resolve(__dirname, ‘src/Villainhr/’)
    }

# 如果要获取 src /Villainhr/index.js 的话,可以直接在 import 写入: import test from ‘Villainhr/index’;

  • modules: 用来设置模块解析的目录。这样,在进行模块查找的时候,webpack 会优先遍历你定义的目录。如果,你还有自定义模块在 src 目录下,通过普通模块解析是找不到的,这时候可以直接在 modules 中添加 src。

    modules: [path.resolve(__dirname, “src”), “node_modules”]

package.json 索引解析

和模块搜索最关键的文件是 package.json 、在 node 环境下,如果模块文件中存在 package.json,会根据其 main 字段定义的文件来进行索引。通过 webpack 设定的模块索引,可以更灵活的设置查找规则。其中,主要依赖的是 mainFieldsmainFilesextensions 这三个字段。

  • mainFields[Array]: 接受的是数组,用来设置在 package.json 文件中,用来定义具体查找文件的字段。例如: mainFields: ["browser", "module", "main"] ,则会按顺序搜索: browsermodulemain 这三个字段。
  • mainFiles[Array]:如果文件不含有 package.json,则直接根据 mainFiles 定义的文件来索引。
  • extensions[Array]:设置默认文件后缀名。当索引文件时,如果具体路径没带文件名的话,会根据 exntensions 定义的内容来获取。

loader 简便书写

modules 指令下,添加具体调用的 loader 一定需要带上后面的 -loader 尾缀。如果你不想带,则会默认报错。不想报错的话,可以使用 moduleExtensions 指令来说明:

  1. moduleExtensions: ['-loader']

这样,就可以直接在 module 中直接不带 -loader 引用:

  1. loader: 'eslint'

externals 定义外部依赖

externals 是用来排除某些你并不想打包的库,并且可以通过 import / require 在全局环境中调用。这个选项一般是提供给一些开源库或者组件作者使用的。

相当于,你调用了一个库,而最终实际打包的文件里面剔除该库的存在,只是留下了一个引用接口。

  1. // 剔除 sw-router 库
  2. externals: {
  3. Router: 'sw-router'
  4. }
  5. // 在代码中使用
  6. import Router from 'Router';

它可以接收如下类型:(array object function regex)

  • array:用来过滤打包文件中的子模块。

    // 将 ./math 文件中的 subtract 过滤不打包。
    externals: {
    subtract: [‘./math’, ‘subtract’]
    }

    // 忽略如下文件打包:
    import {subtract} from ‘./math’;

  • object:通过 key 值,来决定在不同模块规范下,文件暴露的接口名。其中,commonjs 代表 require 模块规则,amd 则代表 define 模块规则,root 则是代表该模块在全局环境,例如 window 访问的对象名。

    externals : {
    ex_loadsh : {

    1. commonjs: "lodash", // require('loadsh')
    2. amd: "lodash", // define(['loadsh'])
    3. root: "_" // window._

    }
    }

通过 externals 定义之后,我们在不同环境访问 loadsh 的方式就变为:

  1. // 全局环境
  2. window.ex_loadsh;
  3. // 模块包中
  4. require('ex_loadsh');
  • function: 前面几个写法都是将需要提出的文件写死,而 function 提供了可以灵活配置的 external list。比如,你想剔除所有 node_modules 包中的库,而里面又有几个包需要引用的话,可以写为:

    externals: [
    function(context, request, callback) {

    1. if (/^yourregex$/.test(request)){ // 剔除具体的包
    2. return callback(null, 'amd ' + request); // 通过 amd 定义剔除文件的引用方式
    3. }
    4. callback();

    }
    ]

不过,更方便的直接使用 webpack-node-externals 来完成。如果项目不是特别复杂,这个配置选项一般用不上。

  • regexp: 使用正则选项,相当于就是通过正则的 test 方法,通过路径名的检查,来决定是否剔除。

    externals: /^(jquery|\$)$/i; //剔除 jquery 和 $ 文件导入

    剔除如下文件

    import $ from ‘jquery’;
    // or
    import $ from ‘$’;

target 设定打包环境

这里,如果项目并不复杂的话,可以直接忽略该属性设置

因为 webpack 本身都是多环境应用,你可以在 node、web、webworker 甚至其他跨平台环境中:node-webkit、electron-main。其常用选项有三个:

  • node:在后台环境中使用
  • web:在浏览器主线程环境中使用
  • webworker:在 web-worker 环境中使用

具体设置方式为:

  1. {
  2. target: 'node'
  3. }

不过,该选项常常用于复杂的打包项目中。比如,一个项目你需要同时输出在 web 环境中和在 webworker 环境中运行的打包脚本文件。这时候,就涉及到多入口文件的 webpack.config.js 设置。这里,可以利用 webpack-merge 来帮助我们完成多入口的合并设置。

  1. var baseConfig = {
  2. target: 'async-node',
  3. entry: {
  4. entry: './entry.js'
  5. },
  6. output: {
  7. filename: '[name].js',
  8. path: path.resolve(__dirname, './dist')
  9. }
  10. };
  11. let targets = ['web', 'webworker', 'node', 'async-node', 'node-webkit', 'electron-main'].map((target) => {
  12. let base = webpackMerge(baseConfig, {
  13. target: target,
  14. output: {
  15. path: path.resolve(__dirname, './dist/' + target),
  16. filename: '[name].' + target + '.js'
  17. }
  18. });
  19. return base;
  20. });
  21. module.exports = targets;

在导出的就会同时编译出 web、webworker、node 等目录,里面的文件就是对应环境中使用的包。如果想用原生的可以直接导出,数组形式的配置项:

  1. var path = require('path');
  2. var serverConfig = {
  3. target: 'node',
  4. output: {
  5. path: path.resolve(__dirname, 'dist'),
  6. filename: 'lib.node.js'
  7. }
  8. };
  9. var clientConfig = {
  10. target: 'web', // <=== can be omitted as default is 'web'
  11. output: {
  12. path: path.resolve(__dirname, 'dist'),
  13. filename: 'lib.js'
  14. }
  15. };
  16. module.exports = [ serverConfig, clientConfig ];

通过,在 webpack 主文件中,具体设置需要使用的配置,即可完成指定环境的编译操作。

node 提供模拟包

node 指令主要是让 webpack 将在 node 环境运行的包,提供相关的设置,能够直接在打包文件中访问。其策略可以是提供一个桩(空对象),或者直接将现成的包直接打进去。

其基本可选择的值主要是直接参考 node 的模块包名:

  1. console
  2. global
  3. process
  4. __filename
  5. __dirname
  6. Buffer
  7. setImmediate

不过,主要用到的还是 Buffer 和 global 两个配置项。其打包策略选项有 4 个值:

  • true: 直接将该包的 polyfill 直接打进去
  • “mock”: 提供空接口。可以访问对应的接口名,但是没有任何作用。
  • “empty”: 提供一个空对象。这个连接口名都不能访问
  • false: 啥都没有。

上述默认配置值为:

  1. node: {
  2. console: false,
  3. global: true,
  4. process: true,
  5. __filename: "mock",
  6. __dirname: "mock",
  7. Buffer: true,
  8. setImmediate: true
  9. }

这样设置了之后,我们可以直接在主文件入口中访问:

  1. const Buffer = require('Buffer');
  2. // doSth()

如果你想啥都不提供,最好直接将 node 设置为 false

  1. node:false

devtool 开启 sourceMap 选项

devtool 主要是给 JS 文件添加对一个的 sourceMap 文件。不过,webpack 可以生成多种 sourceMap 文件,具体的区别是,映射还原度的区别。这里直接参考 webpack 官方文档即可。

2EvAny7.png_web

其中,最常用的选项就是 source-mapcheap-eval-source-map 。(这里实在太多了,各位看着选个合适的就行)如果你想关闭,sourceMap 的话,可以直接使用 hidden-source-map,或者不传。比如,下面的配置:

  1. if (COMPILE) {
  2. config.devtool = 'hidden-source-map';
  3. config.output.path = path.join(__dirname,'public');
  4. }

devServer 本地 localhost 调试

devServer 是 webpack 提供一个简便的调试服务。它可以根据字段配置,自动起一个 server 来进行调试。如果用过 webpack-dev-server 的同学,应该就很熟悉了。那如果利用 webpack,起一个简单的 server 服务呢?这里,直接给一份配置即可:

  1. devServer: {
  2. contentBase: path.join(__dirname, "dist"), // 设置静态资源访问路径
  3. compress: true, // 执行压缩
  4. port: 9000 // 监听的端口
  5. }

不过,更常用的是利用 webpack server 的热更新机制。配置列表为:

  1. devServer: {
  2. contentBase: path.join(__dirname, "dist"),
  3. compress: true,
  4. port: 9000,
  5. hot: true,
  6. hotOnly: true
  7. }

接着,你就可以通过 localhost:9000 来访问你编译过后的目录。

剩下 server 配置,大家可以直接参考 webpack devServer 。

最后说几句

到这里,webpack 3.x 的整个内容差不多已经阐述完了。不过,关于 plugin 的内容,我们这里并没有过多提及,因为,对于一般 webpack 纯使用者来说,直接使用现有成熟的 plugin 即可。还有一个原因是,webpack plugin 内容真的有点多,这里篇幅有限就不写了。后面专门针对其内容详述一篇。

转载https://www.tuicool.com/articles/7Bj6VbY

发表评论

表情:
评论列表 (有 0 条评论,292人围观)

还没有评论,来说两句吧...

相关阅读

    相关 webpack3学习3--管理输出

    到目前为止,我们在 index.html 文件中手动引入所有资源,然而随着应用程序增长,并且一旦开始对文件名使用哈希(hash)\]并输出多个 bundle,手动地对 inde

    相关 webpack3学习笔记

    webpack 是前端开发者一个跨不过去的编译工具。不过由于他的快速迭代,让很多同学在学一个版本的时候,下一个新版本就发布了,让人感觉非常蛋疼和无奈: “我是谁,我在干嘛,我

    相关 webpack3总结笔记

    webpack 是前端开发者一个跨不过去的编译工具。不过由于他的快速迭代,让很多同学在学一个版本的时候,下一个新版本就发布了,让人感觉非常蛋疼和无奈: “我是谁,我在干嘛,我