9.webpack常用转换器(loader)与插件(plugin)

韩烈
2023-12-01

目录


1. Vue环境搭建(Node)

2. npm与yarn详细使用

3. Vue介绍及其基本使用

4. Vue指令(Directives)

5. Vue修饰符(Modifier)

6. Vue计算属性(computed)和侦听器(watch)

7. webpack(module bundler,模块打包器)

8. webpack基本使用

9. webpack常用转换器(loader)与插件(plugin)

10. Vue实例

11. 模块管理规范(ES6、CommonsJs、AMD、CMD)



webpack的loader(装载机)

webpack主要用来处理js代码,并且webpack会自动处理js之间相关的依赖。单在实际开发中不仅仅有基本的js代码,也需要加载css、图片,也包括一些高级的将ES6转成ES5代码,将TypeScript转成ES5代码,将scss、less转成css,将.jsx、.vue文件转成js文件等

webpack默认打开包除了js文件以外的所有文件,需要装不同的文件类型都需要安装对应的loader才可以加载,否则会报错


loader使用过程(★)

(1)通过npm安装需要使用的loader
(2)在webpack.config.js中的modules关键字下进行配置

module: {
    rules: [{
            test: /.css$/,
            use: [{
                    loader: "style-loader"
                },
                {
                    loader: "css-loader"
                }
            ]
        },
        {
            test: /.less$/,
            use: [{
                    loader: "style-loader"
                },
                {
                    loader: "css-loader"
                },
                {
                    loader: "less-loader"
                }
            ]
        },
        {
            test: /.scss$/,
            use: [{
                    loader: "style-loader"
                },
                {
                    loader: "css-loader"
                },
                {
                    loader: "sass-loader"
                }
            ]
        },
        {
            test: /.(png|jpg|gif|bmp|webp)$/,
            use: [{
                loader: 'url-loader?limit=14240&name=[hash:8]-[name].[ext]',
            }]
        },
        {
            test: /.(eot|ttf|woff|woff2|svg)$/,
            use: 'url-loader',
        },
        {
            test: /.js$/,
            exclude: /(node_modules|bower_components)/,
            use: {
                loader: 'babel-loader',
            }
        },
        {
            test: /.vue$/,
            use: {
                loader: 'vue-loader',
            }
        }
    ]
}

css-loader安装使用(css)

1.安装css-loader和style-loader

npm install css-loader style-loader --save-dev
cnpm install css-loader style-loader --save-dev
yarn add css-loader style-loader --save-dev(推荐)

如果没有安装yarn,详见:npm与yarn详细


2.创建css文件

在src/css目录中新建index.css

#first { 
	border: 1px solid red; 
}

3.在main.js(入口)中引入外部的css文件

请不要再html中引入css,避免二次http请求

效果:获取css目录中的index.css文件

// ES6的import语法可以导入js和css
import './css/index.css'
// CommonJS
require(./css/index.css)

4.需要在配置文件(webpack.config.js)中,进行配置

module下参数描述
rulesloader装载机使用规则
css-loader将模块导出的内容作为样式并添加到DOM中
style-loader加载CSS文件并解析import的CSS文件,最终返回CSS代码
注意:style-loader需要放在css-loader的前面。因为多个loader加载顺序是从右到左
// 首先要引入node.js中path模块,用于处理文件与目录的路径
const path = require('path');
// const命令声明一个只读的常量,一旦声明,值不可以改变,改变会报错;只声明不赋值也会报错;
// const常量存储的是一个不可以变化的变量

module.exports = {
	entry:'./src/./js/main.js', // 指定入口文件
	output:{
		path: path.resolve(__dirname, './dist/js'), // 指定出口文件的路径目录
		filename: 'bulid.js' // 制定出口文件的名称
	},
	module:{
		rules:[
			// 在webpack2中,loaders被替换成了rules,其实就是loader的规则
			{
				// “/\.css$/”:相当于一个正则表达式
				test: /\.css$/,
				// 多个loader的加载顺序是从右到左的
				use: [ 'style-loader', 'css-loader' ]
				// test 说明了当前loader能处理那些类型的文件
				// use 则指定了loader的类型
				// 注意:数组中的loader不能省略扩展名
			}
		]
	}
}

5.在终端中输入命令进行css文件打包

如果配置了scripts

npm run build
yarn run build

less-loader安装使用(less)

1.安装less和less-loader

将Less编译为CSS的loader

