webpack4学习笔记

389 阅读16分钟

该学习笔记根据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') // 打包后的路径,路径必须是绝对路径
    }
}

结果:

image-20201207230544987

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、 测试

image-20201207235550267

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、编写配置

  1. css-loader解析@import这种语法
  2. style-loader功能是把css插入index.html的head标签中
  3. loader用法:在use中配置字符串时,是只用一个loader
  4. 多个loader需要配置数组 []
  5. loader的解析顺序是从有到左,从下到上执行
  6. 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、测试

image-20201208220522306

6、添加less解析

  1. 安装:npm install less less-loader --save-dev
  1. 编写less文件及引用
// index.less
body{
    div{
        border: 1px solid #dadada;
    }
}
  1. 编写配置
// webpack.config.js
module.exports = {
    module: {
        rules: [
           
            { 
                test: /\.less$/,
                use: [
                    {
                        loader: 'style-loader',
                       
                    },
                    "css-loader", // 解析 @import 
                    "less-loader" // 把less 转换成css
                ]
            }
        ]
    }
}
  1. 测试

image-20201208223523706

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、测试

image-20201208235424720

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、测试

image-20201213210725719

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、测试

image-20201213211519355

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

image-20201215224905846

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

image-20201215225955812

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
  }
}

image-20201215231017127

3、编写配置文件

module: {
    rules: [
        {
            test: /\.js$/,
            use: {
                loader: "eslint-loader",
                options: {
                    enforce: "pre" // pre 前置执行,post 后置执行
                }
            },
            exclude:/node_modules/
        },
    ]
}

4、测试:npx webpack,在运行后如果提示哪个依赖没有安装,就安装哪个依赖

image-20201215235420316

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.$)

image-20201216225223659

3.10.2 ProvidePlugin

在每个模块中都引入 $

1、编写配置文件

// webpack.config.js
plugins: [    
    new webpack.ProvidePlugin({ // 在每个模块中都引入
        $: "jquery"
    })
],

2、测试

console.log($)

image-20201216225852484

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

image-20201216230735967

  • 配置了 externals

image-20201216230652027

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

image-20201229164115111

image-20201229164130349

image-20201229164143157

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、测试

image-20210112174922750

3.16.3 bannerPlugin 版权插件

1、安装依赖:改插件是 webpack自带插件,不需要单独安装

2、添加配置

let webpack = require('webpack')
plugins: [ // 数组,存放所有的webpack插件
    new webpack.BannerPlugin("make 2021 by jinshw")
]

3、测试

image-20210112175444410

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、测试

image-20210113174849880

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、测试

image-20210113175511041

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

image-20210113181952925

在浏览器上直接访问接口地址:http://localhost:3000/user

image-20210113182016950

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、测试

image-20210114110257616

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:[]

image-20210114110811262

2、测试

image-20210114110257616

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、测试

image-20210114112037596

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、测试

image-20210114120342079

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
# 结果未压缩

image-20210114130949066

npm run build:prod
# 结果已经压缩

image-20210114131021664

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

image-20210114143615011

设置了 noParse

image-20210114143748077

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

image-20210114145703786

没有配置IgnorePlugin,可以在js中引入

// 设置语言
// moment.locale('zh-cn')
// 手动引入所需语言
import 'moment/locale/zh-cn'

image-20210114150007807

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

image-20210114165112625

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

image-20210114165551868

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个线程

image-20210114171136724

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

image-20210115103335153

2、scope hosting 作用域提升,必须是在(production

// test.js
let a = 1;
let b = 2;
let c = 3;
console.log(a+b+c,"-------------------------")

image-20210115104104485

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

image-20210115110918145

image-20210115110941773

image-20210115110954718

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

image-20210115112311696

image-20210115112404827

image-20210115112413062

image-20210115112423164

image-20210115112433584

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、测试

image-20210118103551186

image-20210118103751511

3.24 热更新

需求:现阶段修改代码后,页面全部刷新;现在需要局部更新,在更改代码后,不要页面刷新,只是局部更新。

1、编写代码

// source.js
export default "chtgeo1"

2、添加配置

// webpack.config.js
devServer:{
  hot:true,  
},
plugins: [ 
    new webpack.NamedModulesPlugin(), // 打印更新的模块路径
    new webpack.HotModuleReplacementPlugin(), // 热更新插件
]

3、测试

image-20210118114245541