webpack深入浅出(二)| 小册免费学

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 这一节内容主要介绍详细的webpack配置信息,毕竟“webpack高级配置工程师”是每个前端er的目标

1c355fc58bd6760e38dfc40ae4cc131.png

这一节内容主要介绍详细的webpack配置信息,毕竟“webpack高级配置工程师”是每个前端er的目标

首先要知道webpack的核心概念

  • entry:entry是配置模块的入口,可抽象成输入,Webpack 执行构建的第一步将从入口开始搜寻及递归解析出所有入口依赖的模块。
  • output:output 配置如何输出最终想要的代码。
  • mode:通过选择 development, productionnone 之中的一个,来设置 mode 参数,可以启用 webpack 内置在相应环境下的优化。其默认值为 production
  • loader:webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让 webpack 能够去处理其他类型的文件。
  • plugin:loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。

entry


entry的类型可以为字符串、数组或者对象

类型 例子 含义
string './app/entry' 入口模块的文件路径,可以是相对路径。
array ['./app/entry1', './app/entry2'] 入口模块的文件路径,可以是相对路径。
object { a: './app/entry-a', b: ['./app/entry-b1', './app/entry-b2']} 配置多个入口,每个入口生成一个 Chunk

Webpack 会为每个生成的 Chunk 取一个名称,Chunk 的名称和 Entry 的配置有关:

  • 如果 entry 是一个 stringarray,就只会生成一个 Chunk,这时 Chunk 的名称是 main
  • 如果 entry 是一个 object,就可能会出现多个 Chunk,这时 Chunk 的名称是 object 键值对里键的名称。

output


output是一个object,里面包含了输出文件名称、路径等信息,如下

output: {
    filename: '[name].js',
    path: path.resolve(__dirname, dist),
    publicPath: 'https://cdn.abcd.com/assets/',
    // libraryTarget: var,
    // library: 'test'
}
复制代码
  • filename:输出的文件名,[name]相当于是占位符,可以在编译时替换为内置的 name 变量,除此之外还有id(唯一标识,从0开始)、hash(唯一标识的哈希值),chunkhash(chunk内容的hash值),使用哈希值是可以指定长度如[hash:8].js,默认长度为20
  • path:配置输出文件存放在本地的目录,必须是 string 类型的绝对路径。通常通过 Node.js 的 path 模块去获取绝对路径
  • publicPath:复杂的项目里可能会有一些构建出的资源需要异步加载,加载这些异步资源需要对应的 URL 地址。publicPath就是用于设置这些URL的,比如上面的配置打包之后的html中就会引入
<script src="https://cdn.abcd.com/assets/main.js"></script>
复制代码
  • libraryTarget和library:当构建一个可以被其他模块导入的库时就需要用到这两个配置。libraryTarget配置以何种方式导出,library配置导出库的名字。默认以var方式导出,导出之后的内容是一个自执行函数,此外还有
  • commonjs(按照commonjs标准,exports['libraryName']导出,用require('dep')['libraryName']导入)、
  • commonjs2(与commonjs区别在于增加了module.exports,libraryTarget 为 commonjs2 时,配置 library 将没有意义)、
  • this(编写的库将通过 this 被赋值给通过 library 指定的名称)、
  • window(编写的库将通过 window 被赋值给通过 library 指定的名称)、
  • global(编写的库将通过 global 被赋值给通过 library 指定的名称)
  • libraryExport: 配置要导出的模块中哪些子模块需要被导出,它只有在 libraryTarget 被设置成 commonjs 或者 commonjs2 时使用才有意义

loader


webpack处理模块主要依赖的时loader,使用loader来解析不同的文件,最后统一输出

module: {
  rules: [
    {
      test: /\.less$/, // 正则匹配
      use: ['style-loader', 'css-loader'], // 要使用的loader
      exclude: path.resolve(__dirname, 'node_modules'), // 不包含的目录
      // include: path.join(__dirname, '/src'), // 包含的目录
    },{
      test: /\.less$/,
      loader: 'less-loader',
      exclude: path.resolve(__dirname, 'node_modules'),
      enforce: 'pre', // 有多个规则时,通过enfore可以控制执行循序,pre前置>行内>普通>post后置
    }
  ]
},
复制代码
  • relues:loader的配置放在module下的rules中,rules可以是一个数组也可以是一个对象,还可以是一个字符串,通过不同的匹配规则(test、incluede、exclude)来解析不同的模块
    匹配到文件之后使用loader或者use来声明要使用的loader,当需要有多个loader处理时使用use数组,可以为字符串数组(可以通过'loaderName?param'的形式给loader传递参数,废弃),当参数过多时,也可以使用对象来具体描述loader