npm install less less-loader --save-dev
cnpm install less less-loader --save-dev
yarn add less less-loader --save-dev

2.编写less文件

index.less

@fontSize: 50px;
@fontColor : white;
#res {
    border:1px dashed blue;
}

3.在main.js(入口)中引入

// 获取less下index.less文件
import './less/index.less'

4.在配置文件(webpack.config.js)中,进行配置

module: {
	rules: [
		{
			test: /\.less$/,
			use: [
				{ loader: "style-loader" },
				{ loader: "css-loader" },
				{ loader: "less-loader" }
			]
		}
	]
},

注意:use下使用的是对象,即可额外传参


sass-loader安装使用(sass、scss)

加载Sass/SCSS文件并将它们编译为CSS


1.安装sass和sass-loader

npm install sass-loader sass --save-dev
cnpm install sass-loader sass --save-dev
yarn add sass-loader sass --save-dev

2.编写sass、scss文件

$body-color: red;

body {
  color: $body-color;
}

3.在main.js(入口)中引入外部的scss文件

import "./css/index.scss"

4.在配置文件(webpack.config.js)中,进行配置

module.exports = {
	module: {
		rules: [
			{
				test: /\.s[ac]ss$/i,
				use: [
					// 将js字符串生成为style节点
					"style-loader",
					// 将css转化成 CommonJS 模块
					"css-loader",
					// 将sass编译成css
					"sass-loader",
				],
			},
		],
	}
}

url-loader安装使用(图片、资源)

因为在css中使用图片或字体文件时会引入外部资源,而webpack进行打包时默认不支持这些外部资源的打包,所以需要借助 url-loader


1.安装url-loader

npm install url-loader --save-dev
cnpm install url-loader --save-dev
yarn add url-loader --save-dev

2.在img文件夹下放入图片,并css中使用

css/index.css

#bg {
    width: 200px;
    height: 200px;
    background: url('../imgs/bxg.jpg');
}

3.在main.js(入口)中引入jpeg图片

import img from './img/image.jpeg';
import './css/index.css'

4.在配置文件(webpack.config.js)中,进行配置

limit: 8192
限制图片的最大大小,如果超过了最大限制将会以原图片打包,如果小于限制则会通过base64进行转码

module.exports = {
	module: {
		rules: [
			{
				test: /\.(png|jpg|jpeg|gif)$/i,
				use: [
					{
						loader: 'url-loader',
						options: {
						    // limit默认无限制
						    // 当加载的图片,小于limit,图片将会被编译成base64字符串形式
							// 当加载的图片,大于limit时,需要使用file-loader模块进行加载(转码)
							limit: 8192,
							name: 'img/[name][hash:8].[ext]'
						}
					}
				]
			}
		]
	}
};

注意:在css中引入外部的图片或字体都需要用url-loader来加载,建议分开匹配,方便管理


file-loader安装使用(文件)

将文件上的/file-loader解析为url,然后将文件发送到输出目录

在实际开发中,可能对图片打包的名字有一定的要求。比如:将所有的图片放在一个文件夹中,根上图片原来的名称,同时也要防止重复,所以可以在options中添加占位符等

占位符描述
img文件打包到的文件夹
[name]获取文件原来的名称
[hash:8]防止图片名称冲突,8位hash值
[ext]图片原来的扩展名

占位符

占位符类型描述
[name]String文件/资源的基本名称。默认值:file.basename
[ext]String目标文件/资源的文件扩展名。默认值:file.extname
[path]String资源相对于webpack / config的路径context。默认值:file.directory
[folder]String资源的文件夹在。默认值:file.folder
[query]String资源查询,即?foo=bar。默认值:file.query
[emoji]String随机表情符号表示形式content。默认值:undefined
[emoji:<length>]String与[emoji]相同,但可自定义数量的表情符号。默认值:undefined
[hash]String指定用于对文件内容进行哈希处理的哈希方法。默认值:md4
[contenthash]String指定用于对文件内容进行哈希处理的哈希方法。默认值:md4
digestTypeString哈希函数应使用的摘要。有效值包括:base26,base32,base36,base49,base52,base58,base62,base64和hex。默认值:‘hex’
hashTypeStringhash函数应使用的哈希类型。有效值包括:md4,md5,sha1,sha256,和sha512。默认值:‘md4’
lengthNumber用户还可以为计算的哈希指定长度。默认值:undefined
[N]String通过将当前文件名与进行匹配而获得的第n个匹配项regExp。默认值:undefined

1.安装file-loader

