既然是前端项目,那么就npm就必不可少 运行 npm install webpack-cli -g
来全局安装脚手架 随后使用 npm install webpack-cli -D
安装到工程下
在工程目录下创建 webpack.config.js (文件名固定) 来作为webpack的配置文件,所有有关webpack的配置都写在此文件中,其中的内容通过es5语法暴露出去
webpack 五个核心配置是
entry 入口文件
output 输出
module loader配置
plugins 插件
mode 打包模式 其结构如下
module.exports = {
//入口起点
entry:
//输出
output:{
},
module:{
},
plugins:[
],//插件配置
mode:'development',
//mode:'production'
}
下面详细聊聊这五个配置
entry 入口文件,指示webpack 从哪个文件开始打包,这个入口文件所引用导入的文件都会参与打包
output 输出文件,指示webpack将打包好的文件输出到哪里 其中需要在顶部导入js的内置模块path
webpack 默认只能打包js/json资源,所以当我们想要打包其他资源是,则需要借助loader
module module主要作用是配置loader,而每一个loader都作为一个对象,存在rules数组中。 loader是webpack最重要的一环,只有配置了各种loader webpack才能打包各种各样的资源,其中各种loader通过npm 下载即可
打包资源
打包css资源(需要下载css-loader,style-loader)
{
//正则表达式 表示匹配哪些文件
test:/\.css$/,
use:[//use为一个数组,将loader按从下至上顺序执行
//创建一个style标签 将js中的样式添加到页面中生效
'style-loader',
//将css文件 以字符串的形式变成一个commjs模块加载到js
'css-loader',
]
}
打包less资源(需要下载style-loader,css-loader,less-loader)
{
test:/\.less$/,//每一种匹配规则 只适用与一种文件
use:[
//创建style标签 将js中的样式添加到页面中
'style-loader',
//将css文件 编译成commjs模块加载到js
'css-loader',
//将less文件编译成css文件
'less-loader'
]
},
将css单独打包成一个文件(单独下载mini-css-extract-plugin)
首先new一个对象
const MiniCssExtracetPlugin = requir('mini-css-extract-plugin')
调用插件对象
new MiniCssExtracetPlugin({
filename:'css/built.css'//对输出文件进行重命名
})
修改loader信息
{
test:/\.css/,
use:[
//'style-loader',//创建style标签,将样式放上去
MiniCssExtracetPlugin.loader,//取代style-loader 提取js中的css为单独文件
'css-loader'//将css文件整合到js中
]
}
打包img资源(1)(需要下载url-loader,file-loader) 由于图片数量在实际开发中会很多,在打包过程中就会拖慢打包速度,所以我们需要使用 options来修改loader的一些参数
//当只使用了一个loader时,则可以不使用use数组
loader:'url-loader',
options:{
limit:8 * 1024,
//图片大小小于8kb(项目中较小的图片) 就会被base64编码方式处理
//优点:减少请求数量 (减轻服务器压力)
//缺点:图片体积会更大(请求速度更慢)
name: '[hash:10].[ext]'
//文件名取哈希值前十位加上文件原拓展名
}
},
打包img资源(2)(需要下载html-loader) 上面那种处理方式只能处理 html引用的css文件中引入的图片,不能处理html页面中引入的图片。解决方法是使用html-loader 但是 url-loader是使用es6model去解析,而html-loader是使用commjs去解析, 为了避免冲突我们需要关闭url-loader的es6Module 改用commjs解析(在option中加入esModule:false)
{
//使用html-loader
test:/\.html$/,
loader:'html-loader'
}
options:{
limit:8 * 1024,
name: '[hash:10].[ext]'
//在url-loader中关闭es6Module
esModule:false
}
打包html资源(需要下载适用于html的plugin插件,html-webpack-plugin -D
)
在顶部引入 const HtmlWbpackPlugin = requi('html-webpack-plugin');
随后在plugins列表中new一个对象,其中的template属性,将作为结构模板。
plugins:[
new HtmlWbpackPlugin({
template:'./src/index.html'
})
],
兼容性处理
兼容css(需要下载postcss-loader,postcss-preset-env) 随着css版本的更新迭代,相对于应的兼容性问题也层出不穷,webpack也提供了css兼容性的解决方案
修改loader
{
test:/\.css/,
use:[
MiniCssExtracetPlugin.loader,
'css-loader',
//第一种 使用loader的默认配置 修改loader配置
//帮postcss找到package.json中browserslist的配置,通过指定配置加载兼容性样式
{
loader:'postcss-loader',
options:{
ident:'postcss',
plugins:()=>{
require('postcss-preset-env')
}
}
}
]
}
在package.json 中添加支持的browserlist
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
//兼容最近一个版本的谷歌火狐索菲亚浏览器
],
"production": [
">0.2%",//兼容99.8%的浏览器
"not dead",//不兼容已经死掉的浏览器
"not op_mini all"//不兼容op_mini
]
},
postcss 默认使用生产环境 如需使用开发环境则需要手动配置nodejs 中的临时环境变量,在webpack.config.js 顶部添加 process.env.NODE_ENV = 'development'
如抛错 ValidationError: Invalid options object. PostCSS Loader has been initialized using an options object that does not match the API schema. 则说明 此插件版本不支持在webpack.config.js中进行配合 需要在项目根目录下 创建 postcss.config.js 添加如下代码
module.exports = { plugins:[ require('postcss-preset-env')() ] }
然后在webpack.config.js 中删除post-loader的额外配置
{
loader:'postcss-loader',
//options:{
// ident:'postcss',
// plugins:()=>{
// require//('postcss-preset-env')
// }
//}
}
兼容js(1)(需要下载babel-loader,@babel/core,@babel/preset-env)
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
// 预设:指示babel 做怎样的兼容处理
presets: [
[
'@babel/preset-env',
{
//指定兼容性做到哪个版本的浏览器
targets: {
chrome: '60',
firefox: '50',
ie: '9',
safari: '10',
edge: '17'
}
}
]
]
}
}
这种方法只能转换基本语法,promise等不能转换
如需要兼容所有js(需要下载@babel/polyfill),在入口文件中引入 import '@babel/polyfill'
,这种方法会将所有js兼容性都包括,所以打包后会非常大
压缩处理
压缩js html 在修改mode属性为 production生成模式
删除html中无用的内容
new HtmlWbpackPlugin({
template:'./index.html',
minify:{
//移除空格
collapseWhitespace:true,
//移除注释
removeComments:true
}
})
压缩css(需要下载optimize-css-assets-webpack-plugin插件),并在插件列表中使用
plugins:[
new OptimizeCssAssetsWebpackPlugin()
],
HMR:hot module replacement 热模块替换 当某一个模块发生变化时 只会重新加载变化的模块 其他模块不会被加载
在webpack.config.js 结尾处添加
devServer:{
contentBase:resolve(__dirname,'build'),
compress:true,
port:3000,
open:true,
hot: true
}
js默认不能使用hmr,如需要,在入口文件添加监听即可
if(module.hot){
module.hot.accept('./print.js',()=>{
dosomething()
//监听print.js 文件,如果发生变化,会执行回调函数
})
}
html默认不能使用hmr 而且会导致html文件不能热更新 在入口文件 加上html文件即可(通常不需要hmr功能)
在源代码和构建后代码之间形成映射,当构建后代码出错时,可以映射到源代码 在webpack.config.js 末端添加devtool属性即可属性值及功能如下
开发环境下使用:eval-source-map(调试好) || eval-cheap-module-source-map(速度快) 生成环境下使用:source-map(调试好) || cheap-module-source-map(速度好) || nosources-source-map(隐藏全部代码)||hidden-source-map(隐藏源代码)
当使用oneOf后 当文件命中loader就会停止 不会接着继续判断 提高效率 将所有loader对象放入oneOf数组即可
module: {
rules: [
{
oneOf: [
{},
{},
{}
]
}
]
},
去除无用代码 减少打包体积 前提:es6module productionEnv 问题:会把一些文件干掉 如css babel(直接引用,没有使用)
在packge.json 中 添加配置sideEffects 以排除相应文件
"sideEffects": [
"*.css",
"*.less"
]
将打包后的文件拆分成多个文件 可以实现并行加载/按需加载
多个入口 多个出口 每一个出口文件都对应一个入口文件
entry:{
main:'./js/index.js',
test:'./js/test.js'
},
output:{
// 生成的构建后文件将根据入口文件进行命名
filename:'js/[name].js',
path:resolve(__dirname,'build')
},
添加 属性 将node_modules 中的文件 单独打包成一个chunk,如果是多入口 会将里面公用的modules 单独打包,在配置文件中添加配置
optimization:{
splitChunks:{
chunks:'all'
}
},
只有当需要模块的时候 才去加载,加载完成之后 再次调用会使用缓存
渐进式网络开发应用程序(离线访问) (需要下载 workbox-webpack-plugin 并导入其GenerateSW方法)
在配置文件plugins中使用插件
new GenerateSW({
clientsClaim:true,
skipWaiting:true
})
随后在入口文件中 注册service-worker
//注册serciceworker
if('serviceWorker' in navigator){
window.addEventListener('load',()=>{
navigator.serviceWorker.register('/service-worker.js')
.then(()=>{
console.log('serviceworkder 注册成功');
})
.catch(()=>{
console.log('serviceworkder 注册成功');
})
})
}
忽略打包 如果有包通过标签引入了 可以设置不被打包 在配置文件中添加
//忽略包名 不被打包
externals:{
jquery:'jQuery'
}
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';
// 复用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
/*
正常来讲,一个文件只能被一个loader处理。
当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
先执行eslint 在执行babel
*/
{
// 在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
// 优先执行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: {version: 3},
targets: {
chrome: '60',
firefox: '50'
}
}
]
]
}
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: 'production'
};
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
// 处理less资源
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 处理css资源
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
// 处理图片资源
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
// 关闭es6模块化
esModule: false,
outputPath: 'imgs'
}
},
{
// 处理html中img资源
test: /\.html$/,
loader: 'html-loader'
},
{
// 处理其他资源
exclude: /\.(html|js|css|less|jpg|png|gif)/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
}
]
},
plugins: [
// plugins的配置
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true
}
};