1.首先安装各个模块所需要的依赖
- npm init -y 初始化package.json文件 。
以下所有安装命令的 ‘-D‘ 代表安装在该文件的devDependencies中
npm的文档说明:dependencies是运行时依赖,devDependencies是开发时的依赖
- npm i webpack webpack-cli webpack-dev-server webpack-merge -D
webpack可以看做是模块打包机。webpack-cli封装了与CLI处理相关的所有代码。它捕获选项并将它们发送到webpack编译器。webpack-dev-server是webpack官方提供的一个小型express服务器, 为webpack打包生成的资源文件提供web服务。webpack-merge是和用来区分两个不同的环境
- npm i cross-env -D
可以跨平台设置环境变量
- npm i @babel/core babel-loader @babel/preset-env -D
@babel/core是转译器本身,提供了babel的转译API。babel-loader就是调用这些API来完成转译js过程的。Babel 7宣布废弃babel-preset-es201x而采用新的env插件
- npm i @babel/runtime-corejs2 @babel/plugin-transform-runtime -D
Babel默认只转换新的JavaScript句法,而不转换新的API。需要在入口加载@babel/polyfill插件来转换,但是这种方式是通过向全局对象和内置对象的prototype上添加方法实现的,会造成全局变量污染,因此在babel7.x版本中,@babel/polyfill不再受欢迎。而是@babel/runtime-corejs2(它是babel7 中 @babel/polyfill 的别名)结合@babel/plugin-transform-runtime使用, 可避免全局污染。
在转换 ES2015 语法为 ECMAScript 5 的语法时,babel 会需要一些辅助函数,例如 _extend。babel 默认会将这些辅助函数内联到每一个 js 文件里,这样文件多的时候,项目就会很大。所以 babel 提供了 transform-runtime 来将这些辅助函数“搬”到一个单独的模块 babel-runtime 中,这样做能减小项目文件的大小。
- npm i @babel/plugin-proposal-decorators -D
将类和对象装饰器编译为ES5
- npm i @babel/plugin-syntax-dynamic-import -D (在babel7.x中似乎并不需要再进行单独安装)
允许解析import() 延迟加载,懒加载
- npm i @babel/plugin-proposal-optional-chaining -D
可以访问深层嵌套的属性,可以不用逻辑与去判断 // const baz = obj?.foo?.bar?.baz
注意: babel7.0后,已经不再使用@babel/preset-stage-x的预设了, 所需的插件都需要单独去安装配置,根据公司的项目需要,可以选择性的去配置 :@babel/plugin-*** 这里不做过多赘述。
- npm i vue-loader vue-template-compiler -D
解析vue文件需要安装这两个插件
- npm i uglifyjs-webpack-plugin -D
用来在生产环境压缩js
- npm i css-loader sass node-sass sass-loader postcss-loader autoprefixer mini-css-extract-plugin optimize-css-assets-webpack-plugin -D
css-loader处理css,用来解析@import这种语法。sass-loader将sass语言转换成css, postcss-loader 和 autoprefixer用来为css的样式自动添加浏览器前缀,mini-css-extract-plugin是提取css文件,不再以style标签存放,而是创建link标签引入,所以不再需要style-loader。optimize-css-assets-webpack-plugin用来压缩css
- npm i url-loader file-loader -D
url-loader打包图片资源,file-loader打包字体等资源
- npm i html-webpack-plugin clean-webpack-plugin copy-webpack-plugin -D
html-webpack-plugin用来打包时自动生成html文件,clean-webpack-plugin打包时会自动清除dist,copy-webpack-plugin用来拷贝静态资源到打包目录
安装完上述依赖之后,需要根据自己的安装去配置.babelrc(babel的配置文件)和postcss.config.js。这里直接附上我自己的配置仅供参考。如下:
- .babelrc
{
"presets": [
"@babel/preset-env"
],
"plugins": [
["@babel/plugin-transform-runtime", {
"corejs": 2
}],
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
"@babel/plugin-proposal-optional-chaining"
]
}
复制代码
- postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}复制代码
2. webpack公共文件配置 :webpack.base.config.js
let path = require('path')
let MiniCssExtractPlugin = require('mini-css-extract-plugin') // 提取css公共文件
let { VueLoaderPlugin } = require('vue-loader') //vue-loader 15.x版本以后需要引入
let HtmlWebpackPlugin = require('html-webpack-plugin') //自动生成html
let CopyWebpackPlugin = require('copy-webpack-plugin') //拷贝静态资源
let { CleanWebpackPlugin } = require('clean-webpack-plugin') //打包前清除dist
let webpack = require('webpack')
module.exports = {
entry: [ path.resolve(__dirname, '../src/main.js') ],
output: {
filename: 'js/[name].[hash:8].js', //打包后的js文件放在js目录下,添加hash值防止缓存
chunkFilename: 'js/[name].[hash:8].js', // 配合按需加载路由来使用,用来修改打包后的各个JS模块文件名字,具体请看下方打包后的截图
path: path.resolve(__dirname, '../dist'), //输出的目录
publicPath: '/' //静态资源cdn的地址
},
stats: { // 本地起服务或者打包时候,清除过多的日志信息,精简控制台信息。
modules: false,
children: false,
chunks: false,
chunkModules: false
},
module: { //转换规则
rules: [
{
test: /\.vue$/,
exclude: /node_modules/,
use: ['vue-loader']
},
{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: /\.(css|scss|sass)$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader'
]
},
{
test: /\.(png|jpe?g|svg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 20 * 1024 // 不设置这个的话,打包后的图片默认是超过8k时,会以base64编码
name: 'images/[name].[hash:8].[ext]'
}
}
]
},
{
test:/\.(woff|woff2|eot|ttf|otf)$/,
use: [
{
loader: 'file-loader',
options: {
name: 'fonts/[name].[hash:8].[ext]'
}
}
]
},
]
},
resolve: {
extensions: ['.vue', '.js', '.scss', '.json'],// 能够使用户在引入模块时不带扩展名字, 自动解析
alias: { //别名,方便快速查找模块
'@': path.resolve(__dirname, '../src')
}
},
plugins: [
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, '../index.html'),
title: '这是自定义的名字,请随意',
hash: true,
minify: {
removeAttributeQuotes: true, //删除属性的引号
collapseWhitespace: true //删除空白符与折叠行
}
}),
new CleanWebpackPlugin(),
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../src/assets'),
to: path.resolve(__dirname, '../dist/copyAssets')
}
]),
new MiniCssExtractPlugin({
filename: 'css/[name].[hash:8].css'
}),
new webpack.ProgressPlugin() //显示打包进度的插件
]
}
复制代码
3.webpack开发环境配置 :webpack.dev.config.js
let webpack = require('webpack')
let path = require('path')
let merge = require('webpack-merge')
let base = require('./webpack.base.config')
module.exports = merge(base, {
mode: 'development', // 定义环境变量
devtool: 'cheap-module-eval-source-map',
devServer: {
port: 8000, //设置端口
progress: true,// 控制台显示HDM进度
hot: true, // 启用热更新
open: true, // 自动打开浏览器
historyApiFallback: true,
contentBase: path.resolve(__dirname, '../dist'),
proxy: {
'/api': { //url中匹配到'/api', 就会把'/api'之前的东西全部替换成target
target: '', // 目标服务器host
changeOrigin: true, // 表示要改变原始host
secure: false, // 默认请求的服务是https的, 并且证书是未认证的,所以需要关闭安全检测。
clentLogLevel: 'none', //当使用内联模式(inline mode)时,会在开发工具(DevTools)的控制台(console)显示消息,例如:在重新加载之前,在一个错误之前,或者 模块热替换(Hot Module Replacement) 启用时。默认值是 info。
pathRewrite: {
'^/api': '' // 重写请求,源访问地址中包含'/api'的将会替换为空
}
}
}
},
plugins: [
new webpack.HotModuleReplacementPlugin(), //热更新插件
new webpack.NamedChunksPlugin() // 使用此插件热更新时控制台会显示模块的相对路径
]
})复制代码
4.webpack生产环境配置 :webpack.prod.config.js
let merge = require('webpack-merge')
let base = require('./webpack.base.config')
let UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
let OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
module.exports = merge(base, {
mode: 'production',
devtool: 'cheap-module-source-map',
optimization: {
minimizer: [
new UglifyjsWebpackPlugin({ // 生产环境压缩JS
cache: true, //是否否启用缓存
parallel: true, //多通道并行处理
sourceMap: false, //生产环境关闭源码映射
uglifyOptions: {
warnings: false, //清除警告
compress:{
drop_debugger: true, // 清除degugger
drop_console: true //清除所有的console信息
}
}
}),
new OptimizeCssAssetsPlugin() // 生产环境压缩css
],
splitChunks: { //用于拆分代码,找到 chunk 中共同依赖的模块进行“提取”和“分离”到单独的文件中,减少打包后体积,可以避免内存溢出的问题。
chunks: 'all'
}
},
performance: { // webpack 的性能提示
hints: 'warning', // 显示警告信息
maxEntrypointSize: 5 * 1024 * 1024, // 设置入口文件的最大体积为5M (以字节为单位)
maxAssetSize: 20* 1024 * 1024, // 设置输出文件的最大体积为20M (以字节为单位)
assetFilter (assetFilename) { // 提供资源文件名的断言函数
return assetFilename.endsWith('.js') || assetFilename.endsWith('.css')
}
}
})
复制代码
4.最后一步
在package.json文件的scripts中添加如下,然后执行npm run build即可打包
"serve": "cross-env NODE_ENV=development webpack-dev-server --config ./build/webpack.dev.config.js",
"build": "cross-env NODE_ENV=production webpack --config ./build/webpack.prod.config.js"
复制代码
5.总结
以上配置是采用webpack4.x+babel7.x版本,自行配置时请注意版本兼容问题。如果您想要升级项目到babel7.0, 文档中也提供了一个升级工具:执行 npx babel-upgrade--write--install一键安装babel7.0所需要的所有配置,并且会自动将配置写入package.json和.babelrc文件中。详情请参考文档说明。以下是打包后的截图:
copyAssets是拷贝的静态资源。为什么打包后的js会有0**,2** 这么几个文件呢?这是因为我vue的路由使用了按需加载,每个页面都生成自己单独的js。等需要的时候,才会去加载这些js的。但是这个0, 1, 2,...等等的文件名字默认是以id命名的,这看起来不友好,而且不太方便排错,所以需要在引入路由时候,需要使用特殊的注释语法来提供webpackChunkName,配合output里面设置的chunkFilename: 'js/[name].[hash:8].js' 来修改文件名,代码如下:
export default new Router({
mode: 'history',
routes: [
{
path: '',
redirect: '/Home'
},
{
path: '/Home',
name: 'Home',
component: () => import(/* webpackChunkName: 'Home' */ '@/view/Home')
},
{
path: '/Hello',
name: 'Hello',
component: () => import(/* webpackChunkName: 'Hello' */ '@/view/Hello')
}
]
})复制代码
最终打包后的结果如下,看看,这就舒服多了~