use: [
{
  loader:'babel-loader',
  options:{
    cacheDirectory:true,
  },
},
]
// 等价于
use: ['babel-loader?cacheDirectory']
复制代码
  • noParse:使用noParse可以告知webpack忽略掉一些不必要解析的库,比如jquery等,让webpack 去解析这些文件耗时又没有意义,忽略解析可以提高性能
module: {
    noParse: /jquery/
}
复制代码
  • parser:和noParse区别在于,noParse只能控制文件不被解析,而parser可以精确到语法
module: {
  rules: [
    {
      test: /\.js$/,
      use: ['babel-loader'],
      parser: {
      amd: false, // 禁用 AMD
      commonjs: false, // 禁用 CommonJS
      }
    },
  ]
}
复制代码


plugin


插件目的在于解决 loader 无法实现的其他事。由于插件可以携带参数/选项,必须在 webpack 配置中,向 plugins 属性传入一个 new 实例。

几乎所有 Webpack 无法直接实现的功能都能在社区找到开源的 Plugin 去解决


devServer


devServer可以显著体改开发效率

  • hot:模块热替换功能,默认的行为是在发现源代码被更新后会通过自动刷新整个页面来做到实时预览,开启模块热替换功能后将在不刷新整个页面的情况下通过用新模块替换老模块来做到实时预览。
  • contentBase:配置 DevServer HTTP 服务器的文件根目录,默认情况下为当前执行目录,通常是项目根目录。
  • headers:可以在 HTTP 响应中注入一些 HTTP 响应头。
  • host:DevServer 服务监听的地址,默认值是127.0.0.1,如果想让局域网中的其他机器可以访问,可以设置0.0.0.0
  • port:端口号,默认使用 8080 端口。
  • allowHosts:一个白名单列表,只有 HTTP 请求的 HOST 在列表里才正常返回。
  • https:开启https,会自动的为你生成一份 HTTPS 证书。也可以手动配置
devServer:{
  https: {
    key: fs.readFileSync('path/to/server.key'),
    cert: fs.readFileSync('path/to/server.crt'),
    ca: fs.readFileSync('path/to/ca.pem')
  }
}
复制代码
  • open:编译完成自动打开浏览器访问。
  • openPage:设置open打开的URL。
  • compress:是否开启gzip压缩。
  • proxy:可以将特定的url转发到另一台服务器
proxy: {
  '/api': {
    target: 'http://localhost:3000/api',
    // 如果要代理 websockets
    ws: true,
    // 将主机标头的原点更改为目标URL
    changeOrigin: true,
    secure: false,
    pathRewrite: {
      [`^/api`]: ''
    }
  }
}
// 在访问/api/users时,就会转发到http://localhost:3000/api/users
复制代码


resolve


可以设置设置模块如何被解析

  • alias:别名,可以给对应的路径设置别名来简化书写。例如
resolve:{
  alias:{
    @: './src' // 可以在代码中通过'@'来代替src,原来的./src/views可以用@/views访问
  }
}
复制代码
  • extensions:在导入语句没带文件后缀时,webpack会按照配置的后缀顺序去寻找文件
resolve: {
    extensions: ['.js', '.json']
    // 导入import './foo'时,会先寻找foo.js,如果没有找到会再去找foo.json
}
复制代码
  • modules:告知webpack去哪些目录下寻找依赖
resolve: {
    modules:['./src/components','node_modules']
    // 导入require('foo')时,会优先去'./src/components'目录下寻找,然后再去node_modules下寻找
}
复制代码
  • descriptionFiles:配置描述第三方模块的文件名称,默认是 package.json 文件。
  • enforceExtension:配置导入文件是否必须带后缀,默认为false。如果配置为true,导入时就必须import foo from './foo.js'
  • enforceModuleExtension:与enforceExtension搭配使用,一些第三方依赖包没有携带文件后缀,通过设置enforceModuleExtension: false 来兼容第三方模块