npm install file-loader --save-dev
cnpm install file-loader --save-dev
yarn add file-loader --save-dev

2.在file下放入文件


3.在main.js(入口)中引入文件

import img from './file/file.png'

4.在配置文件(webpack.config.js)中,进行配置

module.exports = {
	module: {
		rules: [
			{
				test: /\.(png|jpe?g|gif)$/i,
				use: [
					{
						loader: 'file-loader'
					}
				]
			}
		]
	}
}

然后webpack通过首选方法运行。这将file.png作为输出目录中的文件发出(使用指定的命名约定,如果指定了这样做的选项),并返回文件的公共URI
默认情况下,结果文件的文件名是文件内容的哈希值,带有所需资源的原始扩展名


babel-loader安装使用(ES6转ES5)

在项目中如果用到了高级的ES6语法,例如class关键字,webpack默认无法进行打包,需要借助babel将高级语法转译为ES5语法之后再进行打包


1.安装balel/core、babel-loader和babel/preset-env

babel核心、babel-loader以及babel的插件

npm install -D babel-loader @babel/core @babel/preset-env
cnpm install -D babel-loader @babel/core @babel/preset-env
yarn add -D babel-loader @babel/core @babel/preset-env

-D相当于–save-dev


2.在配置文件(webpack.config.js)中,进行配置

方式一:此方式需要在src根目录下配置.babelrc文件

webpack.config.js

module: {
	rules: [
		{
			test: /\.m?js$/,
			// include:包含
			// exclude:排除
			exclude: /(node_modules|bower_components)/,
			use: {
				loader: 'babel-loader',
				options: {
					presets: ['@babel/preset-env']
				}
			}
		}
	]
}

src下配置.babelrc文件
配置babel,需要在项目根目录新建.babelrc文件

{
    "presets": [
        "es2015",
"env",
        "stage-0"
    ],
    "plugins": [
        "transform-runtime"
    ]
}

方式二:直接转为ES5

webpack.config.js

module: {
	rules: [
		{
			test: /\.m?js$/,
			exclude: /(node_modules|bower_components)/,
			use: {
				loader: 'babel-loader',
				options: {
					presets: ['es2015']
				}
			}
		}
	]
}

vue-loader安装使用(.vue文件书写代码)

Vue Loader是一个webpack的loader,它允许以一种名为单文件组件(SFCs)的格式撰写Vue组件

vue.runtime.js(runtime-only)代码中,不可以有任何的template
vue.runtime.esm.js(runtime + compiler)代码中,可以有template。由vue-template-compiler编译template

<template>
	<div class="example">{{ msg }}</div>
</template>

<script>
export default {
	data () {
		return {
			msg: 'Hello world!'
		}
	}
}
</script>

<style>
.example {
  color: red;
}
</style>

Vue Loader提供了很多酷炫的特性:
(1)允许为Vue组件的每个部分使用其它的webpack loader
    例如:在 <style> 的部分使用 Sass 和在 <template> 的部分使用 Pug;
(2)允许在一个.vue文件中使用自定义块,并对其运用自定义的loader链;
(3)使用webpack loader将<style>和<template>中引用的资源当作模块依赖来处理
(4)为每个组件模拟出scoped CSS
(5)在开发过程中使用热重载来保持状态

简而言之,webpack和Vue Loader的结合提供了一个现代、灵活且极其强大的前端工作流,来帮助撰写Vue.js应用


Vue CLI

如果不想手动设置webpack,推荐使用Vue CLI直接创建一个项目的脚手架。通过Vue CLI创建的项目会针对多数常见的开发需求进行预先配置,做到开箱即用


webpack手动设置

1.安装vue-loader和vue-template-compiler

npm install vue-loader vue-template-compiler -D

每个vue包的新版本发布时,一个相应版本的vue-template-compiler也会随之发布。编译器的版本必须和基本的vue包保持同步,这样vue-loader就会生成兼容运行时的代码。这意味着每次升级项目中的vue包时,也应该匹配升级vue-template-compiler


2.在配置文件(webpack.config.js)中,进行配置

Vue Loader的配置和其它的loader不太一样。除了通过一条规则(rules)将vue-loader应用到所有扩展名为“.vue”的文件上之外,还需要在webpack 配置中添加Vue Loader的插件
注意:必须配置VueLoaderPlugin(不需要额外装包,该插件在vue-loader中自带)

