1.安装
本地安装
```js
npm install webpack@4 webpack-cli@3 -D
```
2.运行
npm版本在5.2以上的在本地用npx 运行本地安装的webpack
npx webpack
webpack4.0开始实行的是零配置,零配置的特点有很多限制,很多配置不能自定义。
3.webpack的配置
webpack的四大核心概念
1.入口(entry)
因为webpack是用node.js写的,所以webpack遵循的是comm.js规范,
1.在项目的根目录下建立一个webpack.config.js文件,
2.webpack.config.js的基本配置
2.输出(output)
3.loader
4.插件
基本配置
const path = require('path') //node的path模块,用于解析路径
module.exports = {
entry: './src/main.js', //入口文件,相对路径
output: { //出口文件,是绝对路径,要是用node的path模块
path: path.resolve(__dirname, './dist/'),
filename: 'bundle.js',
},
mode: "development" //模式,默认是"production",使用"production"模式打包的压缩混淆的
}
4.webpack的命令配置(在执行npx webpack时可以指定配置文件)
```js
npx webpack --config 要执行的配置文件
```
5.webpack的devServer的使用
1.可以在package.json中添加配置项
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"dev": "webpack-dev-server --hot --compress --open --port 500 --contentBase src",//这里就是devServer的部分指令
},
2.也可以在webpack.config.js添加配置
在package.json中的配置
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"dev": "webpack-dev-server ",
},
在webpack.config.js中添加配置文件
const path = require('path') //node的path模块,用于解析路径的
module.exports = {
entry: './src/main.js', //入口文件,相对路径
output: { //出口文件,是绝对路径,要是用node的path模块
path: path.resolve(__dirname, './dist/'),
filename: 'build.js',
},
mode: "development", //模式,默认是"production",使用"production"模式打包的压缩混淆的
devServer: {
open: true, //启动后打开
hot: true,//开启热更新模式
compress: true,//gzip压缩开启
port: 5000,//自定义端口
contentBase: path.join(__dirname, './src/') //指定托管的目录
}
}
2.webpack-dev-middleware的配置
安装 webpack-dev-middleware
```js
npm install --save-dev express webpack-dev-middleware
```
在项目的根目录下创建一个server.js服务
```js
//用express 搭建了一个server.js 服务
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const app = express();
const config = require('./webpack.config.js'); //引入webpack.config.js配置文件
const compiler = webpack(config);
app.use(webpackDevMiddleware(compiler, {
publicPath: ‘/’ //项目放在根目录下
}));
app.listen(3000, function () {
console.log(‘http://localhost:3000’);
});
```
修改 package.json的启动文件
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"watch": "webpack --watch",
"dev2": "webpack-dev-server --hot --compress --open --port 500 --contentBase src",
"dev": "webpack-dev-server",
"server":"node server.js" //使用npm run server 启动项目
},
在开发中常使用的是webpack-dev-server,
6.webapck中的插件
-
html插件
这个是webpack中的最重要的一个插件,在webpack.config.js中配置,使用方法如下;
第一下载插件:npm install --save-dev html-webpack-plugin;
const path = require('path') //node的path模块,用于解析路径的 const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/main.js', //入口文件,相对路径 output: { //出口文件,是绝对路径,要是用node的path模块 path: path.resolve(__dirname, './dist/'), filename: 'build.js', }, mode: "development", //模式,默认是"production",使用"production"模式打包的压缩混淆的 devServer: { open: true, //启动后打开 hot: true,//开启热更新模式 compress: true,//gzip压缩 port: 5000,//自定义端口 // contentBase: path.join(__dirname, './src/') //指定托管的目录 }, plugins: [new HtmlWebpackPlugin({ filename: 'index.html', //文件名 template: './src/index.html'//模板路径 })] }
7.webpack中的loader
-
css loader
npm install css-loader --save-dev npm install style-loader --save-dev
-
在webpack.config.js添加配置项
const path = require('path') //node的path模块,用于解析路径的 const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/main.js', //入口文件,相对路径 output: { //出口文件,是绝对路径,要是用node的path模块 path: path.resolve(__dirname, './dist/'), filename: 'build.js', }, mode: "development", //模式,默认是"production",使用"production"模式打包的压缩混淆的 devServer: { open: true, //启动后打开 hot: true,//开启热更新模式 compress: true,//gzip压缩 port: 5000,//自定义端口 // contentBase: path.join(__dirname, './src/') //指定托管的目录 }, plugins: [new HtmlWebpackPlugin({ filename: 'index.html', //文件名 template: './src/index.html'//模板路径 })], //loader module: { rules: [ { test: /\.css$/, //正则匹配 use: ['style-loader', 'css-loader'] //loader的执行是从右向左执行的,要注意loader的顺序 } ] } }
-
其他的的loader的使用
-
sass-loader的使用
npm install sass-loader node-sass --save-dev
webpack.config.js的配置
{ test: /\.s(c|a)ss$/, use: ["style-loader", "css-loader", "sass-loader"] }
-
less-loader的使用
npm install --save-dev css-loader
webpack.config.js的配置
{ test: /\.less$/, use: ["style-loader", "css-loader", "less-loader"] },
-
file-loader和url-loader的使用(处理图片和字体),使用url-loader时一定要下载file-loader,url-loader不能独立使用
npm install file-loader --save-dev
webpack.config.js的配置
{ test: /\.(png|jpg|gif|jpeg)$/, use: ['file-loader'] }, //也可是 { test: /\.(png|jpg|gif|jpeg)$/, use: [ { loader: 'url-loader', options: { limit: 20 * 1024,// 小于这个值的图片转换为base64 outputPath: 'images',//存放图片的文件夹名 name: '[name]-[hash:4].[ext]'//图片的名字和后缀,hash:4表示hash值保留4位 } } ] }, //字体图标 { test: /\.(eot|svg|ttf|woff|woff2)$/, use: ['url-loader'] }
-
bable-loader(ES6语法转为ES5语法的)
安装 npm install -D babel-loader @babel/core @babel/preset-env
高级语法的支持 需要根据不同的情况添加不插件,可以在babel的官网查看
对生成器generate的兼容处理需要安装插件@babel/plugin-transform-runtime
npm install --save-dev @babel/plugin-transform-runtime npm install --save @babel/runtime
webpack.config.js的配置
{ test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'], plugins: [ '@babel/plugin-transform-classes', '@babel/plugin-transform-runtime' ] } } }
官方跟推介使用.babelrc的方式把插件配置抽离处理.babelrc是一个json文件
{ "presets": ["@babel/preset-env"], "plugins": [ "@babel/plugin-transform-classes", "@babel/plugin-transform-runtime" ] }
对于ES5的高级语法,使用@babel/polyfill 的转换
npm install --save @babel/polyfill
在要使用的文件中引入
import "@babel/polyfill";
也可以在webpack.config.js的入口文件引入
entry: ["@babel/polyfill", "./src/main.js"],
-
8.source map的使用
-
在webpack.config.js中将
mode
设置为'development'
。 -
添加一个配置项: devtool:‘cheap-module-eval-source-map’,
const path = require('path') //node的path模块,用于解析路径的 const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { // entry: './src/main.js', //入口文件,相对路径 entry: ["@babel/polyfill", "./src/main.js"], output: { //出口文件,是绝对路径,要是用node的path模块 path: path.resolve(__dirname, './dist/'), filename: 'build.js', }, mode: "development", //模式,默认是"production",使用"production"模式打包的压缩混淆的 devServer: { open: true, //启动后打开 hot: true,//开启热更新模式 compress: true,//gzip压缩 port: 5000,//自定义端口 // contentBase: path.join(__dirname, './src/') //指定托管的目录 }, plugins: [new HtmlWebpackPlugin({ filename: 'index.html', //文件名 template: './src/index.html'//模板路径 })], //loader module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader', 'less-loader'] }, { test: /\.less$/, use: ["style-loader", "css-loader", "less-loader"] }, { test: /\.s(c|a)ss$/, use: ["style-loader", "css-loader", "sass-loader"] }, { test: /\.(png|jpg|gif|jpeg)$/, use: [ { loader: 'url-loader', options: { limit: 20 * 1024, outputPath: 'images', name: '[name]-[hash:4].[ext]' } } ] }, { test: /\.(eot|svg|ttf|woff|woff2)$/, use: ['url-loader'] }, { test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader' } } ], }, devtool: 'cheap-module-eval-source-map'//开发环境使用的source map }
9.clean-webpack-plugin打包时自动清除dist目录中的文件,重新生成新的文件
-
使用方式
npm install --save-dev clean-webpack-plugin
-
在webpack.config.js中引入插件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
-
配置插件
plugins: [ new CleanWebpackPlugin() ],
10.CopyWebpackPlugin插件的使用,将单个文件或整个目录复制到构建目录,
-
下载插件
npm install copy-webpack-plugin --save-dev
-
在webpack.config.js中引入
const CopyPlugin = require("copy-webpack-plugin");
-
配置插件
plugins: [ new CopyPlugin({ patterns: [ { from: path.resolve(__dirname, 'assets'), to: "assets" } //from原文件地址,to生成的文件地址 ], }) ],
11.webpack 的内置插件
-
BannerPlugin自动生成注释插件
不需要下载引入,直接使用,webpack.config.js的配置
//导入webpack const { BannerPlugin } = require('webpack'); //配置插件 plugins: [ new BannerPlugin('这是一个全局的注释!!') ],
12.webpack的高级配置
-
通过webpack处理html中的img图片资源 使用html-withimg-loader,
-
多页应用程序的打包
-
在webpack.config.js中的entry中添加多个入口文件,
//1.修改为多入口 entry: { index: './src/main.js', other: './src/other.js' }, //2.多入口要对应多个.js文件 output: { //出口文件,是绝对路径,要是用node的path模块 path: path.resolve(__dirname, './dist/'), filename: '[name].js', //使用[name].js输入不同名的js }, //3.创建多个页面 plugins: [ //创建多个页面 //indexy页面 new HtmlWebpackPlugin({ filename: 'index.html', //文件名 template: './src/index.html',//模板路径 chunks: ['index'] //使用chunk加载对应的.js文件 }), //其他页面 new HtmlWebpackPlugin({ filename: 'other.html', //文件名 template: './src/other.html',//模板路径 chunks: ['other']//加载other.js文件 }), new CleanWebpackPlugin(), new CopyPlugin({ patterns: [ { from: path.resolve(__dirname, 'assets'), to: "assets" } ], }), new BannerPlugin('这是一个全局的注释!!') ],
-
第三方库的引入方式
-
通过expose-loader全局注入,
-
npm install expose-loader --save-dev加载插件
-
在webpack.config.js中添加loader
//全局引入jquery { test: require.resolve('jquery'), use: [{ loader: 'expose-loader', options: '$' }] },
-
-
使用内置插件webpack.providePlugin引入
plugins: [ new ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }) ],
-
13.生成模式(production)和开发模式(development)对应的不同配置
-
将webpack.config.js配置文件公共配置,开发环境配置和生产环境配置
-
下载** webpack-merge**
npm i webpack-merge
-
合并配置,webpack.pro.js
//开发环境 //1.导入merge const { merge } = require('webpack-merge'); const webpackBase = require('./webpack.base.js'); //2.导入公共配置 const webpackbase = require('./webpack.base.js'); //3合并配置并导出 module.exports = merge(webpackBase, { mode: "development", //开发环境 devServer: { open: true, //启动后打开 hot: true,//开启热更新模式 compress: true,//gzip压缩 port: 5000,//自定义端口 // contentBase: path.join(__dirname, './src/') //指定托管的目录 }, devtool: 'cheap-module-eval-source-map'//开发环境使用的source map })
-
生产换的合并
//生成环境 //1.导入merge const { merge } = require('webpack-merge'); const webpackBase = require('./webpack.base.js'); //合并 module.exports = merge(webpackBase, { mode: "production", //模式,默认是"production",使用"production"模式打包的压缩混淆, })
-
修改webpack.json
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack --config ./webpack.pro.js", //打包使用webpack.pro.js "watch": "webpack --watch", "dev2": "webpack-dev-server --hot --compress --open --port 500 --contentBase src", "dev": "webpack-dev-server --config ./webpack.dev.js", //生产环境使用webpack.dev.js "server": "node server.js" },
14.定义环境变量区分开发环境还是生产环境
-
使用webpack 的内置插件 DefinePlugin来配置变量
//开发环境 plugins: [ new DefinePlugin({ IS_DEV: 'true' }) ], //生产环境 plugins: [ new DefinePlugin({ IS_DEV: 'false' }) ],
-
在 src目录中可以全局访问这个变量
-
14.跨域问题和常用的解决方式
-
使用代理()
devServer: { open: true, //启动后打开 hot: true,//开启热更新模式 compress: true,//gzip压缩 port: 5000,//自定义端口 // contentBase: path.join(__dirname, './src/') //指定托管的目录 proxy: { "/api": { target: "http://localhost:3000", pathRewrite: { "^/api": "" } } } },
15.模块热替换HRM
-
使用module.hot.accept()实行代码的热更新
module.hot.accept('./hot.js',function(){ //这里不可以用import导入要热更新的代码 })
16.webpack的打包优化
-
production模式打包的自带优化
-
three shaking
它依赖于 ES2015 模块语法的 静态结构 特性,导入和导出要使用import和export
-
scope-hoisting
-
代码压缩,在production模式中会自动压缩插件这个功能
-
-
css的优化
-
将css提取到独立的文件中,使用插件MiniCssExtractPlugin
//引入插件 const MiniCssExtractPlugin = require("mini-css-extract-plugin");//css插件 //创建插件 new MiniCssExtractPlugin() //修改CSS的loader rules: [ { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'] }, { test: /\.less$/, use: [MiniCssExtractPlugin.loader, "css-loader", "less-loader"] }, { test: /\.s(c|a)ss$/, use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"] } ]
-
自动给css添加前缀,使用 postcss-loader和autoprefixer
-
下载
cnpm install postcss-loader autoprefixer -D
-
在css-loader的前面添加postcss-loader
rules: [ { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader', "postcss-loader", 'less-loader'] }, { test: /\.less$/, use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"] }, { test: /\.s(c|a)ss$/, use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader", "sass-loader"] }, ]
-
开启css 的压缩
Optimize CSS Assets Webpack Plugin
使用此插件压缩在webpack.pro.js 中配置插件
//生产环境的配置 //配置全局的换变量 const { DefinePlugin } = require('webpack'); //1.导入merge const { merge } = require('webpack-merge'); const webpackBase = require('./webpack.base.js'); const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); //css 的压缩 const TerserPlugin = require("terser-webpack-plugin"); //js的压缩 //2.导入公共配置 //3合并配置并导出 module.exports = merge(webpackBase, { mode: "production", //开发环境 optimization: { minimize: true, minimizer: [new TerserPlugin(), new OptimizeCssAssetsPlugin({})], }, devtool: 'cheap-module-source-map'//开发环境使用的source map })
-
17.js的优化
-
代码分离
1.常用的代码分离方法有三
-
入口起点:使用
entry
配置手动地分离代码entry: { index: './src/main.js', //多入口文件 other: './src/other.js'//多入口文件 }, output: { //出口文件,是绝对路径,要是用node的path模块 path: path.resolve(__dirname, '..', './dist/'), filename: '[name].js', },
-
防止重复:使用
SplitChunksPlugin
去重和分离 chunk。//来移除重复模块。 在根目录下 optimization: { splitChunks: { chunks: 'all' } },
-
动态导入:通过模块中的内联函数调用来分离代码。
当涉及到动态代码拆分时,webpack 提供了两个类似的技术。第一种,也是推荐选择的方式是,使用符合 ECMAScript 提案 的
import()
语法 来实现动态导入。第二种,则是 webpack 的遗留功能,使用 webpack 特定的require.ensure
//1.下载babel npm install --save-dev @babel/plugin-syntax-dynamic-import //2.修改.babelrc的配置文件 { "presets": ["@babel/preset-env"], "plugins": [ "@babel/plugin-transform-classes", "@babel/plugin-transform-runtime", "@babel/plugin-syntax-dynamic-import" ] } //3.由于 import() 会返回一个 promise,因此它可以和 async 函数一起使用 //动态导入lodash async function getComponent() { var element = document.createElement('div'); const { default: _ } = await import('lodash'); element.innerHTML = _.join(['Hello', 'webpack'], ' '); return element; } getComponent().then(component => { document.body.appendChild(component); });
-
splitChunks
的相关配置module.exports = { //... optimization: { splitChunks: { chunks: 'async', //默认是async ,其他的值'all'和 'initial' minSize: 30000, //超过30000的大小就分包 maxSize: 0, minChunks: 1, //模块最小应用1次就分包 maxAsyncRequests: 5,//异步发送的请求不能超过5过 maxInitialRequests: 3, //页面初始化是发送的请求不能超过3个 automaticNameDelimiter: '~',//默认的连接符 name: true, //拆分的chunk的名字 cacheGroups: { //缓存组配置,上面的配置读完后进行拆分, vendors: { //定义组名 test: /[\\/]node_modules[\\/]/, priority: -10 }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true } } } } };
-
提高构建的性能优化
-
在module中配置noParse,排除第三方模块,提高打包速度
module: { noParse:/jquery/,//使用正则 rules: [ { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'less-loader'] }, ] }
-
尽可能的少引入loader
-
使用
IgnorePlugin
在使用地方模块,例如moment这个模块时,包含多个国家的语言,如果只需要中文,可以忽略掉其他的语言,从而提高效率
//通过观察moment.js 发现加载语言的函数是 function loadLocale(name) { var oldLocale = null, aliasedRequire; // TODO: Find a better way to register and load all the locales in Node if ( locales[name] === undefined && typeof module !== 'undefined' && module && module.exports && isLocaleNameSane(name) ) { try { oldLocale = globalLocale._abbr; aliasedRequire = require; aliasedRequire('./locale/' + name); //引入不同的语言包 getSetGlobalLocale(oldLocale); } catch (e) { // mark as not found to avoid repeating expensive file require call causing high CPU // when trying to find en-US, en_US, en-us for every format call locales[name] = null; // null means not found } } return locales[name]; }
调用webpack的内置插件IgnorePlugin
new IgnorePlugin(/\.\/locale/, /moment/)
手动导入需要的语言插件包
import moment from 'moment' //引入语言包 import 'moment/locale/zh-cn' //设置语言包 moment.locale('zh-CH')
-
DllPlugin
的使用在使用地方的一些框架时,例如:react,vue,angular的框架时,这框架一个不会被修改,但是每次打包都要去解析他们,这样会影响打包速 度, 借助dllplugin可以提高打包的速度,将这个框架和自已的业务逻辑代码分开,动态链接需要用到两个插件
-
`DLLPlugi
这个插件会生成一个名为
manifest.json
的文件 -
使用vue 框架来演示
//安装vue 和 vue-router npm install vue vue-router
生成一个webpack.vue.js的配置文件
//这配置文件是用来打包vue全家桶的webpack配置 const path = require('path') const webpack = require('webpack') module.exports = { //入口 mode: "development", //开发环境 entry: { vue: [ 'vue/dist/vue.js', 'vue-router' ] }, //出口 output: { path: path.resolve(__dirname, '../dist'), filename: '[name]_dll.js', library: '[name]_dll' }, //使用DLLPlugi配置打包后的文件的路径和文件名 plugins: [ new webpack.DllPlugin({ name: '[name]_dll', path: path.join(__dirname, '../dist/manifest.json'), }) ], }
在webpack.json中配置一个vue文件的打包路径
"build:vue":"webpack --config ./build/webpack.vue.js",
运行
npm run build:vue
就能生成一个vue_dll.js的文件和一个manifest.json的文件 -
使用
DllReferencePlugi
这个插件在webpack.base.js中进行配置关联new DllReferencePlugin({ manifest: path.resolve(__dirname, '../dist/manifest.json') })
-
使用插件 AddAssetHtmlPlugin将生成的vue_dll.js 添加到index.html中
//引入插件 npm i add-asset-html-webpack-plugin -D //在webpack.base.js中配置插件 plugins: [ new AddAssetHtmlPlugin({ filepath: path.resolve(__dirname, '../dist/vue_dll.js') }), ],
-
-
合理利用浏览器的缓存提高访问速,主要方式就是改变output的filename的名字
output: { //出口文件,是绝对路径,要是用node的path模块 path: path.resolve(__dirname, '..', './dist/'), filename: '[name].[contenthash].js', //[contenthash]每次输出的js内容修改了就会有一个新的名字。 },
-
打包分析
bundle analysis
- 通过
--profile --json > stats.json
指定一个目录存放生成的stats.json文件, - 将stats.json 放在指定的工具中分析就可以了
- 官网指定的工具有:
- webpack-chart:webpack stats 可交互饼图。
- webpack-visualizer:可视化并分析你的 bundle,检查哪些模块占用空间,哪些可能是重复使用的。
- webpack-bundle-analyzer:一个 plugin 和 CLI 工具,它将 bundle 内容展示为便捷的、交互式、可缩放的树状图形式。这个工具需要赶在插件才可以使用
- webpack bundle optimize helper:此工具会分析你的 bundle,并为你提供可操作的改进措施建议,以减少 bundle 体积大小
- 通过
-
网页的覆盖率和动态导入的首屏加载的优化
-
查看网页的覆盖率,优化代码,
-
动态导入的第三方库,可以是使用魔法注入提高加载速度。
import(/* webpackPreload: true */ 'ChartingLibrary');
-
-
-
-