项目中要有文件:webpack.config.js,它是运行在nodeJs中的一个文件,需要根据commonJs规范来编写代码,文件导出一个对象,我们根据导出的对象完成一系列配置。
构建流程
webpack启动的时候,会加载entry配置的入口文件,递归解析entry依赖的所有module,按照module.rules的规则进行匹配转化,对Module进行转换后,再解析出当前Module依赖的Module,这些Module会以Entry为单位进行分组,即为一个Chunk。因此一个Chunk,就是一个Entry及其所有依赖的Module合并的结果。最后Webpack会将所有的Chunk转换成文件输出Output。在整个构建流程中,Webpack会在恰当的时机执行Plugin里定义的逻辑,从而完成Plugin插件的优化任务。
loader
对模块进行加载、处理、编译转换,在module的rules中进行配置,如下:如果遇到后缀为css的文件,则会使用css-loader和style-loader进行编译转换。
loader更像是一个管道,将文件通过参数传递,然后经过一系列的处理,最终将文件输出。
rules: [
{
test: /.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /.jpg$/,
use: 'file-loader'
},
]
plugin
相比于loader,Plugin拥有更宽的能力范围,loader只是在加载的环节工作,而插件触及到webpack工作的每一个环节。 Plugin用来扩展webpack功能,实现原理是在构建流程里注入钩子函数。在plugins数组中进行配置。例如:Webpack要求插件必须是一个函数或者是一个包含apply方法的对象。
plugins: [
new CleanWebpackPlugin()
]
依赖:
"devDependencies": {
"@babel/core": "^7.10.5",
"@babel/preset-env": "^7.10.4",
"@vue/cli-plugin-babel": "^4.4.6",
"babel-loader": "^8.1.0",
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^6.0.3",
"css-loader": "^4.0.0",
"eslint": "^7.5.0",
"eslint-loader": "^4.0.2",
"file-loader": "^6.0.0",
"html-webpack-plugin": "^4.3.0",
"less-loader": "^6.2.0",
"style-loader": "^1.2.1",
"stylus-loader": "^3.0.2",
"url-loader": "^4.1.0",
"vue-loader": "^15.9.3",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.11",
"webpack": "^4.44.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^5.0.9"
},
webpack.common.js
//yarn add html-webpack-plugin --dev 自动生成HTML插件
const HtmlWebpackPlugin = require('html-webpack-plugin')
//插件加载
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
//打包入口文件
entry: path.join(__dirname,'./src/main.js'),
output: {
//打包输出路径
path: path.join(__dirname,'./dist'),
//输出,
filename: '[name].[hash:6].js'
},
//配置项通过别名来把原导入路径映射成一个新的导入路径
resolve: {
//在导入语句没带文件后缀时,Webpack 会自动带上后缀后去尝试访问文件是否存在
extensions: ['.js', '.vue', '.json'],//用于配置在尝试过程中用到的后缀列表
alias: {
'assets':path.join(__dirname,'assets'),
'pages': path.join(__dirname,'src/pages'),
'public':path.join(__dirname,'public'),
'components':path.join(__dirname,'src/components')
}
},
module: {
rules: [
{
//yarn add eslint-loader --dev
test: /\.(js|vue)$/,
use: 'eslint-loader',
enforce: 'pre'
}
]
},
plugins: [
//自动生成HTML插件
new HtmlWebpackPlugin({
template: 'src/index.html',
}),
new VueLoaderPlugin()
]
}
webpack.dev.js
const webpack = require('webpack')
const {merge} = require('webpack-merge')
const baseConfig = require('./webpack.common.js')
module.exports = merge(baseConfig, {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
devServer: {
clientLogLevel: 'warning',//日志级别
hot: true,
open: true,
contentBase:path.join(__dirname,'./dist'),
publicPath:'/',
// overlay: { warnings: false, errors: true },
},
module: {
rules: [
{
//css文件处理
test: /\.css?$/,
//执行顺序从右到左
use: ['vue-style-loader','css-loader']
},
{
test: /\.styl(us)?$/,
use: ['vue-style-loader','css-loader', 'stylus-loader']
},
{
test: /\.(js|vue)$/,
use: 'eslint-loader',
enforce: 'pre'
}, {
test: /\.less?$/,
use: [
'vue-style-loader',
'css-loader',
'less-loader'
]
} ,{
test: /\.vue$/,
use: 'vue-loader'
}, {
test: /\.js$/,
exclude: /node_modules/,//很重要
use: {
loader: 'babel-loader'
}
}, {
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10*1024,
esModule: false,
}
}
}, {
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
}
}
}, {
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
}
}
}
]
},
plugins: [
//热更新
new webpack.HotModuleReplacementPlugin()
]
})
webpack.dev.js
const merge = require('webpack-merge')
const baseConfig = require('./webpack.common')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const utils = require('./utils.js')
module.exports = merge(baseConfig, {
mode: 'production',
devtool: 'none',
optimization: {
usedExports:true,
minimize:true,
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'all'
}
}
}
},
module: {
rules: [
{
test: /\.css?$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
},
{
test: /\.styl(us)?$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'stylus-loader']
},
{
test: /\.(js|vue)$/,
use: 'eslint-loader',
enforce: 'pre'
}, {
test: /\.less?$/,
use: [
'vue-style-loader',
'css-loader',
'less-loader'
]
} ,{
test: /\.vue$/,
use: 'vue-loader'
}, {
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
}
}, {
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10*1024,
esModule: false,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
}
}, {
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
}
}, {
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
}
]
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: 'main.css'
}),
new CopyWebpackPlugin({
patterns: [
{
from: utils.resolve('public/'),
to: utils.resolve('dist/public'),
toType: 'dir'
}
]
})
]
})