const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
	module: {
		rules: [
			// ... 其它规则
			{
				test: /\.vue$/,
				loader: 'vue-loader'
			}
		]
	},
	plugins: [
		// 请确保引入这个插件!
		new VueLoaderPlugin()
	]
}

配置完毕后就可以在main.js中引入.vue文件,使用render函数等方式进行渲染了


3.main.js(入口)中使用Vue

方式①:main.js

new Vue({
    el: '#app',
    template: '<div>\n' +
        '<h1>{{ message }}</h1>\n' +
        '<h4 @click="btnClick"></h4>\n' +
        '</div>',
    data() {
        return {
            message: "info",
            name: "code"
        }
    },
    methods: {
        btnClick() {
            console.log("abc!");
        }
    }
})

方式②:main.js
main.js

const App = {
    template: '<div>\n' +
        '<h1>{{ message }}</h1>\n' +
        '<h4 @click="btnClick"></h4>\n' +
        '</div>',
    data() {
        return {
            message: "info",
            name: "code"
        }
    },
    methods: {
        btnClick() {
            console.log("abc!");
        }
    }
}

main.js

new Vue({
    el: '#app',
    template: '<App/>',
    components: {
        App
    }
})

方式③:common.vue定义组件
common.vue

<template>
    <div>
        <h1>{{ message }}</h1>
        <h4 @click="btnClick"></h4>
    </div>
</template>

<script>
    export default {
        name: 'common',
        data() {
            return {
                message: "info",
                name: "code"
            }
        },
        methods: {
            btnClick() {
                console.log("abc!");
            }
        }
    }
</script>

<style scoped>
</style>

main.js

import App from './App.vue'

new Vue({
    el: '#app',
    template: '<App/>',
    components: {
        App
    }
})

最后一步:使用组件

App.vue

<template>
    <div>
        <app></app>
    </div>
</template>

<script>
    import App from './App.vue'
    
    export default {
        name: "start",
        components :{
            App
        }
    }
</script>

<style scoped>
</style>

render函数(渲染函数)

render函数跟template一样都是创建html模板的,但是有些场景中用template实现起来代码冗长繁琐而且有大量重复,这时候就可以用render函数

函数:render
类型:(createElement: () => VNode) => VNode
说明:字符串模板的代替方案,允许发挥JavaScript最大的编程能力。该渲染函数接收一个createElement方法作为第一个参数用来创建VNode(虚拟DOM)

如果组件是一个函数组件,渲染函数还会接收一个额外的context参数,为没有实例的函数组件提供上下文信息

Vue选项中的render函数若存在,则Vue构造函数不会从template选项或通过el选项指定的挂载元素中提取出的HTML模板编译渲染函数


createElement参数(三个)
返回值:VNode(虚拟DOM)

createElement(
	// 类型:{String | Object | Function}
	// 说明:一个HTML标签名、组件选项对象,或者resolve了上述任何一种的一个async函数。必填
	'div',
	
	// 类型:{Object}
	// 说明:一个与模板中 attribute对应的数据对象。可选
	{
	},
	
	// {String | Array}
	// 子级虚拟节点(VNodes),由“createElement()”构建而成,也可以使用字符串来生成“文本虚拟节点”。可选
	[
		'先写一些文字',
		createElement('h1', '一则头条'),
		createElement(MyComponent, {
			props: {
				someProp: 'foobar'
			}
		})
	]
)

plugin(插件)

plugin是什么?

(1)plugin是插件的意思,通常是用于对某个现有的架构或功能进行扩展
(2)webpack中的插件,就是对webpack现有功能的各种扩展,比如:打包优化,文件压缩等等


plugin的使用过程

①:通过npm安装需要使用的plugins(某些webpack已经内置的插件不需要安装)
②:在webpack.config.js中的plugins中配置插件


loader和plugin的区别

loader:用于转换某些类型的模块,是一个转换器
plugin:插件。它是对webpack的本身的扩展,是一个扩展器


通过webpack指令打包(隔行变色)

1.初始化()

npm init -y

2.在项目中安装jQuery

npm install jquery

3.建立项目结构

│  package-lock.json
│  package.json
└─src
│  index.html    // 自己创建
│  main.js       // 自己创建

4.将代码书写在main.js中

// ES6模块化语法导入jQuery
import $ from 'jquery'

// 此处为案例js代码,可以忽略(隔行变色)
$(function () {
	$('ul>li:odd').css('backgroundColor', 'pink')
	$('ul>li:even').css('backgroundColor', 'purple')
})

