目录
模块加载器(Loader)
导入css文件
加载图片
方法一
方法二
转换es6(向下兼容es5)
html代码组件导入导出
导入less文件
自定义loader(Markdown文件加载器)
markdown-loader.js文件
webpack.config.js文件配置
插件(plugins)
清除dist目录插件
通过html-webpack-plugin插件生成html(自动引入js代码)
copy-webpack-plugin
替换内容(DefinePlugin)
分离css文件
压缩css文件
自定义插件
自定义插件作用
webpack钩子链接
optimization属性
Tree-shaking(去掉无代码)
提取公共模块配置
Scope Hoisting(作用域提升)
sideEffects(副作用)
压缩css文件
模块加载器(Loader)
webpack内部默认只会处理解析JavaScript文件,需要通过模块加载器来处理其它类型文件例如css、图片等文件。
注意use下的loader会从后往前依次执行,例如下面代码先执行css-loader后执行style-loader。
const path = require('path')
module.exports = {
entry: {
main: ['./src/main.js', './src/index.js']
},
mode: 'development',
output: {
filename: '[name]-bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: 'dist/'
},
devServer: {
contentBase: 'dist',
overlay: true,
port: 8080,
open: true
},
module: {
rules: [
// es6转换(向下兼容es5)
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader'options: {
presets: ['@babel/preset-env'] // @babel/preset-env包括es6的全部特性转换
}
}
},
// 分离css文件
{
test: /\.css$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
}
]
},
// 加载图片 超过10KB的png图片使用file-loader处理,10KB内的用url-loader处理
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'file-loader'
}
]
},
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 10 * 1024, // 10KBname:'[name].[ext]',
publicPath:'images/',
outputPath:'images/'
}
}
]
},
// html代码组件导入导出
{
test: /\.html$/i,
use: [
{
loader: 'html-loader',
options: {
attrs: ['img:src','a:href']
}
}
]
},
]
},
plugins: []
}
导入css文件
在src文件夹下创建main.css在main.js中通过require('./main.css')引入,命令行输入npm install style-loader css-loader -D安装css-loader(能识别CSS并加载,支持模块化、压缩、文件导入等特性)和style-loader(通过动态创建style标签的方式,让解析后的css内容能够作用到页面中)。然后将webpack.dev.js图中注释内容打开即可(test是通过正则表达式匹配文件,use中为使用的loader),再次运行webpack-dev-server --config=config/webpack.dev.js便可以在http://localhost:8080/中看到添加了css的index.html文件
加载图片
方法一
拷贝文件加载原图片file-loader。
方法二
通过url-loader将图片转换为base64字符串格式
通常搭配使用小文件使用Data URLs,减少请求次数。大文件单独提取存放,提高加载速度。
命令行输入npm install url-loader file-loader -D,配置如上代码。
这时可以在css和less文件中使用图片,(这里的图片会被默认转换为base64字符串格式,好处是浏览器不用发送请求了,直接可以读取,坏处是图片如果太大,会导致转换后体积增大30%,所以这里设置了大小限制limit,表示当大于10kb时,在dist文件夹中创建images文件夹,在该文件夹下生成图片,通过链接导入,小于时才会base64转换),
注意css和less文件中使用图片的地址是src下的图片和文件的相对地址,而html中img标签使用的地址是publicPath(静态资源的引用路径)。
转换es6(向下兼容es5)
babel是一个平台,需要配置插件去完成具体特性的转换。
所以babel-loader依赖@babel/core模块且和需要完成具体特性转换插件例如@babel/preset-env(包括es6所有的特性转换)。
命令行输入npm install -D babel-loader @babel/core @babel/preset-env,配置如上代码.
此时如果在main.js写了es6的语法会被转换成es5(在最后的输出文件main-bundle.js可以查看)。
html代码组件导入导出
使用html-loader后下面的head.html文件,可以像js代码一样导入导出使用
<head><imagesrc=""mode="" /></head>
命令行输入npm install -D html-loader,配置如上代码。
注意html引入的资源中默认只会对image中的src链接进行处理,如果是a标签链接本地图片会无法展示,可以通过opttions下的attrs中添加a:href对a标签的图片链接进行处理解决。
导入less文件
less是css预处理文件,引入了变量函数等是css处理更灵活。首先命令行输入npm install less less-loader -D,然后在src文件夹下创建header.less文件,在main.js中写入require('./header.less'),然后配置webpack.config.js,在rules数组中添加{test: /\.less$/i,use: ["style-loader","css-loader","less-loader",],},注意这里还是会生成style标签插入,想要分离出来,把"style-loader"替换为{loader:MiniCssExtractPlugin.loader},这时less文件也会被分离到index.css中(见分离css文件)。
自定义loader(Markdown文件加载器)
注意use下loader处理的最后结果需要是一个字符串的导出,如果最后一个处理的loader是自定义loader,则需要返回的结果如下
return'module.export = "xxx"'return'export default "xxx"'
这样webpack最后处理将外层括号去掉,通过import 导入的自定义loader处理的文件,导入的内容就为xxx。
markdown-loader.js文件
需要安装marked包解析md文件的输入内容
const marked = require('marked')
module.exports = source => {
// 将md文件内容转换为字符串const html = marked(source)
// JSON.stringify转换字符串中的换行符和引号 例如将”转为\"// 方法一:只经过自定义loader处理 return`module.export = ${JSON.stringify(html)}`// return `export default ${JSON.stringify(html)}`// 方法二: 返回的值再经过html-loader处理// return html
}
webpack.config.js文件配置
const path = require('path')
module.exports = {
entry: {
main: ['./src/main.js', './src/index.js']
},
mode: 'development',
output: {
filename: '[name]-bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: 'dist/'
},
devServer: {
contentBase: 'dist',
overlay: true,
port: 8080,
open: true
},
module: {
rules: [
// 自定义markdown-loader
{
test: /\.md$/,
use: {
loader: './markdown-loader'// 自定义loader:markdown-loader.js文件路径
}
// 方法二 //use: [// { loader: 'html-loader' },// { loader: './markdown-loader' }//]
}
]
},
plugins: []
}
注意方法二是将返回的html交给html-loader处理,故use下数组中的顺序不能反。
方法二转换过程
插件(plugins)
清除dist目录插件
每次webpack打包文件会覆盖dist文件,之前留下的文件不会去删除,所以打包时需要先手动清空dist文件夹,然后在生成打包的文件。
命令行输入npm install clean-webpack-plugin -D,在webpack.dev.js中输入const { CleanWebpackPlugin } = require('clean-webpack-plugin'),然后在plugins数组(和module属性同级的属性)中添加new CleanWebpackPlugin()即可,这时我们每次输入命令行webpack --config=config/webpack.dev.js后都会先清空dist文件夹,然后在生成打包的文件。
通过html-webpack-plugin插件生成html(自动引入js代码)
运行命令行npm install html-webpack-plugin -D安装插件,配置webpack.dev.js中写入const HtmlWebpackPlugin = require('html-webpack-plugin')用于引入自动生成html的插件,给module.export指向的对象添加属性plugins: [new HtmlWebpackPlugin({ template: './src/index.html', title: 'example', meta: {viewport:'width=device-width' }}),new HtmlWebpackPlugin({filename:'about'})]
- template指定的模板便是移入src文件夹下的index.html的路径,在模板中可以通过<%= htmlWebpackPlugin.options.title %>访问example。
每个实例(new HtmlWebpackPlugin)都会生成一个html文件,上面会生成一个index.html和about.html文件。每个文件都会自动引入打包好的js文件.
注意如果webpack.config.js文件是在config文件夹下,但是这里的相对路径./依然指的是项目路径即config的上层路径。最后运行webpack --config=config/webpack.dev.js后会在dist文件上生成一个index.js文件,该文件中会自动引入main-bundle.js即打包后的出口文件(不需要手动引入了,可以去掉output下的publicPath: 'dist/'属性)。
- chunks:当有多个打包的html且有多个输出js文件,默认每个打包文件会引入多个输出js文件,可以通过chunks属性只引入指定的js文件。如下图只引入的对应的js文件。
copy-webpack-plugin
用来将静态文件(一般为public目录下内容)复制到输出文件夹下。
plugin的数组中添加new CopyWebpackPlugin(['public']),这里的public为需要复制的文件夹。
替换内容(DefinePlugin)
DefinePlugin为webpack的内置插件。const webpack=require('webpack'),plugins中添加new webpack.DefinePlugin({API_BASE_URL:'"Example Domain"'}),此时 在代码中的API_BASE_URL将会替换成"Example Domain"。
注意需要用单引号包括双引号,替换时会去掉外层的一层引号(可以使用JSON.stringify('Example Domain')去转换)
分离css文件
当css文件比较大时可以提取为一个文件通过link的方式引入(当css文件比较小时不适合,不提取为单独的文件可以减少http的请求)
命令行输入npm install mini-css-extract-plugin -D安装分离插件,在webpack.dev.js中输入const MiniCssExtractPlugin = require('mini-css-extract-plugin'),将之前配置style-loader的对象替换为{loader:MiniCssExtractPlugin.loader},最后在plugins的数组中添加new MiniCssExtractPlugin({filename:'./index.css'})即可,filename代表分离出来的css名字和地址,这里注意./表示的位置是dist文件夹下。
压缩css文件
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')然后在plugins的数组中添加new OptimizeCssAssetsWebpackPlugin()即可。
注意通常不推荐配置在plugins中,因为这样会在任何情况都使用,可以通过配置在optimization中使其只有在production环境下打包使用。
自定义插件
webpack的插件需要是一个函数或者一个包含apply方法的对象。通过在生命周期的钩子中挂载函数实现扩展功能。
自定义插件作用
清除打包后文件中的注释。
webpack钩子链接
Compiler Hooks | webpack
classMyPlugin {
// compile中包含此次构建的所有信息。 apply(compiler) {
// emit钩子在webpack即将输出文件之前执行
compiler.hooks.emit.tap("MyPlugin", compilation => {
// MyPlugin为插件的名称,compilation理解为此次打包的上下文// compilation.assets下是一个数组包含了所有经过webpack打包后的文件信息;for(const name in compilation.assets) {
// 判断文件名是否以.js结尾if(name.endsWith('.js')){
const contents = compilation.assets[name].source()
// 取出文件内容,将注释去掉const withoutComments = contents.replace(/\/\*\*+\*\//g, '')
// 修改新的文件信息,注意source和size属性要同步修改
compilation.assets[name] = {
source: () => withoutComments,
size: () => withoutComments.length
}
}
}
})
}
}
配置:申明上面文件后在plugins的数组中添加new MyPlugin()即可
optimization属性
用于优化输出的文件,通过在module.exports对象中添加属性optimization配置。
Tree-shaking(去掉无代码)
在webpack --mode production时会被自动调用。配置optimization: {useExports:true,minimize:true}实现,这两个属性只针对ES Module生效。
useExports:打包只导出外部使用过的成员。
minimize: 移除未被外部使用的成员。
注意:由Webpack打包的代码必须使用ES Module而不是commonjs(当配置了babel转换为commonjs时上面2个属性即使配置了也不会生效,故通常可以设置modules:false来关闭转换)。
提取公共模块配置
当有多入口文件生成多个打包文件时,如果入口文件中都用到jQuery,需要都引入,这时打包文件会重复打包jquery,在的module.exports对象中添加属性optimization: {splitChunks: {chunks: 'all'}},这时便会提取公共模块配置。不会重复打包重复的模块。
Scope Hoisting(作用域提升)
设置concatenateModules:true。
尽可能的将所有模块合并输出到一个函数中。
sideEffects(副作用)
在webpack --mode production时会被自动调用。模块执行时除了导出成员之外所作的事情。
设置sideEffects:true开启功能并在package.json文件中添加sideEffects:false标识代码没有副作用,才可以生效使文件中只有被导出的文件才会被执行。
注意副作用是包括直接引入css文件或未导出成员仅执行代码。开启过后下面代码将会被去除。
import'./global.css'import'./preset.js'
可以通过在package.json中添加属性"sideEffects":["./src/preset.js","*.css"] 来保留。
压缩css文件
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')后在optimization属性下添加minimizer:[new OptimizeCssAssetsWebpackPlugin()]即可。
注意这样表示我们要自定义压缩器,会覆盖webpack内置的js压缩器,所以此时js文件将不会被压缩了,我们通过const TerserWebpackPlugin = require('terser-webpack-plugin')引入,然后在数组中添加new TerserWebpackPlugin()即也可以压缩js文件了。