vue-cli
及诸多脚手架生成的项目里, 配置项非常繁琐, 结构也非常混乱, 实际上 webpack 常规配置就需要两个, 分别给开发环境和产品环境使用.
而且像 webpack-merge
这样的插件, 可以通过简单的 Object.assign
或 [].concat
完成.
示例:
base.js
基础设置:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: path.resolve(__dirname, '../src/main.js'),
output: {
path: path.resolve(__dirname, '../dist'),
publicPath: '/',
filename: '[name].[hash].js',
chunkFilename: '[id].[hash].js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
extractCSS: true
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
extensions: ['.js', '.json', '.vue'],
alias: {
vue$: 'vue/dist/vue.esm.js'
}
},
performance: {
hints: false
},
plugins: [
new ExtractTextPlugin('style.css'),
new HtmlWebpackPlugin({
filename: path.resolve(__dirname, '../dist/index.html'),
template: path.resolve(__dirname, '../index.html'),
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency'
})
]
};
dev 配置:
const base = require('./base');
module.exports = Object.assign({}, base, {
devtool: '#eval-source-map',
devServer: {
historyApiFallback: true,
noInfo: true
}
});
prod 配置:
const webpack = require('webpack');
const base = require('./base');
module.exports = Object.assign({}, base, {
devtool: '#source-map',
devServer: {
historyApiFallback: true,
noInfo: true
},
plugins: (base.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
});
preset-latest
或 preset-2015
之类的东西, 谨慎添加. 慢慢必要性也不会太大.
module.exports = {
presets: [['env', { modules: false }]],
plugins: ['transform-runtime'],
comments: false
};
这里是我用的配置:
module.exports = {
root: true,
env: {
browser: true,
es6: true,
node: true
},
extends: ['dwing'],
plugins: ['html', 'vue'],
rules: {
'no-new': 0,
'no-bitwise': 0,
'import/extensions': ['error', 'always', { js: 'never', vue: 'never' }],
'import/no-extraneous-dependencies': 0
},
settings: {
'import/resolver': {
webpack: {
config: './config/base.js'
}
}
}
};
在 vscode 下默认是无法对 .vue
文件进行 autofix 的.
需要注意其中的两个插件, 一个是eslint-plugin-html
, 一个是eslint-plugin-vue
, 同时要修改 vscode 的配置 eslint.validate
, 参考:
// 将设置放入此文件中以覆盖默认设置
{
"editor.tabSize": 2,
"[vue]": {
"editor.formatOnSave": true
},
"eslint.autoFixOnSave": true,
"eslint.validate": [
"javascript",
"javascriptreact",
{ "language": "vue", "autoFix": true },
{ "language": "html", "autoFix": true }
]
}
根据项目来权衡,是否需要进行服务器端渲染(SSR).
本项目中采用前后端完全分离的做法, 后端将直接透传前端相关的请求. 目前市面上大多数 devServer 都是用 express 框架做的,而实际项目中用到 express 的可能性小之又小. 找了很久 koa 相关的,都无法跑通,这里我就自己搞了一个能够在 koa 上进行开发运行的方法.
使用 Stream PassThrough
将请求结果转发到前端 webpack-dev-server
const { PassThrough } = require('stream');
router.get('/', (ctx) => {
ctx.set('Content-Type', 'text/html');
// webpack-dev-server 端口 9000
ctx.body = request.get('http://localhost:9000/index.html').pipe(PassThrough());
});
router.get('/(.*)', async (ctx) => {
const path = ctx.path.split('.').reverse();
if (path.length > 0) {
const type = path[0];
switch (type) {
case 'css': {
ctx.set('Content-Type', 'text/css');
break;
}
case 'js': {
ctx.set('Content-Type', 'text/javascript');
break;
}
case 'jpg': {
ctx.set('Content-Type', 'image/jpeg');
break;
}
case 'png': {
ctx.set('Content-Type', 'image/png');
break;
}
default: {
ctx.set('Content-Type', 'text/plain');
}
}
}
ctx.body = request.get(`http://localhost:9000${ctx.path}`).pipe(PassThrough());
});
唯一的不足就是, PassThough
默认的 mime 是 application/octet-stream
需要手动替换头信息.
koa-send
就可以满足:
const send = require('koa-send');
router.get('/(.*)', async (ctx) => {
try {
await send(ctx, '/index.html', { root: path.resolve(__dirname, '../dist') });
} catch (e) {}
});
router.get('/(.*)', async (ctx) => {
try {
await send(ctx, ctx.path, { root: path.resolve(__dirname, '../dist') });
} catch (e) {}
});