在只要这几步,webpack速成不是事儿一文中, 笔者简单介绍了webpack的常见用法。能满足最基本的开发需求。在这篇文章中,再来谈谈一些较高级的应用。
1. 配置不同环境的构建脚本
之前构建都是通过 npx webpack ...
这样的方式执行构建命令。可能你会觉得这样的方式不够高效。甚至在某些特定的情况下还需要设置 Node 的环境变量。根据环境变量值的不同,设置构建 --mode 的不同。
scripts 配置的入口在 package.json
中,另外再介绍下。通过执行 npm i
默认安装package.json中全部依赖。
"scripts": {
"build": "webpack",
"dev": "webpack-dev-server"
},
cross-env 设置node环境变量的插件 npm i cross-env -D
- 开发环境构建:
npm run dev
通过图中可以看到,npm run dev
相当于 npx webpack-dev-server
- 生产环境构建:
npm run build
1.1 设置node环境变量
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server",
"build": "cross-env NODE_ENV=production webpack"
},
先安装插件cross-env
npm i cross-env -D
执行 npm run dev
, 先设置环境变量 NODE_ENV=devlelopment, 然后执行 webpack 命令。
为什么要设置环境变量呢? 设置环境变量后,可以在打包构建时执行相应环境变量下的脚本。
在webpack.config.js中process.env.NODE_ENV
拿到环境变量值。做你想做的事情。哈哈哈~
- 通过 webpack 自带的插件定义全局变量
_DEV_
,类似于全局变量 window
//应用: 在项目 src/index.js 文件中代码里区分开发或者是生产环境
if(__DEV__){
alert('开发环境')
}else{
alert('生产环境')
}
- 根据环境不同,来设置某些插件是否可用
在webpack.config.js文件中,设置变量 let isDev = process.env.NODE_ENV === 'development',然后定义插件的disable属性的值
plugins: [
new ExtractTextWebpackPlugin({
filename: 'css/index.css',
disable: isDev
}),
],
1.2 构建 DLL 动态链接库
.dll 为后缀的文件称为动态链接库,在一个动态链接库中可以包含给其他模块调用的函数和数据
- 把 基础模块独立出来打包到单独的动态连接库里
- 当需要导入的模块在动态连接库里的时候,模块不能再次被打包,而是去动态连接库里获取 dll-plugin
- 提高构建效率
react, react-dom 为例
- 创建 webpack.config.react.js
let path = require('path');
let webpack = require('webpack');
module.exports = {
entry: {
vendor: ['react', 'react-dom']
},
output: {
filename: '[name].js',
path: path.join(__dirname, 'dist'),
libraryTarget: "var", //构建后输出js文件所属规范, 如果 设置为 commonjs, 则输出文件符合 commonjs规范
library: '_dll_[name]', //构建后输出js库的名字
},
mode: 'development',
plugins: [
new webpack.DllPlugin({
name: '_dll_[name]',
path: path.join(__dirname, 'dist', '[name].manifest.json')
})
],
};
- 设置构建命令
"scripts": {
"build": "webpack",
"dev": "webpack-dev-server",
"react": "wepack --config webpack.config.react.js"
},
- 执行 npm run react
- 输出的 vendor.js
1.3 使用动态链接库
在webpack.config.js中配置插件
plugins: [
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, 'dist', 'vendor.manifest.json')
})
]
- react编译需要安装如下loader
npm i babel-core babel-loader babel-preset-env babel-preset-react babel-preset-stage-0 -D
- 配置相关rules
module: {
rules: [
{
test: /\.jsx?/,
use: 'babel-loader',
exclude:/node_modules/,
include:/src/
},
]
},
- 在项目根目录下创建 .babelrc文件
{
"presets": [
"env",
"stage-0",
"react"
]
}
- 执行构建命令
npm run build
, 控制台打印:
[./node_modules/react-dom/index.js] delegated ./node_modules/react-dom/index.js from dll-reference _dll_vendor 42 bytes {index} [built]
[./node_modules/react/index.js] delegated ./node_modules/react/index.js from dll-reference _dll_vendor 42 bytes {index} [built]
由此可以看出项目构建时是使用的预先构建好的react库文件,从控制台打印的构建耗时也明显不同。
2. 抽离公共代码(库文件或组件)
- 创建src/a.js, src/x.js 文件
- 在src/index.js 和 src/x.js文件中都import a.js文件
- 在src/index.js 和 src/x.js文件中都引入 react库文件
index.js
import './index.css';
// if(module.hot){
// console.log('热更新');
// }
import React, { Component } from 'react'
import { render } from 'react-dom'
import a from './a.js'
render(<h1>hello zfpx</h1>, window.app)
x.js
import React, { Component } from 'react'
import { render } from 'react-dom'
import a from './a.js'
a.js
module.exports = {
a: 'a.js'
}
在webpack.config.js中配置:
optimization: {
splitChunks: {
cacheGroups: {
commons: { //提供公共组件, 只要超出0字节就生产新的包
chunks: 'initial',
//miniChunks: 2,
//maxInitalRequest: 5,
name: 'commons',
minSize: 0
},
vendor: {// 抽离第三插件
test: /node_modules/,
chunks: 'initial',
name: 'vender',
priority: 10,
enforce: true
}
}
}
},
执行构建脚本 npm run build
, 控制台打印:
如果注释相关构建信息:
从二者控制台信息中可以看出,构建后的index.js 和 x.js文件体积大小和 dist目录中输出的文件数量是不一样的。3. 设置全局变量
在index.js中引入 jquery.js后,在a.js文件中想不引入jquery.js直接使用jquery对象
webpack.config.js中配置
module: {
rules: [
{
test: /jquery/,
use:[{
loader:'expose-loader',
options:'$'
}]
},
]
}
或者使用webpack提供的内置插件
// 提供全局变量插件
new webpack.ProvidePlugin({
$:'jquery'
}),
二者的区别是神马呢
- 使用插件时:
1. $不会定义到window上
2. 只要是用到jquery(或者 $)的地方,当前bundle.js都会把jquery打包进去
webpack.config.js 相关配置为:
entry: {
index: './src/index.js',
x: './src/x.js'
},
output: {
filename: '[name].[hash].bundle.js',
path: path.resolve(__dirname, 'dist'),
library: '_dll_[name]'
},
...
pugins: [
new HtmlWebpackPlugin({
template: 'src/index.html',
hash: true
}),
]
index.js
console.log($)
x.js
console.log($);
从构建的日志中可以看出,index.js构建后的文件大小和x.js构建的文件大小一致
- 使用 expose-loader
1.导入一次,就会暴露出来
2.$会定义到在window上
index.js
import $ from 'jquery'
console.log('index.js');
console.log($);
x.js
console.log('x.js');
console.log($);
console.log(window.$);
构建日志:
浏览器打印日志:
从构建的日志中可以看出,index.js构建后的文件大小和x.js构建的文件大小不一致 从浏览器打印日志可以看出,x.js在没有直接import jquery时,也可以拿到jquery对象
4. 小结
webpack还有很多其他适用的功能,比如在使用vue时,常常会根据路由加载相应的组件js也就是我们所说的 按需加载。可以用到webpack代码分离中的 动态导入和懒加载(dynamic imports),优化代码加载,提升性能。