项目结构示意图

webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const vueLoaderPlugin = require('vue-loader/lib/plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const webpack = require('webpack')
const HappyPack = require('happypack')
const os = require('os')
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length })
function resolve(dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
entry: path.resolve(__dirname, '../src/main.js'),
output: {
filename: 'js/[name].[hash:8].js',
path: path.resolve(__dirname, '../dist'),
chunkFilename: 'js/[name].[hash:8].js',
publicPath: './'
},
externals: {},
module: {
rules: [
{
test: /\.vue$/,
use: [{
loader: 'vue-loader',
options: {
compilerOptions: {
preserveWhitespace: false
}
}
}]
},
{
test: /\.js$/,
use: ['happypack/loader?id=happyBabel'],
exclude: /node_modules/,
include: [resolve('src'), resolve('node_modules/webpack-dev-server/client')]
},
{
test: /\.(jpe?g|png|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 10240,
fallback: {
loader: 'file-loader',
options: {
name: 'img/[name].[hash:8].[ext]',
publicPath: '../'
}
}
}
}
]
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10240,
fallback: {
loader: 'file-loader',
options: {
name: 'media/[name].[hash:8].[ext]',
publicPath: '../'
}
}
}
}
]
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 10240,
fallback: {
loader: 'file-loader',
options: {
name: 'font/[name].[hash:8].[ext]',
publicPath: '../'
}
}
}
}
]
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
},
extensions: ['.js', '.vue', '.json'],
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html')
}),
new HappyPack({
id: 'happyBabel',
loaders: ['babel-loader?cacheDirectory'],
threadPool: happyThreadPool
}),
new vueLoaderPlugin(),
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, '../public'),
to: path.resolve(__dirname, '../dist')
}
]
}),
]
}
webpack.dev.js
const merge = require('webpack-merge')
const webpack = require('webpack')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') //更好的看到webpack警告和错误
const devConfig = merge(webpackConfig, {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
devServer: {
compress: true,
host: "192.168.31.71",
port: 8080,
quiet:true,
hot: true,
inline: true,
hotOnly: true, //当编译失败时,不刷新页面
overlay: true, //用来在编译出错的时候,在浏览器页面上显示错误
publicPath: '/', //一定要加
open: true,
proxy: {
// '/api': 'http://localhost:8080'
},
watchOptions: {
// 不监听的文件或文件夹,支持正则匹配
ignored: /node_modules/,
// 监听到变化后等1s再去执行动作
aggregateTimeout: 1000,
// 默认每秒询问1000次
poll: 1000
}
},
module: {
rules: [
{
test: /\.css$/,
use: ['vue-style-loader', 'css-loader', 'postcss-loader'],
},
{
test: /\.scss$/,
use: ['vue-style-loader', 'css-loader', 'postcss-loader', 'sass-loader'],
exclude: /node_modules/
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new FriendlyErrorsPlugin({
compilationSuccessInfo: {
messages: [`Your application is running here: http://localhost:8080`],
}
}),
new webpack.DefinePlugin({
'env':JSON.stringify(process.env.NODE_ENV)
})
]
})
module.exports = devConfig
webpack.prod.js
const webpackConfig = require('./webpack.config')
const merge = require('webpack-merge')
const webpack = require('webpack')
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
const optimizeCss = require('optimize-css-assets-webpack-plugin');
function resolve(dir) {
return path.join(__dirname, '..', dir)
}
const prodConfig = merge(webpackConfig, {
mode: "production",
devtool: 'none',
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendors: {
name: 'vendors',
test: /[\\\/]node_modules[\\\/]/,
priority: -10,
chunks: 'initial'
},
common: {
name: 'chunk-common',
minChunks: 2,
priority: -20,
chunks: 'initial',
reuseExistingChunk: true
}
}
},
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
}
}, 'css-loader', 'postcss-loader'],
},
{
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
}
}, 'css-loader', 'postcss-loader', 'sass-loader'],
exclude: /node_modules/
}
]
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: 'css/[name].[hash].css',
chunkFilename: 'css/[name].[hash].css',
}),
new HardSourceWebpackPlugin(),
new optimizeCss({
cssProcessor: require('cssnano'),
cssProcessorOptions: {
discardComments: { removeAll: true }
},
canPrint: true
}),
new webpack.DefinePlugin({
'env':JSON.stringify(process.env.NODE_ENV)
})
]
})
module.exports = prodConfig
zip.js
var fs = require("fs")
var archiver = require("archiver")
var path = require("path")
var output = fs.createWriteStream("./dist.zip")
var output_path = path.normalize(__dirname + '/../dist.zip')
var archive = archiver('zip',{
zlib:{level:9}
})
archive.pipe(output)
archive.directory('dist/',false)
archive.finalize()
.babelrc
{
"presets": [
"@babel/preset-env"
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"helpers": true,
"regenerator": true,
"useESModules": false,
"corejs": 2
}
]
]
}
.browserslistrc
> 1%
last 2 versions
not ie <= 8
package.json
{
"name": "webpack-vue",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.dev.js",
"build:dev": "cross-env NODE_ENV=production webpack --config build/webpack.prod.js",
"build:prod": "cross-env NODE_ENV=production webpack --config build/webpack.prod.js",
"pkg": "node build/zip.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.10.2",
"@babel/plugin-transform-runtime": "^7.10.1",
"@babel/preset-env": "^7.10.2",
"@vue/test-utils": "^1.0.3",
"archiver": "^5.1.0",
"autoprefixer": "^9.8.0",
"babel-core": "7.0.0-bridge.0",
"babel-jest": "^26.0.1",
"babel-loader": "^8.1.0",
"clean-webpack-plugin": "^3.0.0",
"compression-webpack-plugin": "^4.0.0",
"copy-webpack-plugin": "^6.0.2",
"cross-env": "^7.0.3",
"css-loader": "^3.5.3",
"cssnano": "^4.1.10",
"file-loader": "^6.0.0",
"friendly-errors-webpack-plugin": "^1.7.0",
"happypack": "^5.0.1",
"hard-source-webpack-plugin": "^0.13.1",
"html-webpack-plugin": "^4.3.0",
"jest": "^26.0.1",
"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",
"sass-loader": "^8.0.2",
"sass-resources-loader": "^2.0.3",
"style-loader": "^1.2.1",
"url-loader": "^4.1.0",
"vue-jest": "^3.0.5",
"vue-loader": "^15.9.2",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.11",
"webpack": "^4.43.0",
"webpack-bundle-analyzer": "^3.8.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^4.2.2"
},
"dependencies": {
"@babel/polyfill": "^7.10.1",
"@babel/runtime": "^7.10.2",
"@babel/runtime-corejs2": "^7.10.2",
"core-js": "^2.6.11",
"element-ui": "^2.14.1",
"vue": "^2.6.11",
"vue-router": "^3.3.2"
}
}
postcss.config.js
module.exports = {
plugins: [require('autoprefixer')]
}