这篇主要介绍《webpack优化环境配置(中)》。
知识点包括:
一、tree shaking
1、复制上一篇的生产环境缓存工程文件。然后重命名。
tree shaking(树摇):去除无用的代码。
2、在src文件夹下新建test.js,测试使用该功能,是否会把没有引用的js代码也打包。
test.js代码如下,两个函数都使用export暴露出去。
export function mul(x, y) {
return x * y;
}
export function count(x, y) {
return x - y;
}
3、index.js代码,我们只引入test.js中的一个mul函数,那么count函数就没有被用到,那么使用tree shaking后,打包后的文件应该没有count函数,被去掉了。
import '../css/index.css';
// 引入icon-font样式文件
import '../iconfit/iconfont.css';
// 只引入test.js中的一个mul函数
import { mul } from './test';
function sum(...args) {
return args.reduce((p, c) => p + c, 0);
}
console.log(mul(2, 2));
console.log(sum(1, 2, 3, 4));
4、config中需要修改运行环境为production环境,注释说明入代码中所写
const { resolve } = require('path');
const minicssextractplugin = require('mini-css-extract-plugin');
const cssminimizerwebpackplugin = require('css-minimizer-webpack-plugin');
const Htmlwebpackplugin = require('html-webpack-plugin');
// css浏览器兼容性处理,默认是运行在生产环境下,若要运行于开发环境,还需做以下代码
process.env.NODE_ENV = 'production'
// tree shaking:去除无用代码
//前提: 1.必须使用ES6模块化2.开启production环境
//作用:减少代码体积
//在package.json中配置"sideEffects" : false所有代码都没有副作用(都可以进行tree shaking)
//问题:可能会把css/@babel/polyfill (副作用)文件干掉,因为这些文件都是引入了,但没有直接使用
//,所以需要配置为"sideEffects" : ["*.css"]
module.exports = {
entry: {
// 把之前的单入口修改为多入口
// 有几个入口,打包就生成几个built.js
index: './src/js/index.js',
test: './src/js/test.js'
},
output: {
// [name]:取entry中的入口文件名进行命名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [{
// oneOf 是每一个文件,只匹配到一个loader即可,
// 不像之前,每个文件都要把下列loader全部匹配一遍
// 注意不能有两个loader处理同一个类型文件
oneOf: [
{
// 检测css文件,并打包
test: /\.css$/,
use: [
minicssextractplugin.loader,
'css-loader',
{
// 对css做兼容性处理
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [require('postcss-preset-env')()]
}
}
}
]
},
{
// 检测less文件,并打包
test: /\.less$/,
// use内代码,是从下往上的顺序执行的
use: [
minicssextractplugin.loader,
'css-loader',
{
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [require('postcss-preset-env')()]
}
}
},
'less-loader'
]
},
{
// js兼容性处理
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env', {
useBuiltIns: 'usage',
corejs:
{
version: 3
},
targets: {
// 浏览器兼容的版本
chrome: '60',
firefox: '50'
}
}
]
]
}
},
{
//对图片进行打包处理
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
outputPath: 'imgs',
esModule: false
},
type: 'javascript/auto'
},
{
// 处理html中的图片文件
test: /\.html$/,
loader: 'html-loader',
options: {
esModule: false,
}
},
{
// 处理其他文件,如字体图标等
exclude: /\.(js|css|less|html|jpg|png|gif)$/,
loader: 'file-loader',
options: {
outputPath: 'media',
esModule: false,
},
type: 'javascript/auto'
}
]
}]
},
plugins: [
new minicssextractplugin({
// 打包提取成单独文件
filename: 'css/built.[contenthash:10].css'
}),
new cssminimizerwebpackplugin(
// 压缩css文件
),
new Htmlwebpackplugin({
template: './src/index.html',
// 压缩html
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
// 生产环境下,js自动压缩
mode: 'production'
}
5、package.json中代码
{
"name": "webpack_production",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack --mode development",
"build": "webpack --mode production"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.16.5",
"@babel/preset-env": "^7.16.5",
"babel-loader": "^8.2.3",
"core-js": "^3.21.1",
"css-loader": "^6.5.1",
"css-minimizer-webpack-plugin": "^3.3.1",
"eslint": "^8.10.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.25.4",
"eslint-webpack-plugin": "^3.1.1",
"file-loader": "^6.2.0",
"html-loader": "^3.0.1",
"html-webpack-plugin": "^5.5.0",
"less-loader": "^10.2.0",
"mini-css-extract-plugin": "^2.4.5",
"postcss-loader": "^6.2.1",
"postcss-preset-env": "^7.1.0",
"style-loader": "^3.3.1",
"url-loader": "^4.1.1",
"webpack": "^5.65.0",
"webpack-cli": "^4.9.1"
},
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
},
"sideEffects": [
"*.css"
]
}
注意:为了能够识别ES6模块,需要下载core-js包。输入npm i core-js -D,
然后输入npm run build
即可进行打包。
最后打包成功的built.js中只包含了引入并使用的mul函数,未被引入和使用的count函数并没有被打包进来。
二、code split(代码分割)
第一种方法
代码分割会把打包的一个大文件分割成多个不同的文件,这样在加载的时候就会并行加载,速度更快。还可以实现按需下载。
1、复制上一小节工程文件,并重命名。
在src下的js文件夹中有两个.js文件,我们以往打包是最后只生成了一个built.js文件,如果想生成两个呢。
2、首先修改index.js代码,去除引入的test.js代码
import '../css/index.css';
// 引入icon-font样式文件
import '../iconfit/iconfont.css';
function sum(...args) {
return args.reduce((p, c) => p + c, 0);
}
console.log(sum(1, 2, 3, 4));
2、修改webpck.config.js代码
const { resolve } = require('path');
const minicssextractplugin = require('mini-css-extract-plugin');
const cssminimizerwebpackplugin = require('css-minimizer-webpack-plugin');
const Htmlwebpackplugin = require('html-webpack-plugin');
// css浏览器兼容性处理,默认是运行在生产环境下,若要运行于开发环境,还需做以下代码
process.env.NODE_ENV = 'production'
// tree shaking:去除无用代码
//前提: 1.必须使用ES6模块化2.开启production环境
//作用:减少代码体积
//在package.json中配置"sideEffects" : false所有代码都没有副作用(都可以进行tree shaking)
//问题:可能会把css/@babel/polyfill (副作用)文件干掉,因为这些文件都是引入了,但没有直接使用
//,所以需要配置为"sideEffects" : ["*.css"]
module.exports = {
entry: {
// 把之前的单入口修改为多入口
// 有几个入口,打包就生成几个built.js
index: './src/js/index.js',
test: './src/js/test.js'
},
output: {
// [name]:取entry中的入口文件名进行命名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [{
// oneOf 是每一个文件,只匹配到一个loader即可,
// 不像之前,每个文件都要把下列loader全部匹配一遍
// 注意不能有两个loader处理同一个类型文件
oneOf: [
{
// 检测css文件,并打包
test: /\.css$/,
use: [
minicssextractplugin.loader,
'css-loader',
{
// 对css做兼容性处理
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [require('postcss-preset-env')()]
}
}
}
]
},
{
// 检测less文件,并打包
test: /\.less$/,
// use内代码,是从下往上的顺序执行的
use: [
minicssextractplugin.loader,
'css-loader',
{
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [require('postcss-preset-env')()]
}
}
},
'less-loader'
]
},
{
// js兼容性处理
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env', {
useBuiltIns: 'usage',
corejs:
{
version: 3
},
targets: {
// 浏览器兼容的版本
chrome: '60',
firefox: '50'
}
}
]
]
}
},
{
//对图片进行打包处理
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
outputPath: 'imgs',
esModule: false
},
type: 'javascript/auto'
},
{
// 处理html中的图片文件
test: /\.html$/,
loader: 'html-loader',
options: {
esModule: false,
}
},
{
// 处理其他文件,如字体图标等
exclude: /\.(js|css|less|html|jpg|png|gif)$/,
loader: 'file-loader',
options: {
outputPath: 'media',
esModule: false,
},
type: 'javascript/auto'
}
]
}]
},
plugins: [
new minicssextractplugin({
// 打包提取成单独文件
filename: 'css/built.[contenthash:10].css'
}),
new cssminimizerwebpackplugin(
// 压缩css文件
),
new Htmlwebpackplugin({
template: './src/index.html',
// 压缩html
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
// 生产环境下,js自动压缩
mode: 'production'
}
最后打包生成的文件,这就是对js文件进行了代码分割,通过修改入口文件的方法。
第二种方法
1、我们将config.js代码的入口文件改回一个,并使用一个内置的配置splitChunks
开启代码分割功能。
const { resolve } = require('path');
const minicssextractplugin = require('mini-css-extract-plugin');
const cssminimizerwebpackplugin = require('css-minimizer-webpack-plugin');
const Htmlwebpackplugin = require('html-webpack-plugin');
// css浏览器兼容性处理,默认是运行在生产环境下,若要运行于开发环境,还需做以下代码
process.env.NODE_ENV = 'production'
// tree shaking:去除无用代码
//前提: 1.必须使用ES6模块化2.开启production环境
//作用:减少代码体积
//在package.json中配置"sideEffects" : false所有代码都没有副作用(都可以进行tree shaking)
//问题:可能会把css/@babel/polyfill (副作用)文件干掉,因为这些文件都是引入了,但没有直接使用
//,所以需要配置为"sideEffects" : ["*.css"]
module.exports = {
entry: './src/js/index.js',
output: {
// [name]:取entry中的入口文件名进行命名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [{
// oneOf 是每一个文件,只匹配到一个loader即可,
// 不像之前,每个文件都要把下列loader全部匹配一遍
// 注意不能有两个loader处理同一个类型文件
oneOf: [
{
// 检测css文件,并打包
test: /\.css$/,
use: [
minicssextractplugin.loader,
'css-loader',
{
// 对css做兼容性处理
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [require('postcss-preset-env')()]
}
}
}
]
},
{
// 检测less文件,并打包
test: /\.less$/,
// use内代码,是从下往上的顺序执行的
use: [
minicssextractplugin.loader,
'css-loader',
{
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [require('postcss-preset-env')()]
}
}
},
'less-loader'
]
},
{
// js兼容性处理
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env', {
useBuiltIns: 'usage',
corejs:
{
version: 3
},
targets: {
// 浏览器兼容的版本
chrome: '60',
firefox: '50'
}
}
]
]
}
},
{
//对图片进行打包处理
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
outputPath: 'imgs',
esModule: false
},
type: 'javascript/auto'
},
{
// 处理html中的图片文件
test: /\.html$/,
loader: 'html-loader',
options: {
esModule: false,
}
},
{
// 处理其他文件,如字体图标等
exclude: /\.(js|css|less|html|jpg|png|gif)$/,
loader: 'file-loader',
options: {
outputPath: 'media',
esModule: false,
},
type: 'javascript/auto'
}
]
}]
},
plugins: [
new minicssextractplugin({
// 打包提取成单独文件
filename: 'css/built.[contenthash:10].css'
}),
new cssminimizerwebpackplugin(
// 压缩css文件
),
new Htmlwebpackplugin({
template: './src/index.html',
// 压缩html
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
// 代码分割的配置,可以将node_modules中代码单独打包一个chunk输出
// 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk输出
optimization: {
splitChunks: {
chunks: 'all'
}
},
// 生产环境下,js自动压缩
mode: 'production'
}
2、然后修改index.js代码,增加一个官方的node_modules(jquery)。
import '../css/index.css';
// 引入icon-font样式文件
import '../iconfit/iconfont.css';
// 引入jquery
import $ from 'jquery';
function sum(...args) {
return args.reduce((p, c) => p + c, 0);
}
console.log($);
console.log(sum(1, 2, 3, 4));
3、然后安装jquery,npm i jquery --save
,最后打包npm run build
。
会将自己编写的index.js和jquery有关的js分开生成,即生成两个.js文件。
第三种方法
第三种方法是通过修改index.js文件实现的,import动态导入语法,能将某个文件单独打包,config.js中入口还是修改为单入口。
我们希望除了官方的node_modules,其他使用的js文件也可以被分割打包出来。
1、首先把config.js中的第二种方法使用的插件去掉。
const { resolve } = require('path');
const minicssextractplugin = require('mini-css-extract-plugin');
const cssminimizerwebpackplugin = require('css-minimizer-webpack-plugin');
const Htmlwebpackplugin = require('html-webpack-plugin');
// css浏览器兼容性处理,默认是运行在生产环境下,若要运行于开发环境,还需做以下代码
process.env.NODE_ENV = 'production'
// tree shaking:去除无用代码
//前提: 1.必须使用ES6模块化2.开启production环境
//作用:减少代码体积
//在package.json中配置"sideEffects" : false所有代码都没有副作用(都可以进行tree shaking)
//问题:可能会把css/@babel/polyfill (副作用)文件干掉,因为这些文件都是引入了,但没有直接使用
//,所以需要配置为"sideEffects" : ["*.css"]
module.exports = {
entry: './src/js/index.js',
output: {
// [name]:取entry中的入口文件名进行命名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [{
// oneOf 是每一个文件,只匹配到一个loader即可,
// 不像之前,每个文件都要把下列loader全部匹配一遍
// 注意不能有两个loader处理同一个类型文件
oneOf: [
{
// 检测css文件,并打包
test: /\.css$/,
use: [
minicssextractplugin.loader,
'css-loader',
{
// 对css做兼容性处理
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [require('postcss-preset-env')()]
}
}
}
]
},
{
// 检测less文件,并打包
test: /\.less$/,
// use内代码,是从下往上的顺序执行的
use: [
minicssextractplugin.loader,
'css-loader',
{
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [require('postcss-preset-env')()]
}
}
},
'less-loader'
]
},
{
// js兼容性处理
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env', {
useBuiltIns: 'usage',
corejs:
{
version: 3
},
targets: {
// 浏览器兼容的版本
chrome: '60',
firefox: '50'
}
}
]
]
}
},
{
//对图片进行打包处理
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
outputPath: 'imgs',
esModule: false
},
type: 'javascript/auto'
},
{
// 处理html中的图片文件
test: /\.html$/,
loader: 'html-loader',
options: {
esModule: false,
}
},
{
// 处理其他文件,如字体图标等
exclude: /\.(js|css|less|html|jpg|png|gif)$/,
loader: 'file-loader',
options: {
outputPath: 'media',
esModule: false,
},
type: 'javascript/auto'
}
]
}]
},
plugins: [
new minicssextractplugin({
// 打包提取成单独文件
filename: 'css/built.[contenthash:10].css'
}),
new cssminimizerwebpackplugin(
// 压缩css文件
),
new Htmlwebpackplugin({
template: './src/index.html',
// 压缩html
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
// 代码分割的配置,可以将node_modules中代码单独打包一个chunk输出
// 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk输出
optimization: {
splitChunks: {
chunks: 'all'
}
},
// 生产环境下,js自动压缩
mode: 'production'
}
2、修改index.js代码,import动态导入语法,能将某个文件单独打包
import '../css/index.css';
// 引入icon-font样式文件
import '../iconfit/iconfont.css';
function sum(...args) {
return args.reduce((p, c) => p + c, 0);
}
console.log(sum(1, 2, 3, 4));
// 通过js代码,实现代码分割功能。以ES10的方法引入test.js
// import动态导入语法,能将某个文件单独打包
// webpackChunkName:'test'表示打包后的文件名为test
import(/*webpackChunkName:'test'*/'../js/test')
.then((result) => {
console.log(result);
})
.catch(() => {
console.log('文件加载失败~');
})
3、输入npm run build
打包
注:笔记转载自疯子的梦想@博客,课程来自尚硅谷b站Webpack5实战课程