Vue-Webpack-Pc && 移动端
谁能想到这是一个广告!!
地址 github.com/jason-xiewe…
配置详情请看 webpack config.js
Vue + Vuex + vue-router + ElementUI + Axios
命令
-
① npm install 安装依赖包
-
② npm run serve 开启本地开发模式 localhost: 8080
-
③ npm run build 生产打包
-
⑤ npm run analyzer 进行包分析 localhost: 8888
优化打包速度 *
开启多线程打包 第三方组件单独打包 图片处理 *
多浏览器方案适配 ** 整合 polyfill
移动端方案适配 ** lib-flexible 库
// webpack.config.js
const path = require('path');
const webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const WebpackBundleAnalyzer = require('webpack-bundle-analyzer');
const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
const smp = new SpeedMeasureWebpackPlugin();
const isProd = process.env.NODE_ENV === 'production';
console.log(isProd, process.env.analyzer);
const config = {
entry: path.resolve(__dirname, './src/index.js'),
output: {
path: path.resolve(__dirname, './dist'),
filename: 'js/[name].[hash:4].js',
chunkFilename: 'js/[name].[chunkhash:6].js'
},
devServer: {
hot: true,
port: 8080,
open: true,
host: 'localhost',
compress: true,
useLocalIp: false,
contentBase: './dist',
clientLogLevel: 'error',
disableHostCheck: true,
historyApiFallback: true,
// overly: true,
proxy: {}
},
resolve: {
alias: {
vue$: 'vue/dist/vue.esm.js',
'@': path.resolve(__dirname, './src')
},
extensions: ['.js', '.json', '.vue', '.es6'],
modules: [path.resolve(__dirname, 'node_modules')],
mainFields: ['browser', 'module', 'main']
},
module: {
rules: [{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
include: path.resolve(__dirname, 'src'),
use: [{
loader: 'thread-loader',
options: {
workers: 4
}
},
{
loader: 'babel-loader',
options: {
cacheDirectory: true
}
}
// 'babel-loader?cacheDirectory=true'
]
},
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
use: [
isProd ? MiniCssExtractPlugin.loader : 'vue-style-loader',
'css-loader',
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
isProd ? MiniCssExtractPlugin.loader : 'vue-style-loader',
'css-loader',
'less-loader',
'postcss-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [{
loader: 'file-loader',
options: {
outputPath: './images'
}
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 65
},
optipng: {
enabled: false
},
pngquant: {
quality: [0.65, 0.90],
speed: 4
},
gifsicle: {
interlaced: false
},
webp: {
quality: 75
}
}
}
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [{
loader: 'file-loader',
options: {
outputPath: './font'
}
}]
}
]
},
optimization: {
splitChunks: {
name: true,
chunks: 'all',
minSize: 20000, // 20k
minChunks: 1,
maxAsyncRequests: 10,
maxInitialRequests: 3,
automaticNameDelimiter: '-',
cacheGroups: {
commons: {
name: 'vendor',
test: /[\\/]node_modules[\\/]/,
priority: 5,
chunks: 'initial'
},
vue: {
name: 'vue',
test: /[\\/]node_modules[\\/]vue[\\/]/,
priority: 10,
chunks: 'all'
},
elementUI: {
name: 'element-ui',
test: /[\\/]node_modules[\\/]element-ui[\\/]/,
priority: 9,
chunks: 'all'
},
lodash: {
name: 'lodash',
test: /[\\/]node_modules[\\/]lodash[\\/]/,
priority: 15,
chunks: 'async'
},
echarts: {
name: 'echarts',
test: /[\\/]node_modules[\\/]echarts[\\/]/,
priority: 20,
chunks: 'async'
},
axios: {
name: 'axios',
test: /[\\/]node_modules[\\/]axios[\\/]/,
priority: 25,
chunks: 'async'
},
moment: {
name: 'moment',
test: /[\\/]node_modules[\\/]moment[\\/]/,
priority: 30,
chunks: 'async'
}
}
},
minimizer: [
new TerserPlugin({
parallel: true,
cache: true
})
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, './public/index.html'),
title: 'vue',
favicon: path.resolve(__dirname, './public/favicon.ico'),
filename: 'index.html',
inject: true,
chunks: ['element-ui', 'vue', 'vendor', 'main'],
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false
}
}),
new OptimizeCSSAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano')
}),
new VueLoaderPlugin(),
new webpack.optimize.SplitChunksPlugin(),
new MiniCssExtractPlugin({
filename: "css/[name].[contenthash:6].css",
chunkFilename: "css/[name].css"
})
]
};
if (!isProd) {
config.devtool = 'source-map';
config.watch = true;
config.watchOptions = {
ignored: /node_modules/,
aggregateTimeout: 300,
poll: 300
};
config.module.rules.unshift({
test: /.(vue|js|jsx)$/,
use: [{
loader: 'eslint-loader',
options: {
formatter: require('eslint-friendly-formatter')
}
}],
enforce: 'pre',
exclude: /node_modules/,
include: [path.resolve(__dirname, 'src')]
});
} else {
config.plugins.push(new CleanWebpackPlugin(['dist']));
config.plugins.push(new HardSourceWebpackPlugin());
config.devtool = 'none';
config.watch = false;
}
if (process.env.analyzer) {
config.plugins.push(new WebpackBundleAnalyzer.BundleAnalyzerPlugin());
}
module.exports = smp.wrap(config);