因为webpack4.x配置文件已经默认放到了node_modules里面,配置只能在根目录新建vue.config.js来进行配置,所以便动手基于wepack4.x手动配置了一个vue的脚手架,功能跟vue-cli类似,最主要的区别是将打包文件如:js、html、css放到了根目录,基本上是有了一个脚手架的雏形,更多细节还在优化中,接下来看看具体的配置吧。
首先在根目录创建了一个build文件,里面有三个文件:webpack.base.conf.js webpack.dev.conf.js webpack.prod.conf.js
接下来看一下三个文件具体的实现逻辑:
1、webpack.base.conf.js
这个文件主要是包含了开发环境和生产环境共性的逻辑,基于打包环境做了一些判断:
const webpack = require('webpack');
const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
const isProd = process.env.NODE_ENV === 'production';
const MiniCssExtractPluginLoader = {
loader:MiniCssExtractPlugin.loader,
options:{
publicPath: '../'
}
}
/**
* css和scss开发、生产依赖
* 生产分离css
*/
const cssConfig = [isProd ? MiniCssExtractPluginLoader : 'vue-style-loader',
{
loader: 'css-loader',
options: {
sourceMap: !isProd,
}
},
'postcss-loader'
],
scssConfig = [isProd ? MiniCssExtractPluginLoader : 'vue-style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
sourceMap: !isProd
}
},
'sass-loader'
];
module.exports = {
mode: process.env.NODE_ENV,
entry: {
app: './src/main.js',
vue: ['vue', 'vue-router', 'vuex'],
vendor: ['axios']
},
output: {
path: path.resolve(__dirname, '../'),
publicPath: '',
filename: 'js/[name].[hash:8].js',
chunkFilename: 'js/chunk-[chunkhash:8].[id].js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: file => (
/node_modules/.test(file) &&
!/\.vue\.js/.test(file)
)
},
{
test: /\.css$/,
use: cssConfig
},
{
test: /\.scss$/,
use: scssConfig
},
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
test: /\.(png|jpe?g|gif|bmp|svg)$/,
use: [{
loader: 'url-loader',
options: { // 配置图片编译路径
limit: 8192, // 小于8k将图片转换成base64
name: '[name].[hash:8].[ext]',
outputPath: 'images/'
}
}, {
loader: 'image-webpack-loader', // 图片压缩
options: {
bypassOnDebug: true
}
}]
},
{
test: /\.html$/,
use: [{
loader: 'html-loader',
options: { // 配置html中图片编译
minimize: true
}
}]
},
{
test: /\.(mp4|ogg|svg)$/,
use: ['file-loader']
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 8192,
name: 'fonts/[hash:8].[name].[ext]'
}
}
]
},
plugins: [
new VueLoaderPlugin(), // vue加载器
new HtmlWebpackPlugin({ // 处理模板
title: '',
filename: 'index.html',
template: 'start.ejs',
inject: true,
minify: { // 对index.html压缩
collapseWhitespace: isProd, // 去掉index.html的空格
removeAttributeQuotes: isProd // 去掉引号
}
// hash: true // 去掉上次浏览器的缓存(使浏览器每次获取到的是最新的html)
}),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}
}),
new MiniCssExtractPlugin({ // 分离css
filename: 'css/[name].[hash:8].css',
chunkFilename: 'css/chunk-[hash:8].[id].css',
allChunks: true
}),
new webpack.ProvidePlugin({ // 配置第三方库
$http: 'axios' // 在.vue文件中可以使用$http发送请求,不用每次都import Axios from 'axios';也不用挂载到vue原型链上
}),
new FriendlyErrorsWebpackPlugin() // 识别某些类别的webpack错误,并清理,聚合和优先级
],
resolve: {
extensions: ['.js', '.vue', '.json', '.scss', '.less'], // import引入文件的时候不用加后缀
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': path.resolve(__dirname, '../src'),
'component': path.resolve(__dirname, '../src/component'),
'container': path.resolve(__dirname, '../src/container'),
}
},
node: {
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
}
}
2、webpack.dev.conf.js
这个文件主要配置的是开发环境的依赖包括devServer,方便调试以及排错
const webpack = require('webpack');
const path = require('path');
const WebPackBaseConfig = require('./webpack.base.conf.js');
const { merge } = require('webpack-merge');
module.exports = merge(WebPackBaseConfig, {
devtool: 'inline-source-map',
devServer: {
historyApiFallback: true,
disableHostCheck: true,
// contentBase: path.join(__dirname, ''), // 将 当前目录下的文件,作为可访问文件。
compress: true, // 开启Gzip压缩
host: '0.0.0.0', // 设置服务器的ip地址,默认localhost
port: 3008, // 端口号
hot: true,
quiet: true,
inline: false,
open: true, // 自动打开浏览器
openPage: 'xxx' // 自动打开浏览器的url
},
plugins: [
new webpack.HotModuleReplacementPlugin(), //启用热替换模块
new webpack.NamedModulesPlugin() //启用HMR时,插件将显示模块的相对路径
]
})
3、webpack.prod.conf.js
这个文件是生产环境的配置,主要对编译做了一些优化,如:css编译,tree-shaking,js压缩混淆
const webpack = require('webpack');
const path = require('path');
const { merge } = require('webpack-merge');
const WebPackBaseConfig = require('./webpack.base.conf.js');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const glob = require('glob-all');
// const PurifyCSSPlugin = require('purifycss-webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = merge(WebPackBaseConfig, {
stats: {
assets: true, // 显示资产信息
assetsSort: 'name', // 通过name排序
chunksSort: 'name', // chunk 通过name排序
entrypoints: false, // 禁止告诉stats是否显示带有相应捆绑商品的入口点
modules: false // 禁止打印 指示stats是否添加有关已构建模块的信息。
},
optimization: {
splitChunks: {
cacheGroups: {// 这里开始设置缓存的 chunks
vendor: { // key 为entry中定义的 入口名称
chunks: 'initial', // 必须三选一: "initial" | "all" | "async"(默认就是异步)
test: /node_modules/, // 正则规则验证,如果符合就提取 chunk (指定是node_modules下的第三方包)
name: 'vendor', // 要缓存的 分隔出来的 chunk 名称
minChunks: 1,
enforce: true
},
styles: {
chunks: 'all',
test: /\.(css|scss)$/,
name: 'vendor',
minChunks: 1,
enforce: true
}
}
},
minimize: true, // 告诉webpack使用TerserPlugin或中指定的插件最小化捆绑optimization.minimizer
minimizer: [ // js css打包压缩
(compiler) => {
const TerserPlugin = require('terser-webpack-plugin'); // js压缩优化 用terser-webpack-plugin替换掉uglifyjs-webpack-plugin解决uglifyjs不支持es6语法问题
new TerserPlugin({
parallel: true, // 使用多进程并行运行可提高构建速度。并发运行的默认次数:os.cpus().length - 1
sourceMap: true,
extractComments: false, //禁止提取注释到LICENSE.txt文件中
terserOptions: {
compress: {
pure_funcs: ["console.log"] // 去除console.log打印信息
}
}
}).apply(compiler);
},
new OptimizeCSSAssetsPlugin({})
]
},
plugins: [
new CleanWebpackPlugin({ //清理文件夹
cleanOnceBeforeBuildPatterns: ['js', 'css', 'images', '*.html']
}),
// new PurifyCSSPlugin({
// paths: glob.sync([ // css tree shaking 移除项目中我们没有用到css代码,减小css的打包体积
// path.join(path.resolve(__dirname,"../src/*."))
// ])
// })
]
})
4、根目录创建.babelrc ,编译es6
{
"presets": ["@babel/preset-env"],
"plugins": [
"@babel/plugin-transform-runtime",
"@babel/plugin-proposal-class-properties",
["import", {
"libraryName": "vant",
"libraryDirectory": "es",
"style": true
}]
]
}
5、根目录创建postcss.config.js,解析scss
module.exports = {
loader: 'postcss-loader',
plugins: [
require('autoprefixer')
]
}
6、根目录创建start.ejs,以ejs为模板
<%= htmlWebpackPlugin.options.title %>
7、package.json配置
{
"name": "xxx",
"description": "xx",
"version": "1.0.0",
"author": "[email protected]",
"private": true,
"scripts": {
"start": "cross-env NODE_ENV=development webpack-dev-server --config ./build/webpack.dev.conf.js",
"build": "cross-env NODE_ENV=production webpack --config ./build/webpack.prod.conf.js"
},
"dependencies": {
"axios": "^0.19.2",
"babel-preset-es2015": "^6.24.1",
"better-scroll": "^1.15.2",
"es6-promise": "^4.2.8",
"vue": "^2.6.11",
"vue-router": "^3.3.4",
"vuex": "^3.5.1"
},
"devDependencies": {
"@babel/core": "^7.10.4",
"@babel/plugin-transform-runtime": "^7.10.4",
"@babel/polyfill": "^7.10.4",
"@babel/preset-env": "^7.10.4",
"@babel/runtime": "^7.10.4",
"autoprefixer": "^9.8.4",
"babel-loader": "^8.1.0",
"babel-plugin-import": "^1.13.0",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-plugin-transform-remove-console": "^6.9.4",
"clean-webpack-plugin": "^3.0.0",
"cross-env": "^7.0.2",
"css-loader": "^3.6.0",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^6.0.0",
"friendly-errors-webpack-plugin": "^1.7.0",
"glob-all": "^3.2.1",
"html-webpack-plugin": "^4.3.0",
"image-webpack-loader": "^6.0.0",
"less": "^3.12.2",
"less-loader": "^6.2.0",
"mini-css-extract-plugin": "^0.9.0",
"node-sass": "^4.14.1",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-loader": "^3.0.0",
"purify-css": "^1.2.5",
"purifycss-webpack": "^0.7.0",
"rimraf": "^3.0.2",
"sass-loader": "^9.0.1",
"terser-webpack-plugin": "^3.0.6",
"url-loader": "^4.1.0",
"vue-loader": "^15.9.3",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.11",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^5.0.7"
}
}