这篇主要介绍《webpack优化环境配置(中)》。(demo代码github地址)
知识点包括:
一、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实战课程