该学习笔记根据B站上的教程整理,教程地址:www.bilibili.com/video/BV1a4…
一、简介
依赖版本:
"devDependencies": {
"html-webpack-plugin": "^3.2.0",
"webpack": "4.43.0",
"webpack-cli": "3.3.12",
"webpack-dev-server": "3.11.0"
}
1.1 引言
webpack是一个现代的静态模块打包器(module bundler)。当webpack处理应用程序时,她会递归构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后打包成一个或多个bundle
1.2 核心概念
1.2.1 入口(entry)
入口的起点指示webpack应用使用哪些模块,作为构建其内部的依赖关系图的开始。进入起点入口后,webpack会找出有哪些模块和库是入口起点(直接和间接)依赖。
可以通过webpack配置中的entry属性,来指定一个入口的起点(或者多个入口)。默认入口文件为
./src
//webapck.config.js
module.exports = {
entry:'./src/main.js'
}
1.2.2 输出(output)
output
属性告诉webpack在哪里输出构建的bunldes
,以及如何命名这些文件,默认路径为./dist
。基本上整个应用结构都会被编译输出路径的文件夹中。
let path = require('path');
module.exports = {
mode: "development", // 模式 默认两种 production development
entry: './src/index.js', // 入口
output: {
filename: "bundle.js", // 打包后的名称
path: path.resolve(__dirname,'dist') // 打包后的路径,路径必须是绝对路径
}
}
1.2.3 加载器(loader)
loader是能让webpack处理那些非JavaScript的文件(webpack自身只能处理JavaScript)。loader能够把所有类型的文件处理转化成webpack能够处理的的有效模块。然后就能利用webpack的打包能力,对他们进行处理。
本质上webpack loader将所有类型的文件,转换为应用程序的依赖图可以直接引用的模块。
注意:loader能够
import
导入任何类型的模块(例如css文件),这是webpack特有的功能,其他打包程序或任务执行器可能不支持。
1.2.4 插件(plugin)
二、安装环境
yarn add webpack webpack-cli -D
或者
npm install webpack webpack-cli --save-dev
三、环境配置
3.1 基本环境配置
webpack自身可以打包js文件,这里基本配置打包js,并且输出
let path = require('path');
module.exports = {
mode: "development", // 模式 默认两种 production development
entry: './src/index.js', // 入口
output: {
filename: "bundle.js", // 打包后的名称
path: path.resolve(__dirname,'dist') // 打包后的路径,路径必须是绝对路径
}
}
结果:
3.2 配置开发服务
在开发环境(development)时,需要在浏览器中访问页面,webpack提供了webpack-dev-server开发库(内置了express服务),在这个服务启动的时,会在内存中生成打包文件。
1、安装库文件
yarn add webpack-dev-server@3.11.0 -D
2、添加配置
// webpack.config.js
module.exports = {
devServer:{
port: 3000,
progress: true,
contentBase: './dist',
compress: true
}
}
3、运行
// 在package.json 中配置
"dev": "webpack-dev-server"
----------------------------------
npm run dev
4、测试
3.3 打包HTML
1、安装库文件
yarn add html-webpack-plugin@3.2.0 -D
2、添加配置
let HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
plugins: [ // 数组,存放所有的webpack插件
new HtmlWebpackPlugin({
template: "./src/index.html",
filename: "index.html"
})
]
}
3、运行
npm run dev
4、 测试
3.4 样式处理(style)
1、引言
webpack默认只能解析js文件,css文件不能解析,则需要css-loader进行解析,并且用style-loader把css文件内容插入到index.html的head标签中
2、安装loader
npm install css-loader style-loader --save-dev
# 或者
yarn add css-loader style-loader -D
3、添加css文件及引用
/* src/base.css */
body{
color: yellow;
}
---------------------------
/* src/index.css */
@import './base.css';
body{
background: red;
}
// index.js
require("./index.css")
4、编写配置
- css-loader解析@import这种语法
- style-loader功能是把css插入index.html的head标签中
- loader用法:在use中配置字符串时,是只用一个loader
- 多个loader需要配置数组
[]
- loader的解析顺序是从有到左,从下到上执行
- loader还可以写成对象形式
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: 'style-loader',
options: {
// 设置style插入的位置
insert: function(element){
var parent = document.querySelector('head');
var lastInsertedElement
= window._lastElementInsertedByStyleLoader;
if (!lastInsertedElement) {
parent.insertBefore(element, parent.firstChild);
} else if (lastInsertedElement.nextSibling) {
parent.insertBefore(element, lastInsertedElement.nextSibling)
} else {
parent.appendChild(element)
}
}
}
},
"css-loader"
]
}
]
}
}
5、测试
6、添加less解析
- 安装:npm install less less-loader --save-dev
- 编写less文件及引用
// index.less
body{
div{
border: 1px solid #dadada;
}
}
- 编写配置
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.less$/,
use: [
{
loader: 'style-loader',
},
"css-loader", // 解析 @import
"less-loader" // 把less 转换成css
]
}
]
}
}
- 测试
3.5 样式处理(link)
问题:之前使用css-loader和style-loader处理css文件时,是把css内容插入到HTML文件head标签中。如果想使用
<link>
标签引入到HTML中,怎么办?答案:使用
mini-css-extract-plugin
抽离css插件
1、安装插件
npm install mini-css-extract-plugin --save-dev
2、编写配置
// 引入
let MiniCssExtractPlugin = require("mini-css-extract-plugin")
plugins: [
new MiniCssExtractPlugin({// 配置插件
filename: "main.css",
})
],
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,// 把之前style-loader替换成抽离插件的loader
"css-loader"
]
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,// 把之前style-loader替换成抽离插件的loader
"css-loader", // 解析 @import
"less-loader" // 把less 转换成css
]
}
]
}
3、测试
3.6 样式处理(添加前缀)
1、安装插件
npm install postcss-loader autoprefixer --save-dev
2、添加样式
/* index.css */
body{
transform: rotate(45deg);
}
3、编写配置
// 在webpack.config.js 中添加postcss-loader
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader"
]
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader", // 解析 @import
"postcss-loader",
"less-loader"
]
}
]
}
// 在package.json中添加浏览器支持,不然打包后的css中样式也不会添加前缀的
"browserslist": [
"defaults",
"not ie <= 8",
"last 2 versions",
"> 1%",
"iOS >= 7",
"Android >= 4.0"
]
4、测试
npm run build
/* 打包后main.css中的结果*/
body{
color: yellow;
}
body{
background: red;
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
body div {
border: 1px solid #dadada;
}
3.7 样式处理(压缩)
1、安装插件
npm install css-minimizer-webpack-plugin --save-dev
2、编写配置
// webpack.config.js
mode: "production"// 修改为生产模式
// 设置优化项
let CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
optimization: { // 优化
minimizer:[
new CssMinimizerPlugin()
]
}
3、测试
3.8 转化ES6语法
3.8.1 箭头函数
1、安装依赖
npm install babel-loader @babel/core @babel/preset-env --save-dev
2、编写函数
let fn = () => {
console.log("fn....")
}
fn();
3、编写配置文件
module: {
rules: [
{
test: /\.js$/,
use: {
loader:"babel-loader",
options:{
presets:[
'@babel/preset-env'
],
plugins:[
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }]
]
}
}
}
]
}
4、测试
3.8.2 类转化
1、安装依赖
npm install @babel/plugin-proposal-class-properties --save-dev
2、编写类文件
class Person{
name = "John"
}
let p = new Person()
console.log(p.name)
3、编写配置文件
module: {
rules: [
{
test: /\.js$/,
use: {
loader:"babel-loader",
options:{
presets:[
'@babel/preset-env'
],
plugins:[
"@babel/plugin-proposal-class-properties"
]
}
}
}
]
}
4、测试
3.8.3 装饰类转化
1、安装依赖
npm install @babel/plugin-proposal-decorators --save-dev
2、编写装饰类文件
@log
class Person{
name = "John"
}
let p = new Person()
console.log(p.name)
function log(target){
console.log(target)
}
3、编写配置文件
module: {
rules: [
{
test: /\.js$/,
use: {
loader:"babel-loader",
options:{
presets:[
'@babel/preset-env'
],
plugins:[
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }]
]
}
}
}
]
}
4、测试
3.9 处理JS语法及校验
3.9.1 处理ES6语法
1、安装依赖
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
2、编写测试文件
// a.js 并且在index.js中引用:require("./a.js")
module.exports = Beans
class Beans{
}
function * gen(params){
yield 1;
}
console.log(gen().next())
3、编写配置文件
module: {
rules: [
{
test: /\.js$/,
use: {
loader:"babel-loader",
options:{
presets:[
'@babel/preset-env'
],
plugins:[
"@babel/plugin-transform-runtime"
]
}
},
include:path.join(__dirname,'src'),
exclude:/node_modules/
},
]
}
4、测试:npx webpack
3.9.2 处理includes语法
1、安装依赖
npm install @babel/polyfill --save
2、编写测试文件
// a.js中添加includes测试语句
"aaa".includes('a')
3、编写配置文件
// a.js 中引用
require('@babel/polyfill')
4、测试:执行 npm webpack
3.9.3 JS语法校验
1、安装依赖
npm install eslint eslint-loader --save-dev
2、下载eslint配置文件,并且把配置文件放到项目根目录下(下载文件地址:eslint.org/demo),注意下载文…
.
,最终名称.eslintrc.json
。也可以自己在项目根目录下配置.eslintrc.js
文件
// .eslintrc.js
// http://eslint.org/docs/user-guide/configuring
module.exports = {
//此项是用来告诉eslint找当前配置文件不能往父级查找
root: true,
//此项是用来指定eslint解析器的,解析器必须符合规则,babel-eslint解析器是对babel解析器的包装使其与ESLint解析
parser: 'babel-eslint',
//此项是用来指定javaScript语言类型和风格,sourceType用来指定js导入的方式,默认是script,此处设置为module,指某块导入方式
parserOptions: {
sourceType: 'module'
},
//此项指定环境的全局变量,下面的配置指定为浏览器环境
env: {
browser: true,
},
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
// 此项是用来配置标准的js风格,就是说写代码的时候要规范的写,如果你使用vs-code我觉得应该可以避免出错
extends: 'standard',
// required to lint *.vue files
// 此项是用来提供插件的,插件名称省略了eslint-plugin-,下面这个配置是用来规范html的
plugins: [
'html'
],
// add your custom rules here
// 下面这些rules是用来设置从插件来的规范代码的规则,使用必须去掉前缀eslint-plugin-
// 主要有如下的设置规则,可以设置字符串也可以设置数字,两者效果一致
// "off" -> 0 关闭规则
// "warn" -> 1 开启警告规则
//"error" -> 2 开启错误规则
// 了解了上面这些,下面这些代码相信也看的明白了
'rules': {
// allow paren-less arrow functions
'arrow-parens': 0,
// allow async-await
'generator-star-spacing': 0,
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
}
}
3、编写配置文件
module: {
rules: [
{
test: /\.js$/,
use: {
loader: "eslint-loader",
options: {
enforce: "pre" // pre 前置执行,post 后置执行
}
},
exclude:/node_modules/
},
]
}
4、测试:npx webpack,在运行后如果提示哪个依赖没有安装,就安装哪个依赖
3.10 全局变量引入问题
拿jQuery举例,正常如下方式使用:
npm install jquery --save-dev
// 在js模块中这样引用
import $ from 'jquery'
3.10.1 暴露到全局window上
1、安装依赖
npm install expose-loader --save-dev
2、配置文件
// 全局暴露
//import $ from "expose-loader?exposes[]=$&exposes[]=jQuery!jquery";
// webpack.config.js
rules: [
{
test: require.resolve("jquery"),
loader: "expose-loader",
options: {
exposes: ["$", "jQuery"],
},
},
]
3、测试
console.log(window.$)
3.10.2 ProvidePlugin
在每个模块中都引入
$
1、编写配置文件
// webpack.config.js
plugins: [
new webpack.ProvidePlugin({ // 在每个模块中都引入
$: "jquery"
})
],
2、测试
console.log($)
3.10.3 引入打包
1、在index.html中引入jQuery的cdn路径
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
2、编写配置文件
// webpack.config.js
externals: {
jquery: "jQuery"
},
3、测试
- 在没有配置
externals
- 配置了
externals
3.11 图片处理
3.11.1 在JS中创建图片来引入
1、安装依赖
cnpm install file-loader --save-dev
2、添加配置
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: "file-loader" // 正常习惯应该使用 url-loader处理图片,在后面再讲改为url-loader
}
]
}
3、在JS中创建图片
import logo from './logo.png'
let image = new Image();
image.src = logo;
document.body.appendChild(image);
4、测试
3.11.2 在CSS引入图片
1、安装依赖
cnpm install css-loader --save-dev
注意:
css-loader
会把css文件中的 url("./logo.png") 变为url(require("./logo.png"))
2、添加配置
module: {
rules: [
{
test: /\.css$/,
use: "css-loader"
}
]
}
3、编写css代码
body{
background: url("./logo.png")
}
4、测试
3.11.3 在HTML中引入图片
1、安装依赖
cnpm install html-withimg-loader --save-dev
2、添加配置
module: {
rules: [
{
test: /\.html$/,
use: "html-withimg-loader"
},
{
test: /\.(png|jpg|gif)$/,
use:[{
loader:'file-loader',
options:{
esModule:false //解决html-webpack-plugin 发生了冲突
}
}]
}
]
}
注意:
html-withimg-loader和file-loader 版本是 5.* 之上的版本冲突,不能打包,解决方法是:esModule:false
3、编写代码
<!--在index.html中添加代码-->
<img src="./logo.png" />
4、测试
3.11.4 把图片打包成base64
1、安装依赖
cnpm install url-loader -save-dev
2、添加配置
module: {
rules: [
{
test: /\.html$/,
use: "html-withimg-loader"
},
{
test: /\.(png|jpg|gif)$/,
use:[{
loader:'url-loader', // url-loader中集成了file-loader
options:{
limit: 10 * 1024, // 设置阀值,在这个限制下图片转化为base64,否则使用file-loader
esModule:false //解决html-webpack-plugin 发生了冲突
}
}]
}
]
}
3、编写代码
<img src="./logo.png">
4、测试
3.12 打包文件分类
1、图片打包指定路径
module: {
rules: [
{
test: /\.html$/,
use: "html-withimg-loader"
},
{
test: /\.(png|jpg|gif)$/,
use:[{
loader:'url-loader', // url-loader中集成了file-loader
options:{
limit: 10 * 1024, // 设置阀值,在这个限制下图片转化为base64,否则使用file-loader
esModule:false, //解决html-webpack-plugin 发生了冲突
outputPath: "/img/" //把图片打包到这个路径下
}
}]
}
]
}
2、CSS样式打包到指定路径下
new MiniCssExtractPlugin({
filename: "css/main.css",
})
3、在全局的CSS和图片路径前添加访问域名
output: {
publicPath: 'http://www.chtgeo.com' // 全局公共路径
},
4、在CSS或图片等类型文件单独的添加路径
{
test: /\.(png|jpg|gif)$/,
use:[{
loader:'url-loader',
options:{
limit: 1,
esModule:false,
outputPath: "/img/",
publicPath: 'http://www.chtgeo.com' // 给图片类型添加公共域名路径
}
}]
}
3.13 打包多页应用
1、创建新工程,新建2个JS文件,一个index.html模板文件
//1. 新建webpack-dev-2文件夹
// 新建src/index.js
console.log("this is index")
// 新建src/other.js
console.log("this is other")
2、初始化工程,添加webpack环境
# 初始化工程
npm init -y
# 安装webpack依赖
cnpm install webpack webpack-cli --save-dev
# 安装html-webpack-plugin
cnpm install html-webpack-plugin --save-dev
3、编写配置文件
// webpack.config.js
let path = require('path');
let HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports={
mode:"development",
entry:{
home: "./src/index.js",
other:"./src/other.js"
},
output: {
filename: "[name].js",
path: path.resolve(__dirname,"dist")
},
plugins:[
new HtmlWebpackPlugin({
template: "./index.html",
filename: "home.html",
chunks: ["home"]
}),
new HtmlWebpackPlugin({
template: "./index.html",
filename: "other.html",
chunks: ["other"]
})
]
}
4、测试
npx webpack
3.14 配置source-map
1、源码映射,会单独生成一个sourceMap文件 出错了 会标识当前报错地方的列和行。(大而全)
devtool:'source-map'
2、不会产生单独的文件,但是可以显示行和列
devtool:'eval-source-map'
3、不会产生列,但是会产生单独的映射文件,产生后的文件可以保留起来
devtool:'cheap-module-source-map'
4、不会产生文件,集成在打包后的文件中,不会产生列
devtool:"cheap-module-eval-source-map"
3.15 watch的用法
webpack 可以监听文件变化,当它们修改后会重新编译。
1、打开监听
watch:true // 默认是false
2、可以配置
watchOptions
选项
watchOptions:{
poll: 1000, //指定毫秒为单位进行轮询
aggregateTimeout:500, //防抖,当第一个文件更改,会在重新构建前增加延迟
ignored:/node_modules/
}
3.16 webpack小插件的应用
3.16.1 cleanWebpackPlugin 清理删除插件
1、安装依赖
cnpm install clean-webpack-plugin --save-dev
2、添加配置
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
plugins: [ // 数组,存放所有的webpack插件
new CleanWebpackPlugin()
],
3、测试:清除
dist
文件夹下的文件
3.16.2 copyWebpackPlugin 拷贝静态文件
1、安装依赖:
注意:安装的版本是4.4.3,最新版本配置有变化
cnpm install copy-webpack-plugin@4.4.3 --save-dev
2、添加配置
const CopyWebpackPlugin = require('copy-webpack-plugin')
plugins: [ // 数组,存放所有的webpack插件
new CopyWebpackPlugin([
{ from: path.resolve(__dirname, "doc"),to: "./doc"}
])
]
3、测试
3.16.3 bannerPlugin 版权插件
1、安装依赖:改插件是
webpack
自带插件,不需要单独安装
2、添加配置
let webpack = require('webpack')
plugins: [ // 数组,存放所有的webpack插件
new webpack.BannerPlugin("make 2021 by jinshw")
]
3、测试
3.17 webpack跨域问题
3.17.1 第一种:代理
第一种情况,服务端不是自己开发的,前端需要请求服务端接口数据,前端自己需要代理
1、编写个服务端测试程序
// server.js
let express = require('express')
let app = express()
app.get("/user",(req,res) => {
res.json({name:"测试"})
})
app.listen(3000)
2、编写前端请求接口程序
// 前端请求
let xhr = new XMLHttpRequest();
xhr.open('GET',"/api/user",true)
xhr.onload =function(){
console.log(xhr.response)
}
xhr.send();
3、前端添加代理
// webpack.config.js
devServer:{
proxy:{ // 重写的方式,把请求代理到服务器上
"/api":{
target: "http://localhost:3000",
pathRewrite: { "/api":"" }
}
}
}
4、测试
3.17.2 第二种:前端需要模拟数据
第二种:前端只是想单独的模拟数据
1、编写前端请求接口程序
// 前端请求
let xhr = new XMLHttpRequest();
xhr.open('GET',"/user",true)
xhr.onload =function(){
console.log(xhr.response)
}
xhr.send();
2、添加配置
// webpack.config.js
devServer:{
before(app){
app.get("/user",(req,res) => {
res.json({name:"测试-before"})
})
}
}
3、测试
3.17.3 第三种:有服务端,不需要代理
第三种情况,有服务器,前端和服务器都是自己实现,想在服务器中启动webpack配置
1、安装依赖:
注意版本,最新版本4.x.x与下面配置不兼容
cnpm install webpack-dev-middleware@3.4.0 --save-dev
2、编写服务端代码,添加webpack配置
// server.js
let express = require('express')
let app = express()
let webpack = require('webpack')
// 中间件
let middleware = require('webpack-dev-middleware')
let config = require('./webpack.config.js')
let compiler = webpack(config);
app.use(middleware(compiler))
app.get("/user",(req,res) => {
res.json({name:"测试-3333"})
})
app.listen(3000)
3、测试
// 启动服务
node ./server.js
访问前端页面: http://localhost:3000
在浏览器上直接访问接口地址:http://localhost:3000/user
3.18 resolve属性的配置
3.18.1 设置别名
需求:有时候需要引入其他第三方库文件,例如:引入
bootstrap
库文件
1、安装依赖
cnpm install bootstrap --save
cnpm install popper.js -D # bootstrap 4.x.x版本的需要使用popper.js
2、编写测试代码
// 在index.js中引用
// 在不使用别名是,可以这样引用import "bootstrap/dist/css/bootstrap.css"
import "bootstrap" // 直接引用
<!--index.html-->
<div class="btn btn-danger">bootstrap-test</div>
3、添加配置
resolve:{// 解析 第三方包 common
modules: [path.resolve('node_modules')],
alias: {
bootstrap: "bootstrap/dist/css/bootstrap.css",
}
},
4、测试
3.18.2 主入口字段和文件
需求:上一步别名引入很长,这样不太方便,想直接找相应的css文件
1、添加配置
resolve:{// 解析 第三方包 common
modules: [path.resolve('node_modules')],
mainFields: ['style','main'] // 查找入口字段
// alias: { // 别名
// bootstrap: "bootstrap/dist/css/bootstrap.css",
// }
},
注意:
mainFields 字段是查找node_modules
下的库文件中的package.json中的字段,如下图,bootstrap中的字段。如果想设置入口文件的名称,可以配置
mainFiles:[]
2、测试
3.18.3 扩展名称设置
需求:在引入第三方文件时,不想写后缀名称,例如,有个style.css文件,在index.js中引入,
// 正常引入方式 import './style.css' // 现想写成 import './stype'
1、编写代码
body {
background-color: coral!important;
}
// index.js
import './style'
2、添加配置
resolve:{// 解析 第三方包 common
modules: [path.resolve('node_modules')],
extensions: ['.js','.css','.vue'] // 文件扩展名称
// mainFields: ['style','main'] // 查找入口字段
// alias: { // 别名
// bootstrap: "bootstrap/dist/css/bootstrap.css",
// }
},
3、测试
3.19 定义环境变量
需求:根据不同的环境(开发,成产)使用不同url
1、编写代码
let url= ""
if(DEV === 'dev'){
url = "http://localhost:3000"
}else{
url = "http://www.chtgeo.com"
}
console.log(url,",--------------------------------")
console.log(FLAG,typeof FLAG)
console.log("EXPRESSION==",EXPRESSION)
2、添加配置
注意:
webpack自带自定义插件,可以自定义变量;自定义变量后的值,插件会直接给转成变量,而不是字符串;如果想定义字符串,推荐用JSON.stringify("dev")
定义。
plugins:[
new webpack.DefinePlugin({
DEV: JSON.stringify('dev'), // console.log('dev')
FLAG: 'true', // console.log(true)
EXPRESSION: '1+1' // console.log(1+1)
}),
]
3、测试
3.20 区分不同环境
1、安装依赖
cnpm install webpack-merge --save-dev
2、编写配置文件
// webpack.base.js 公共配置
let path = require('path');
let HtmlWebpackPlugin = require("html-webpack-plugin")
let MiniCssExtractPlugin = require("mini-css-extract-plugin")
let CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const { loader } = require('mini-css-extract-plugin');
let webpack = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = {
optimization: {
minimizer:[
new CssMinimizerPlugin()
]
},
resolve:{// 解析 第三方包 common
modules: [path.resolve('node_modules')],
extensions: ['.js','.css','.vue'] // 文件扩展名称
},
devServer:{
port: 8080,
progress: true,
contentBase: './dist',
compress: true,
open: true,
},
// mode: "development", // 模式 默认两种 production development
entry: './src/index.js', // 入口
watch:true,
watchOptions:{
poll: 1000, //指定毫秒为单位进行轮询
aggregateTimeout:500, //防抖,当第一个文件更改,会在重新构建前增加延迟
ignored:/node_modules/
},
output: {
filename: "bundle.js", // 打包后的名称
path: path.resolve(__dirname,'dist'), // 打包后的路径,路径必须是绝对路径
// publicPath: 'http://www.chtgeo.com'
},
plugins: [ // 数组,存放所有的webpack插件
......
],
module: {
......
}
}
// webpack.prod.js 成产环境配置
let { merge } = require('webpack-merge')
let base = require('./webpack.base.js')
module.exports = merge(base,{
mode:'production',
})
// webpack.dev.js 测试环境配置
let { merge } = require('webpack-merge')
let base = require('./webpack.base.js')
module.exports = merge(base,{
mode: "development",
})
3、添加运行命令
"scripts": {
"build:dev": "webpack --config webpack.dev.js",
"build:prod": "webpack --config webpack.prod.js"
},
4、运行测试
npm run build:dev
# 结果未压缩
npm run build:prod
# 结果已经压缩
3.21 webpack优化
3.21.1 noParse
需求:有些时候,在使用第三方包,明确第三包中没有相关依赖,不需要解析第三方包;则配置
noParse
不解析,我们用jquery库做测试
1、安装依赖
cnpm install jquery --save
2、编写代码
// index.js
import $ from 'jquery'
3、添加配置
// webpack.config.js
module: {
noParse: /jquery/,
}
4、测试
未配置
noParse
设置了
noParse
3.21.2 IgnorePlugin
需求:在引入第三方包时,想忽略第三方包中的一些引用,例如:引用
moment
库,不想打包这个库中的语言包
1、安装依赖
cnpm install moment --save
2、编写程序
// index.js
import moment from 'moment'
moment.locale('zh-cn')
let r = moment().endOf('day').fromNow()
console.log(r)
3、添加配置
// webpack.config.js
plugins: [
new webpack.IgnorePlugin(/\.\/locale/,/moment/),
]
4、测试
配置了IgnorePlugin
没有配置IgnorePlugin,可以在js中引入
// 设置语言
// moment.locale('zh-cn')
// 手动引入所需语言
import 'moment/locale/zh-cn'
5、其他优化,exclude和include,如下:
{
test: /\.js$/,
use: {
loader:"babel-loader",
options:{
presets:[
'@babel/preset-env'
],
plugins:[
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }],
"@babel/plugin-transform-runtime"
]
}
},
include:path.join(__dirname,'src'),
exclude:/node_modules/
},
3.21.3 dllPlugin
需求:把第三方库文件,打包成动态库引入,例如:react
1、安装依赖
cnpm install @babel/preset-react --save-dev
cnpm install react react-dom --save-dev
2、编写代码
<!--index.html-->
<div id="root"></div>
// index.js
import React from 'react';
import { render } from 'react-dom';
render(<h1>jsx</h1>,window.root)
3、添加配置
a. 添加react依赖配置
// webpack.config.js
{
test: /\.js$/,
use: {
loader:"babel-loader",
options:{
presets:[
'@babel/preset-env',
'@babel/preset-react'
]
}
}
},
b. 编写
webpack.react.js
文件
// webpack.react.js
let path = require('path')
let webpack = require('webpack')
module.exports = {
mode: 'development',
entry:{
react:['react','react-dom']
},
output:{
filename:'_dll_[name].js',
path:path.join(__dirname,'dist'),
library:'_dll_[name]',
// libraryTarget:'var' // commonjs var this ...
},
plugins:[
new webpack.DllPlugin({
name:"_dll_[name]",
path:path.join(__dirname,'dist','manifest.json'),
})
]
}
c. 运行生成动态库文件
npx webpack --config webpack.react.js
d. 在主配置文件
webpack.config.js
中添加配置
plugins: [
new webpack.DllReferencePlugin({
manifest:path.join(__dirname, 'dist','manifest.json'),
})
]
e. 在
index.html
中引入动态库js文件
<script src="/_dll_react.js"></script>
4、测试
# 确保已经执行 npx webpack --config webpack.react.js,已经生成动态库文件了
npm run dev
3.21.4 happypack
需求:在工程非常大的时候,打包非常慢,这时可以考虑多线程打包,引用
happypack
插件
1、安装依赖
cnpm install happypack --save-dev
2、添加配置
const Happypack = require('happypack')
module: {
rules: [
{
test: /\.js$/,
use: 'Happypack/loader?id=js',
include:path.join(__dirname,'src'),
exclude:/node_modules/
},
]
}
// 插件Happypack--id 需要与rules中配置的id一致(use: 'Happypack/loader?id=js')
plugins: [
new Happypack({
id:"js",
use: [
{
loader:"babel-loader",
options:{
presets:[
'@babel/preset-env',
'@babel/preset-react'
],
plugins:[
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }],
"@babel/plugin-transform-runtime"
]
}
}
]
}),
]
3、测试:默认是开启3个线程
3.21.5 webpack自带优化
1、
tree-shaking
把没有用到的代码自动删除掉,注意:只能是生成环境(production
)使用import xxx from 'xxx'
方式引用才有效果;let xxx require('xxx')
没有效果
// test.js
let sum = (a,b) => {
return a + b + "sum";
}
let minus = (a,b) => {
return a - b + "minus";
}
export default {sum,minus}
// index.js
import {sum,minus} from './test.js';
console.log(calc.sum(1,2))
// 如果webpack.config.js文件中配置了minimizer,需要使用terser-webpack-plugin插件,不然tree-shaking不生效
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
optimization: {
minimizer:[
new CssMinimizerPlugin(),
new TerserPlugin()
]
},
}
注意:在安装terser-webpack-plugin库时,注意版本与webpack的大版本一致,这里webpack的大版本是4,那么terser-webpack-plugin的版本也需要是4.x.x,不然不兼容
cnpm install terser-webpack-plugin@4.2.3 --save-dev
2、
scope hosting
作用域提升,必须是在(production
)
// test.js
let a = 1;
let b = 2;
let c = 3;
console.log(a+b+c,"-------------------------")
3.22 webpack多页面抽离公共代码
需求:在多页面应用时,多个页面中可能引用公共的代码,或者公共的第三方库文件,这样可以把公共代码或第三方库文件抽离个公共文件,其他页面引用这个公共页面。
3.22.1 抽离公共代码
1、编写代码
//aa.js
console.log("aa......")
//bb.js
console.log("bb......")
// index.js
import './aa'
import './bb'
console.log("other......")
2、添加配置
// webpack.config.js 多页面配置修改
entry: {// 入口
index:'./src/index.js',
other:'./src/other.js'
},
output: {// 出口
filename: "[name].js", // 打包后的名称
path: path.resolve(__dirname,'dist'), // 打包后的路径,路径必须是绝对路径
},
// webpack.config.js添加抽离公共代码配置
optimization: {
splitChunks:{ // 分割代码块
cacheGroups:{ // 缓存组
common:{ // 公共模块
chunks:'initial',
minSize:0, // 公共代码大于等于minSize字节时,抽离公共代码
minChunks:2 // 公共代码被引用次数大于等于minChunks时,被抽离
}
}
}
}
3、测试
npm run build
3.22.2 抽离第三方代码
1、编写代码
// index.js添加
import $ from 'jquery'
console.log($)
// other.js添加
import $ from 'jquery'
console.log($)
2、添加配置
// webpack.config.js 中添加vendor配置
optimization: {
splitChunks:{ // 分割代码块
cacheGroups:{ // 缓存组
common:{ // 公共模块
chunks:'initial',
minSize:0, // 公共代码大于等于minSize字节时,抽离公共代码
minChunks:2 // 公共代码被引用次数大于等于minChunks时,被抽离
},
vendor:{
priority:1,// 权重必须配置,不然先抽离common,不能抽离vendor
test:/node_modules/, // 把它抽离出来
chunks:'initial',
minSize:0, // 公共代码大于等于minSize字节时,抽离公共代码
minChunks:2 // 公共代码被引用次数大于等于minChunks时,被抽离
}
}
}
}
3、测试
npm run build
3.23 懒加载
需求:在代码运行时,点击按钮在加载js程序。例如:点击一个按钮,在加载
source.js
文件
1、编写代码
// index.js
// 懒加载
let button = document.createElement('button');
button.innerHTML = "懒加载"
button.addEventListener('click',function(){
// es6中草案中的语法,jsonp实现动态加载文件
import('./source.js').then(data => {
console.log(data.default);
})
})
document.body.appendChild(button);
// source.js
export default "chtgeo1"
2、测试
3.24 热更新
需求:现阶段修改代码后,页面全部刷新;现在需要局部更新,在更改代码后,不要页面刷新,只是局部更新。
1、编写代码
// source.js
export default "chtgeo1"
2、添加配置
// webpack.config.js
devServer:{
hot:true,
},
plugins: [
new webpack.NamedModulesPlugin(), // 打印更新的模块路径
new webpack.HotModuleReplacementPlugin(), // 热更新插件
]
3、测试