ES6模块化语法

语句说明
import导入的库对象的变量名
from可以写具体的路径,也可以写包名;如果写的是包名就会去/node_modules中查找

在index.html直接引入src/main.js无法再浏览器中运行,因为浏览器不支持import语法;所以需要webpack进行打包输出一个bundle.js,执行以下命令:

参数说明
-d指定打包模式为development(开发),表示不压缩
-p指定打包模式为production(线上),表示压缩
通过“-d”参数可以指定打包模式为development,表示不压缩;-p表示production模式,并压缩

5.命令打包

①:使用webpack命令打包

webpack  ./src/main.js  -o  ./dist/bundle.js  -d

上面命令会在自动生成一个dist文件并且会生成一个bundle.js文件,webpack将jQuery文件和自己写的js代码的代码编译到bundle.js中


②:通过手动建立webpack.config文件,书写配置

webpack.config.js配置文件(需要放在项目的根目录下使用)

const path = require('path')

module.exports = {
	// 入口。可以为相对路径,当然绝对路径也没错
	entry: './src/main.js',
	output: {  // 输出配置
		path: path.join(__dirname, './dist'), // 输出的目录
		filename: 'bundle.js' // 输出的文件名
	},
	mode: 'production' // 打包的模式:production | development
}

然后执行命令,因为在webpack.config.js中配置了入口和出口了,直接执行如下命令即可

webpack

当每次修改或者新增一个js文件的时候,就会重新执行一下webpack 命令进行编译,这种方式非常的麻烦,这样整个项目下来岂不是要执行百万次。使用webpack命令相关的参数,就避免这个情况

命令描述
webpack --config XXX.js使用另一份配置文件(比如webpack.config2.js)来打包
webpack --watch监听变动并自动打包
webpack -p压缩混淆脚本,这个非常非常重要
webpack -d生成map映射文件,告知哪些模块被最终打包到哪里了其中的
webpack --progress显示进度条
webpack --color添加颜色
参数说明
-p一个未压缩的 700kb 的文件,压缩后直接降到 180kb (主要是样式这块一句就独占一行脚本,导致未压缩脚本变得很大)
–watch监听文件是否有改变,有改变就会重新编译有改变的文件

webpack-banner-plugin(banner头)

(1)在webpack.config.js中配置

打包文件头部添加注释,相当于Spring Boot启动时的banner
注意:webpack-banner-plugin是webpack默认包含的不需要安装

const webpack = require('webpack')

module.exports = {
	plugins: [
		new webpack.BannerPlugin("(c) 最终版权归---所有")
	]
}

webpack-dev-server(加载至内存,热部署)

webpack-dev-server提供了一个简单的网络服务器,并具有实时重新加载(实时重新加载)功能

webpack-dev-server是一个小型的node.js Express服务器,它使用webpack-dev-middleware中间件来为通过webpack打包生成的资源文件提供Web服务。它还有一个通过Socket.IO连接着webpack-dev-server服务器的小型运行时程序。webpack-dev-server发送关于编译状态的消息到客户端,客户端根据消息作出响应

webpack-dev-server在编译之后将不会写入到任何输出文件。另外将捆绑文件保留在内存中,然后将它们服务到server中,就好像它们是挂载在server根路径上的真实文件一样。如果页面希望在其他不同路径中找到捆绑文件,则可以通过dev server配置中的publicPath选项进行修改
执行npm run build才会编译存储在磁盘中


1.安装webpack-dev-server包

npm install webpack-dev-server webpack webpack-cli -D
npm install webpack-dev-server -D
yarn add webpack-dev-server -D

2.在webpack.config.js中配置webpack-dev-server

修改配置文件,告知dev服务器,从什么位置查找文件

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
	mode: 'development',
	entry: {
		index: './src/index.js',
		print: './src/print.js'
	},
	devtool: 'inline-source-map',
	devServer: {                      // +
		contentBase: './dist',        // +
		hot: true					  // +
	},                               // +
	plugins: [
		new CleanWebpackPlugin({ cleanStaleWebpackAssets: false }),
		new HtmlWebpackPlugin({
			title: 'Development',
		}),
	],
	output: {
		filename: '[name].bundle.js',
		path: path.resolve(__dirname, 'dist'),
	}
}

以上配置通知webpack-dev-server,将dist目录下的文件服务到localhost:8080下


devServer是webpack中的一个选项,选项本身可以设置如下属性

