webpack 基本语法
都是在 webpack.config.js 页面上写的
const path = require('path') // path 模块是node自带的 可自行查看module.exports = {mode:'none',//工作模式 development(开发模式 会添加一些注释) none (原始状态) production(生产模式也就是打包发布的模式 自动压缩模式)entry:'./src/index.js',// 需要打包的文件路径 入口文件 所有需要打包的都需要在入口文件import加入output:{ // 输出路径 类似重定向路径 一开始打包的路径为 dist/main.js 现在为dist/bundle.jsfilename:'bundle.js',path:path.join(__dirname,'dist'),// path 必须为绝对路径否则会报错。 dist 可修改//如果publicPath为空 则表示在根目录下会找不到打包后的图片 而图片打包后在dist目录下,所以需要指定publicPath:'dist/' //publicPath 是打包路径},}// 默认打包的路径为 src/index.js ==> dist/main.js
webpack 模块
webpack 只是一个打包工具,是将文件打包不会对里面的代码进行处理 如果需要对代码进行处理就需要使用到 loader loader是webpack对文件进行处理的模块
rules里面的每个对象就是一个模块
use 还有一种写法可以写绝对路径 就跟require一样 。use是以test中写入的XX文件格式用use下的模块来执行
css-loader 模块
css-loader 安装完css-loader 你会发现css格式的文件还是无法执行 也会就需要安装style-loader
yarn add css-loader --dev // css-loaderyarr add style-loader --dev //style-loader
const path = require('path')
module.exports = {
mode:'none',
entry:'./src/index.js',
output:{
filename:'bundle.js',
path:path.join(__dirname,'dist'),
publicPath:'dist/'
},
module:{//加入模块
rules:[ // rules:[] 是模块的规则加载器 webpack 提供了很多关于 loader插件
{
test:/\.css$/, // 以css结尾的文件用use中指定的loader
// css-loader: 将文件安装css来执行 style-loader:将css文件用style标签追加到页面上
use:['style-loader','css-loader'] // 注意:use如果有多个loader它的执行顺序是从后往前执行 也就是先执行css-loader
}, // 每一个对象就是一个模块加载器
},
}
webpack 是把所有的css ,html 以javascript来呈现的
/* 支持加载其他的样式加载模块 */
@import url(./style.css);
body{
min-height: 100vh;
color: white;
background: url(./background.png);
background-size: cover;
}
/* webpack 打包到css 文件时将文件按 css-loader来打包但在打包过程中遇到了.png文件 png 文件就会作为一个模块打包,webpack 将png文件用url-loader来处理 */
/* css-loader 会触发文件中别的文件 如 png css 都可以触发 */
babel-loader 模块
webpack不会处理js中es6和更高版本的新特性就需要用babel-loader来代替原来的js打包工具 babel-loader只相当于一个平台 在babel里面的@babel/core 和 @babel/preset-env 必须包含这两个才会打包生效
yarn add babel-loader @babel/core @babel/preset-env --dev
module:{
rules:[
{
test:/\.js$/,
use:{
loader:'babel-loader',
options:{
presets:['@babel/preset-env'] //@babel/preset-env 包含了es6的所有新特性
}
}
},
{// 多个模块就往后累加
test:/\.css$/, // 以css结尾的文件用use中指定的loader
// css-loader: 将文件安装css来执行 style-loader:将css文件用style标签追加到页面上
use:['style-loader','css-loader'] // 注意:use如果有多个loader它的执行顺序是从后往前执行 也就是先执行css-loader
} // 每一个对象就是一个模块加载器
]
},
file-loader 模块 和url-loader模块 文件模块
注意:小文件使用url-loader可以减少请求次数 大文件用file-loader来单独提取存放可以提高加载速度
yarn add file-loader --dev
yarn add url-loader --dev
{ // 文件资源加载器 图片 //file-loader
test:/\.png$/,
//use 也可以是个对象
use:{
loader:'url-loader' , // loader属性 用url-loader来处理.png结尾的文件 url-loader转换出来的文件是base64格式
options:{ // 配置选项
//options 中limit就是限制 如果文件大于10KB就使用file-loader 如果小于就使用url-loader 但要想使用file-loader 需要安装 file-loader
limit: 10 * 1024 //10kb
}
} //webpack 执行时候是以file-loader来处理png文件
},//直接加到module下面的rules数组中就行
html-loader 模块
yarn add html-loader --dev
{ // html的打包loader
//html-loader默认只会处理 img标签的资源 a标签的不会处理
test:/\.html$/,
use:{
loader:'html-loader',
options:{
sources:{ //webpakc默认可以识别img的src文件但不识别a标签的href 所有加上a标签的href属性
list:[
{
tag:'img',
attribute:'data-src',
type:'src'
},{
tag:'a',
attribute:'href',
type:'src'
}
]
} // attrs 默认是 img:src 我们可以按照这个格式添加 a:href
}
}
},
自定义loader
比如我们想让项目中md文件加入打包就需要自己模拟个
loader相当于一个管道 如 文件类似是md格式的就需要通过管道(loader)转为javascript(管道可以有多个)。如果想让md成为loader直接上传到npm上就可以使用了
md文件
markdown-loader.js 就是use 引入的 markdown-loader模块
需要安装 marked 模块 模块作用是将 md 文件转为html html格式又不是js格式的需要在转换下有两种写法 下面介绍:
这里使用的是第二种
yarn add marked --dev //将md文件的内容转为html的模块
{ // 自己模拟的原理
test:/\.md$/,
use:[
'html-loader',
'./markdown-loader'
] // use 跟requirt一样可以使用绝对路径引入
}
markdown-loader.js
const marked = require('marked')
// 模拟一个loader的工作原理 webpack 最重要的是loader的转换器
module.exports = source =>{ //输入的是文件的内容 输出是文件处理后的结果
console.log(source) // 打印的是文件里面的内容
// return 'console.log("hello~")' //需要返回的是javascript类型的格式
const html = marked(source) // 返回的是html格式
// 两种方法
//第一种直接module.exports 解释下为什么需要json.stringify()因为直接module.exports = html会是文件中的换行符什么导致错乱
// 在打包的bundle.js中 结果是 module.exports = "<h1 id=\"关于我\">关于我</h1>\n<p>我是何晓丹,一个手艺人~</p>\n"
// return `module.exports = ${ JSON.stringify(html) }`
//第二种使用html-loader
return html //在配置文件中修改use加入html-loader
}
// 我们可以用多个loader 来完成一个loader
webpack 插件
清除打包文件目录 dist
clean-webpack-plugin 插件
yarn add clean-webpack-plugin --dev
webpack.config.js
const path = require('path') // path 模块是node自带的 可自行查看
// 注名字不能乱写
const { CleanWebpackPlugin } = require('clean-webpack-plugin') //清除上次的打包目录(dist)
module.exports = {
mode:'none',
entry:'./src/index.js',
output:{
filename:'bundle.js',
path:path.join(__dirname,'dist'),
publicPath:'dist/'
},
module:{//模块
rules:[ // rules:[] 是模块的规则加载器 webpack 提供了很多关于 loader插件
{ // yarn add babel-loader @babel/core @babel/preset-env --dev
test:/\.js$/,
use:{
loader:'babel-loader',
options:{
presets:['@babel/preset-env'] //@babel/preset-env 包含了es6的所有新特性
}
}
}
.......
]
},
plugins:[ // 插件
new CleanWebpackPlugin() // 清除打包文件目录
]
}
自动生成html文件插件
html-webpack-plugin
使用这个插件的原因是:没使用之前index.html在打包的范围外,而且需要确定index.html里的文件引用是否正确
webpack是知道项目中生成的包,会自动引用到html文件中。将下图中index.html生成到dist目录里 这样发布时候只需要发布dist文件
yarn add html-webpack-plugin --dev
安装完成后在 webpack.config.js中引入插件
const HtmlWebpackPlugin = require('html-webpack-plugin')
plugins:[ // 插件
new CleanWebpackPlugin(), // 清除打包文件目录
new HtmlWebpackPlugin() //自动生成html
]
另外需要注意的是 output中的publicPath的值 如果html在dist目录下里面的资源也在是不需要指定具体目录的

index.html在dist下 ,所以里面引入文件就不需要加dist publicPath不需要设置值。 因为publicPath 默认就是在打包目录下找资源文件
HtmlWebpackPlugin 插件 的options选项
plugins:[ // 插件
new HtmlWebpackPlugin({
title:'webpack html plugin', // 修改自动生成html文件的标题头
meta:{ // 添加 meta标签 <meta name="viewport" content="width=device-width">
viewport:'width=device-width'
},
template:'./src/index.html' // 根据模板打包
}), //自动生成html
//可根据自己需要看是否需要加多个html页面这两个html页面打包出来是一致的内容,可修改options 这里只是介绍有这种功能
new HtmlWebpackPlugin({ // 一个HtmlWebpackPlugin代表一个html文件 如果需要多个就写多个HtmlWebpackPlugin插件
filename:'about.html'
})
]
copy-webpack-plugin 插件 复制文件到dist目录
plugins:[ // 插件
new CleanWebpackPlugin(), // 清除打包文件目录
new HtmlWebpackPlugin({ // 一个HtmlWebpackPlugin生产一个html页面
title:'webpack html plugin',
meta:{
viewport:'width=device-width'
},
template:'./src/index.html'
}), //自动生成html
// yarn add copy-webpack-plugin --dev
new CopyWebpackPlugin({ //文件copy 从public 复制到dist下 to:"值为dist下的文件夹"
patterns: [
{ from: "public", to: "dest" }
]
}),
]
可以根据需求到webpack官网 查找插件和模块 根据关键字查找插件和模块
自定义webpack插件
参考网站:https://blog.csdn.net/qq_36380426/article/details/104471422
Webpack 插件组成
在自定义插件之前,我们需要了解,一个 Webpack 插件由哪些构成,下面摘抄文档:
一个具名 JavaScript 函数;
在它的原型上定义 apply 方法;
指定一个触及到 Webpack 本身的事件钩子;
操作 Webpack 内部的实例特定数据;
在实现功能后调用 Webpack 提供的 callback。
插件由一个构造函数实例化出来。构造函数定义 apply 方法,在安装插件时,apply 方法会被 Webpack compiler 调用一次。apply 方法可以接收一个 Webpack compiler对象的引用,从而可以在回调函数中访问到 compiler 对象。
官方文档提供一个简单的插件结构:
class HelloWorldPlugin {
apply(compiler) {
compiler.hooks.done.tap('Hello World Plugin', (
stats /* 在 hook 被触及时,会将 stats 作为参数传入。 */
) => {
console.log('Hello World!');
});
}
}
module.exports = HelloWorldPlugin;
使用插件:
// webpack.config.js
var HelloWorldPlugin = require('hello-world');
module.exports = {
// ... 这里是其他配置 ...
plugins: [new HelloWorldPlugin({ options: true })]
};
apply 方法为插件原型方法,接收 compiler 作为参数。
选择插件触发时机
选择插件触发时机,其实是选择插件触发的 compiler 钩子(即何时触发插件)。
Webpack 提供钩子有很多,这里简单介绍几个,完整具体可参考文档《Compiler Hooks》:
entryOption : 在 webpack 选项中的 entry 配置项 处理过之后,执行插件。
afterPlugins : 设置完初始插件之后,执行插件。
compilation : 编译创建之后,生成文件之前,执行插件。。
emit : 生成资源到 output 目录之前。
done : 编译完成。
事件钩子函数
在 compiler.hooks 下指定事件钩子函数,便会触发钩子时,执行回调函数。
Webpack 提供三种触发钩子的方法:
tap:以同步方式触发钩子;tapAsync:以异步方式触发钩子;tapPromise:以异步方式触发钩子,返回 Promise;
MyPlugin.js
class MyPlugin{
apply(compiler){
console.log("myplugin 启动")
compiler.hooks.emit.tap('MyPlugin',(compilation) => {
// compilation => 可以理解为此次打包的上下文 所以打包的文件内容
for(const name in compilation.assets){ // compilation.assets是需要打包的对象
//name 是打包的文件名称
// console.log(compilation.assets[name].source()) //source()访问到文件的具体值
//endsWith('.js') 判断字符串是否以.js的为结尾 true返回的是此方法 否则false
if(name.endsWith('.js')){
const contents = compilation.assets[name].source()
const withoutComments = contents.replace(/\/\*\*+\*\//g,'') //用正则给js中不用的注释删除
compilation.assets[name] = { //替换原来的数据 source() 是个方法调用时候给的就是具体值 赋值时候也要给函数,size为必写项。
source:()=> withoutComments,// function(){ return withoutComments }
size:()=> withoutComments.length
}
}
}
})
}
}
module.exports = MyPlugin;
在webpack.config.js引入插件
const MyPlugin = require('./MyPlugin.js')
//在插件中调用
plugins:[ // 插件
new MyPlugin()
]
没使用插件前

使用插件后