其他


module.export = {
  devtool: 'source-map', // 控制是否生成source-map
  watch: true, // 是否开启文件监听
  watchOptions: {
    // 不监听的文件或文件夹,支持正则匹配
    // 默认为空
    ignored: /node_modules/,
    // 监听到变化发生后会等300ms再去执行动作,防止文件更新太快导致重新编译频率太高
    // 默认为 300ms  
    aggregateTimeout: 300,
    // 默认每隔1000毫秒询问一次
    poll: 1000
  },
  externals: {
    // 把导入语句里的 jquery 替换成运行环境里的全局变量 jQuery
    jquery: 'jQuery'
  },
  resolveLoader:{
    // 去哪个目录下寻找 loader
    modules: ['node_modules'],
    // 入口文件的后缀
    extensions: ['.js', '.json'],
    // 指明入口文件位置的字段
    mainFields: ['loader', 'main']
  }
}
复制代码


其他配置类型


webpack.config.js可以导出一个对象,这是最常见的形式,此外webpack还可以导出一个函数,这个函数接收两个参数环境变量env和命令参数argv,导出形式如下

const UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
module.exports = function (env = {}, argv) {
  const plugins = [];
  const isProduction = env['production'];
  // 在生产环境才压缩
  if (isProduction) {
    plugins.push(
      new UglifyJsPlugin()
    )
  }
  return {
    plugins: plugins,
    // 在生成环境不输出 Source Map
    devtool: isProduction ? undefined : 'source-map',
  };
}
复制代码

除此之外还可以导出一个Promise,用于不能以同步的方式返回一个描述配置的 Object时

module.exports = function(env = {}, argv) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        // ...
      })
    }, 5000)
  })
}


相关文章
|
缓存 JavaScript 前端开发
webpack深入浅出(四)| 小册免费学
随着时间和业务量的累积,代码变得越来越臃肿,打包时间变得越来越长,这无疑是一件很头疼的事情(虽然现在大部分都是CI/CD构建),缩小搜索范围也可以减少构建时间
93 0
|
JSON 前端开发 JavaScript
webpack深入浅出(三)| 小册免费学
之前我们了解了webpack中的配置方式,下面我们来说一下实际生产中经常使用的loader以及plugin 以下说到的所有依赖都将省略安装过程,除非特别指明,否则都是直接npm安装依赖名
70 0
|
前端开发 JavaScript
webpack深入浅出(一)| 小册免费学
随着前端应用的日益复杂,通过直接编写 JavaScript、CSS、HTML 开发 Web 应用的方式已经无法应对当前 Web 应用的发展,前端工程化越来越受到了重视,许多前端构建工具脱颖而出,webpack就是目前最为流行的打包构建工具,因此每位前端er都需要掌握webpack技术。
67 0
|
3月前
|
JavaScript
webpack打包TS
webpack打包TS
135 60
|
2月前
|
缓存 前端开发 JavaScript
Webpack 打包的基本原理
【10月更文挑战第5天】
|
2月前
|
前端开发 JavaScript
ES6模块化和webpack打包
【10月更文挑战第5天】
|
2月前
|
缓存 前端开发 JavaScript
深入了解Webpack:模块打包的革命
【10月更文挑战第11天】深入了解Webpack:模块打包的革命
|
3月前
|
JavaScript 测试技术 Windows
vue配置webpack生产环境.env.production、测试环境.env.development(配置不同环境的打包访问地址)
本文介绍了如何使用vue-cli和webpack为Vue项目配置不同的生产和测试环境,包括修改`package.json`脚本、使用`cross-env`处理环境变量、创建不同环境的`.env`文件,并在`webpack.prod.conf.js`中使用`DefinePlugin`来应用这些环境变量。
141 2
vue配置webpack生产环境.env.production、测试环境.env.development(配置不同环境的打包访问地址)
|
2月前
|
缓存 前端开发 JavaScript
Webpack技术深度解析:模块打包与性能优化
【10月更文挑战第13天】Webpack技术深度解析:模块打包与性能优化
|
2月前
|
前端开发 JavaScript 开发者
深入了解Webpack:现代JavaScript应用的打包利器
【10月更文挑战第11天】 深入了解Webpack:现代JavaScript应用的打包利器