选项描述
contenBase为哪个文件夹提供本地服务,默认是根文件夹
port端口号
inline页面实时刷新
historyApiFallback在SPA页面中,依赖HTML5的history模式
hot热模块加载
open自动打开浏览器
注意:以上选择可以在devServer中直接配置属性,也可以在scripts中配置命令,能够到达相同的效果;需要加上“–”号。例:–hot

3.在package.json中配置运行脚本(npm脚本)

在script节点下添加一个dev脚本

①:简单脚本
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server"
},
②:设置webpack-dev-server的端口号,dev脚本命令后面加上参数“--port”
"scripts": {
	"test": "echo \"Error: no test specified\" && exit 1",
	"dev": "webpack-dev-server --port 3000"
},
③:设置服务器的根路径、热模块替换、自动打开浏览器
"scripts": {
	"test": "echo \"Error: no test specified\" && exit 1",
	"dev": "webpack-dev-server --hot --open --contentBase ./src --port 3000"
	// --contenBase ./src:如果配置了,webpack.config.js就不用配置contentBase了
},
"scripts": {
	"test": "echo \"Error: no test specified\" && exit 1",
	"dev": "webpack serve --hot--open --port 8000"
	// serve:将资源作为服务器的可访问文件,相当于:-dev-server
},

注意:默认情况下webpack-dev-server会将入口的文件打包输出到项目的根目录, 并且不会在物理磁盘中保存,只在内存中存放,方便开发调试,请不要在json文件中添加注释

现在bundle.js已经是托管到内存中了,如果需要将HTML也托管到内存中,需要借助一个插件: html-webpack-plugin


4.运行脚本

在命令行中运行npm dev/npm run dev,会看到浏览器自动加载页面。如果更改任何源文件并保存它们,则Web服务器将在编译代码后自动重新加载

npm run dev

解释:当执行npm run dev/npm dev时,会到package.json下去找到scripts#dev,并执行后面的命令


脚本执行流程
package.json中的scripts的脚本在执行时,会按照一定的顺序寻找命令对象的位置
(1)首先,会找本地(项目下)的node_modules/.bin路径中对应的命令
(2)全局环境变量中寻找

devServer.publicPath & devServer.contentBase

参数描述
devServer.contentBase告诉服务器从哪里提供内容。只有在想要提供静态文件时才需要
devServer.publicPath用于确定应该从哪里提供 bundle,并且此选项优先

webpack-dev-server中的publicPath

在开发阶段,借用devServer启动一个开发服务器进行开发,这里也会配置一个publicPath,这里的publicPath路径下的打包文件可以在浏览器中访问。而静态资源仍然使用output.publicPath。

webpack-dev-server打包的内容是放在内存中的,这些打包后的资源对外的的根目录就是publicPath,换句话说,这里设置的是打包后资源存放的位置

devServer的publicPath:

const publicPath = '/dist/'

// 则启动devServer后index.html的位置
const htmlPath = `${pablicPath}index.html`
// 包的位置
cosnt mainJsPath = `${pablicPath}main.js`

以上可以直接通过http://lcoalhost:8080/dist/main.js访问到

访问: http://localhost:8080/webpack-dev-server,可以得到devServer启动后的资源访问路径


html-webpack-plugin(编译后生成index.html)

在真实发布项目时,发布的是dist(出口)文件夹中的内容,但是dist文件夹中如果没有index.html文件,那么打包的js等文件也就没有意义了;所以需要将index.html文件打包到dist文件夹中,这时候就需要用到HtmlWebpackPlugin插件
创建HTML文件来服务您的捆绑软件


HtmlWebpackPlugin插件功能

用于将css和js添加到html模版中,其中template和filename会受到路径的影响,从源码中可以看出
①:自动升一个index.html文件(可以指定模板来生成)
②:将打包的js文件,自动通过script标签插入到body中


(1)安装HtmlWebpackPlugin插件

使用插件后,内存中的index.html会自动添加bundle.js的引入,不需要自己手动添加,这样减少了html的代码量

npm install --save-dev html-webpack-plugin
yarn add --save-dev html-webpack-plugin

(2)修改webpack.config.js文件中plugins部分内容

注意:需要删除在output中添加的publicPath属性,否则插入的script标签中src可能会有问题

var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
	①:不使用模板,即index.html还需要引入编译后的文件
	plugins: [new HtmlWebpackPlugin()]

	②:template表示根据什么模板来生成index.html
	plugins: [
		new HtmlWebpackPlugin({
			template: 'index.html'
		})

		new HTMLWebpackPlugin({
			// 源文件
			template: path.join(__dirname, './src/index.html'),
			// 输出在服务器根目录的文件名, 文件存放在内存中, 不会在磁盘上显示
			filename: 'index.html'
		})
	]
};

template:用于定义模版文件的路径
源码:

this.options.template = this.getFullTemplatePath(this.options.template, compiler.context);

因此template只有定义在webpack的context下才会被识别,webpack context的默认值为process.cwd(),既运行node命令时所在的文件夹的绝对路径


filename:输出的HTML文件名,默认为index.html,可以直接配置带有子目录
源码:

this.options.filename = path.relative(compiler.options.output.path, filename);

所以filename的路径是相对于output.path的,而在webpack-dev-server中,则是相对于webpack-dev-server配置的publicPath

如果webpack-dev-server的publicPath和output.publicPath不一致,在使用html-webpack-plugin可能会导致引用静态资源失败,因为在devServer中仍然以output.publicPath引用静态资源,和webpack-dev-server的提供的资源访问路径不一致,从而无法正常访问。

有一种情况除外,就是output.publicPath是相对路径,这时候可以访问本地资源;所以一般情况下都要保证devServer中的publicPath与output.publicPath保持一致

3.编写index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app"></div>

<script src="./dist/build.js"></script>
// 使用上面②方式,js等引入可省略
</body>
</html>

uglifyjs-webpack-plugin(js压缩)

uglify-js用于压缩JavaScript
注意:要求的最小版本为Node v6.9.0和Webpack v4.0.0版本


(1)安装uglifyjs-webpack-plugin

npm install uglifyjs-webpack-plugin --save-dev
yarn add uglifyjs-webpack-plugin -D

(2)插件添加到你的webpack配置中

在webpack.config.js配置

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
	optimization: {
		minimizer: [new UglifyJsPlugin()],
	},
};

紧接着通过首选方式运行webpack


webpack-merge(配置文件分离)

开发(开发环境)和生产(生产环境)这两个环境下的构建目标存在着巨大差异


开发环境中:需要强大的源地图和一个有着重加载(实时重新加载)或热模块更换(热模块替换)能力的本地服务器
生产环境中:目标则转移到其他方面,关注点在于压缩包,更轻量的源地图,资源优化等,通过这些优化方式改善加载时间。通常建议为每个环境编写彼此独立的webpack配置
通用配置:虽然将生产环境和开发环境做了略微区分,但是,还是会遵循不重复原则,保留一个“common(通用)”配置。配置合并在一起,将使用一个称为webpack-merge的工具。此工具会引用“common”配置,因此不必再在环境特定的(特定于环境)的配置中编写重复代码


(1)安装webpack-merge

npm install --save-dev webpack-merge
yarn add --save-dev webpack-merge

(2)编写不同配置文件

common.cofing.js(公共)

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
	entry: {
		app: './src/index.js'
	},
	output: {
		filename: '[name].bundle.js',
		path: path.resolve(__dirname, 'dist')
	},
	plugins: [
		// 对于CleanWebpackPlugin的v2 versions以下版本,使用new CleanWebpackPlugin(['dsit/*'])
		new CleanWebpackPlugin(),
		new HtmlWebpackPlugin({
			title: 'Production'
		}),
	],
}

dev.config.js(开发)

const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
	mode: 'development',
	devtool: 'inline-source-map',
	devServer: {
		contentBase: './dist'
	}
})

prod.config.js(生产)

const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
	mode: 'production'
});

(3)在package.json中配置npm脚本

把scripts的命令重新指向指向新配置文件(默认:webpack.config.js)

package.json(Scripts)

"scripts": {
	// "start": "webpack serve --open",改为↓
	"start": "webpack serve --open --config webpack.dev.js",
	// "build": "webpack",改为↓
	"build": "webpack --config webpack.prod.js"
}

解释:让script#start(npm start)中webpack-dev-server,使用webpack.dev.js配置文件,而让script#build(npm run build)使用webpack.prod.js配置文件


(4)指定mode

许多library通过与process.env.NODE_ENV环境变量关联,以决定library中应该引用哪些内容。例如,当process.env.NODE_ENV没有被设置为’production’时,某些library为了使调试变得容易,可能会添加额外的log(日志记录)和test(测试)功能。并且,在使用process.env.NODE_ENV === 'production’时,一些library可能针对具体用户的环境,删除或添加一些重要代码,以进行代码执行方面的优化。从webpack v4开始,指定mode会自动地配置DefinePlugin


模式(Mode,内置优化)

提供mode配置选项,告知webpack使用相应模式的内置优化

语法 => mode : string
值:string = ‘none’ | ‘development’ | ‘production’

选项描述
development会将DefinePlugin中process.env.NODE_ENV的值设置为development,为模块和chunk启用有效的名
production会将DefinePlugin中process.env.NODE_ENV的值设置为production。为模块和chunk启用确定性的混淆名称,FlagDependencyUsagePlugin、FlagIncludedChunksPlugin、ModuleConcatenationPlugin、NoEmitOnErrorsPlugin和TerserPlugin
none不使用任何默认优化选项
如果没有设置,webpack会给mode的默认值设置为production
注意:设置NODE_ENV并不会自动地设置mode

用法
1.只需在配置对象(module.exports)中提供mode选项

module.exports = {
mode: 'development'
};

2.从CLI参数中传递

webpack --mode=development

DefinePlugin(定义全局常量)

DefinePlugin允许在编译时创建配置的全局常量,这在需要区分开发模式与生产模式进行不同的操作时,非常有用(webpack自带)

例如:如果想在开发构建中进行日志记录,而不在生产构建中进行,就可以定义一个全局常量去判断是否记录日志。这就是DefinePlugin的发光之处,设置好它,就可以忘掉开发环境和生产环境的构建规则

传递给DefinePlugin的每个键都是一个标识符或多个以“.”连接的标识符
(1)如果该平均值字符串,则被作为代码片段来使用
(2)如果该值不是字符串,则将被转换成字符串(包括函数方法)
(3)如果值是一个对象,则它所有的键将使用相同方法定义
(4)如果键添加typeof作为前缀,它会被定义为typeof调用


定义全局常量

new webpack.DefinePlugin({
	PRODUCTION: JSON.stringify(true),
	VERSION: JSON.stringify('5fa3b9'),
	BROWSER_SUPPORTS_HTML5: true,
	TWO: '1+1',
	'typeof window': JSON.stringify('object'),
	'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
});

这些值将内联到代码中,从而允许通过代码压缩来删除冗余的条件判断


使用常量

console.log('Running App version ' + VERSION);
if(!BROWSER_SUPPORTS_HTML5) require('html5shiv');

注意:在定义process值时,两种方式比较
方式①:

'process.env.NODE_ENV': JSON.stringify('production')

方式②:

process: {
	env: { 
		NODE_ENV: JSON.stringify('production')
	}
}

方式①更好,方式②会覆盖process对象,这可能会破坏与某些模块的兼容性,因为这些模块会在过程对象上定义其他值
也就是说,使用方式②定义process,第二次定义值的时候会将第一次覆盖掉


注意:由于本插件会直接替换文本,因此提供的值必须在串联本身中再包含一个实际的引号。通常,可以使用类似’“production”'这样的替换引号,或者直接用JSON.stringify(‘production’)


if (!PRODUCTION) {
  console.log('Debug info');
}

if (PRODUCTION) {
  console.log('Production log');
}

非官方webpack压缩过的代码

if (!true) {
  console.log('Debug info');
}
if (true) {
  console.log('Production log');
}

经过压缩后

console.log('Production log');

使用场景

new webpack.DefinePlugin({
	// 在生产/开发内置中使用功能标志可以启用/添加项目的不同特性
	'NICE_FEATURE': JSON.stringify(true),
	'EXPERIMENTAL_FEATURE': JSON.stringify(false)
	// 服务网址:在生产或开发建造中使用不同的服务URL
	'SERVICE_URL': JSON.stringify('https://dev.example.com')
})

运行时值通过runtimeValue
可以使用依赖于文件的值定义变量,并且当这些文件在文件系统中更改时将被重新评估。这意味着当此类监视的文件更改时,webpack将重建

function (getterFunction, [string]) => getterFunction()
第一个参数 webpack.DefinePlugin.runtimeValue是function,应返回要分配给定义的值
第二个参数 要监视的文件路径数组。通过true而不是[string]此处将模块标记为不可缓存

const fileDep = path.resolve(__dirname, 'sample.txt');

new webpack.DefinePlugin({
	BUILT_AT: webpack.DefinePlugin.runtimeValue(Date.now, [fileDep])
})

BUILT_AT值应为“sample.txt”是文件系统中的最后更新时间。例如:1597953013291

 类似资料: