|
@@ -0,0 +1,278 @@
|
|
|
|
+const path = require('path');
|
|
|
|
+const webpack = require('webpack');
|
|
|
|
+const HtmlWebpackPlugin = require('html-webpack-plugin'); // 自动生成index.html
|
|
|
|
+const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 文本分离插件,分离js和css
|
|
|
|
+const { CleanWebpackPlugin } = require('clean-webpack-plugin'); // 清理垃圾文件
|
|
|
|
+const CopyWebpackPlugin = require('copy-webpack-plugin');
|
|
|
|
+
|
|
|
|
+const WebpackBar = require('webpackbar');
|
|
|
|
+
|
|
|
|
+const VueLoaderPlugin = require('vue-loader/lib/plugin'); // vue加载器
|
|
|
|
+
|
|
|
|
+const HardSourceWebpackPlugin = require('hard-source-webpack-plugin'); // 为模块提供中间缓存,缓存默认的存放路径是: node_modules/.cache/hard-source
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * 判断是生产环境还是开发环境
|
|
|
|
+ * @type {boolean}
|
|
|
|
+ * isProd为true表示生产
|
|
|
|
+ */
|
|
|
|
+const isProd = process.env.NODE_ENV === 'production';
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+// 获取本机ip
|
|
|
|
+const getIp = require('./get_ip')();
|
|
|
|
+
|
|
|
|
+// 获取时间
|
|
|
|
+const TimeFn = require('./get_time');
|
|
|
|
+
|
|
|
|
+console.log(
|
|
|
|
+ `
|
|
|
|
+ _ooOoo_
|
|
|
|
+ o8888888o
|
|
|
|
+ 88" . "88
|
|
|
|
+ (| -_- |)
|
|
|
|
+ O\\ = /O
|
|
|
|
+ ____/\`---'\\____
|
|
|
|
+ .' \\\\| |// \`.
|
|
|
|
+ / \\\\||| : |||// \\
|
|
|
|
+ / _||||| -:- |||||- \\
|
|
|
|
+ | | \\\\\\ - /// | |
|
|
|
|
+ | \\_| ''\\---/'' | |
|
|
|
|
+ \\ .-\\__ \`-\` ___/-. /
|
|
|
|
+ ___\`. .' /--.--\\ \`. . __
|
|
|
|
+ ."" '< \`.___\\_<|>_/___.' >'"".
|
|
|
|
+ | | : \`- \\\`.;\`\\ _ /\`;.\`/ - \` : | |
|
|
|
|
+ \\ \\ \`-. \\_ __\\ /__ _/ .-\` / /
|
|
|
|
+======\`-.____\`-.___\\_____/___.-\`____.-'======
|
|
|
|
+ \`=---='
|
|
|
|
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
+ 佛祖保佑 永无BUG
|
|
|
|
+ ${TimeFn()}
|
|
|
|
+ `
|
|
|
|
+);
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * css和stylus开发、生产依赖
|
|
|
|
+ * 生产分离css
|
|
|
|
+ */
|
|
|
|
+const cssConfig = [
|
|
|
|
+ isProd ? MiniCssExtractPlugin.loader : 'vue-style-loader',
|
|
|
|
+ 'thread-loader',
|
|
|
|
+ {
|
|
|
|
+ loader: 'css-loader',
|
|
|
|
+ options: {
|
|
|
|
+ sourceMap: !isProd
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ 'postcss-loader'
|
|
|
|
+];
|
|
|
|
+const stylusConfig = [
|
|
|
|
+ isProd ? MiniCssExtractPlugin.loader : 'vue-style-loader',
|
|
|
|
+ 'thread-loader',
|
|
|
|
+ {
|
|
|
|
+ loader: 'css-loader',
|
|
|
|
+ options: {
|
|
|
|
+ sourceMap: !isProd
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ loader: 'stylus-loader',
|
|
|
|
+ options: {
|
|
|
|
+ sourceMap: !isProd
|
|
|
|
+ }
|
|
|
|
+ }, {
|
|
|
|
+ loader: 'style-resources-loader',
|
|
|
|
+ options: {
|
|
|
|
+ injector: 'prepend',
|
|
|
|
+ patterns: path.resolve(__dirname, 'src/assets/stylus/variables.styl')
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+];
|
|
|
|
+
|
|
|
|
+const config = {
|
|
|
|
+ entry: {
|
|
|
|
+ index: isProd ? ['core-js/stable', 'regenerator-runtime/runtime', './src/main.js'] : './src/main.js' // 入口文件
|
|
|
|
+ // index: ['core-js/stable', 'regenerator-runtime/runtime', './src/main.js'], // 入口文件
|
|
|
|
+ },
|
|
|
|
+ output: {
|
|
|
|
+ path: path.resolve(__dirname, 'production'),
|
|
|
|
+ filename: isProd ? 'javascript/[name].[hash:8].js' : '[name].js', // [name] 是entry的key
|
|
|
|
+ publicPath: isProd ? './' : '/'
|
|
|
|
+ // publicPath: './',
|
|
|
|
+ },
|
|
|
|
+ module: {
|
|
|
|
+ rules: [
|
|
|
|
+ {
|
|
|
|
+ test: /\.css$/,
|
|
|
|
+ use: cssConfig
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ test: /\.styl(us)?$/,
|
|
|
|
+ use: stylusConfig,
|
|
|
|
+ include: [path.resolve(__dirname, 'src')]
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ test: /\.vue$/,
|
|
|
|
+ use: [
|
|
|
|
+ 'thread-loader', 'cache-loader',
|
|
|
|
+ {
|
|
|
|
+ loader: 'vue-loader',
|
|
|
|
+ options: {
|
|
|
|
+ loaders: {
|
|
|
|
+ css: cssConfig,
|
|
|
|
+ stylus: stylusConfig
|
|
|
|
+ },
|
|
|
|
+ preserveWhitespace: false // 不要留空白
|
|
|
|
+ }
|
|
|
|
+ }],
|
|
|
|
+ include: [path.resolve(__dirname, 'src')]
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ test: /\.js$/,
|
|
|
|
+ use: [
|
|
|
|
+ 'thread-loader', 'cache-loader',
|
|
|
|
+ {
|
|
|
|
+ loader: 'babel-loader',
|
|
|
|
+ options: {
|
|
|
|
+ cacheDirectory: !isProd
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ ],
|
|
|
|
+ exclude: (file) => (
|
|
|
|
+ /node_modules/.test(file) && !/\.vue\.js/.test(file)
|
|
|
|
+ )
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ test: /\.svg$/,
|
|
|
|
+ use: ['thread-loader', 'babel-loader', 'vue-svg-loader'],
|
|
|
|
+ include: [path.resolve(__dirname, 'src')]
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ test: /\.(png|jpe?g|gif|bmp)$/,
|
|
|
|
+ use: [
|
|
|
|
+ {
|
|
|
|
+ loader: 'url-loader',
|
|
|
|
+ options: { // 配置图片编译路径
|
|
|
|
+ limit: 8192, // 小于8k将图片转换成base64
|
|
|
|
+ name: '[name].[ext]?[hash:8]',
|
|
|
|
+ outputPath: 'images/'
|
|
|
|
+ }
|
|
|
|
+ }],
|
|
|
|
+ include: [path.resolve(__dirname, 'src')]
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ test: /\.html$/,
|
|
|
|
+ use: [{
|
|
|
|
+ loader: 'html-loader',
|
|
|
|
+ options: { // 配置html中图片编译
|
|
|
|
+ minimize: true,
|
|
|
|
+ attributes: false
|
|
|
|
+ }
|
|
|
|
+ }]
|
|
|
|
+ }
|
|
|
|
+ ]
|
|
|
|
+ },
|
|
|
|
+ resolve: { // 配置路径别名
|
|
|
|
+ extensions: ['.js', '.vue', '.styl'], // import引入文件的时候不用加后缀
|
|
|
|
+ modules: [
|
|
|
|
+ 'node_modules',
|
|
|
|
+ path.resolve(__dirname, 'src/assets'),
|
|
|
|
+ path.resolve(__dirname, 'src/docs'),
|
|
|
|
+ path.resolve(__dirname, 'src/utils')
|
|
|
|
+ ]
|
|
|
|
+ },
|
|
|
|
+ plugins: [
|
|
|
|
+ new webpack.BannerPlugin(`@meri-design ${TimeFn()}`),
|
|
|
|
+ new HardSourceWebpackPlugin(),
|
|
|
|
+ new VueLoaderPlugin(), // vue加载器
|
|
|
|
+ new CopyWebpackPlugin([{
|
|
|
|
+ from: path.resolve(__dirname, 'node_modules/vue/dist/vue.min.js'),
|
|
|
|
+ to: 'modules'
|
|
|
|
+ }, {
|
|
|
|
+ from: path.resolve(__dirname, 'node_modules/vuex/dist/vuex.min.js'),
|
|
|
|
+ to: 'modules'
|
|
|
|
+ }, {
|
|
|
|
+ from: path.resolve(__dirname, 'node_modules/vue-router/dist/vue-router.min.js'),
|
|
|
|
+ to: 'modules'
|
|
|
|
+ }]),
|
|
|
|
+ new HtmlWebpackPlugin({
|
|
|
|
+ template: path.join(__dirname, 'src/index.html'), // 引入模版
|
|
|
|
+ favicon: path.join(__dirname, 'src/assets/favicon.ico'),
|
|
|
|
+ filename: 'index.html',
|
|
|
|
+ minify: { // 对index.html压缩
|
|
|
|
+ collapseWhitespace: isProd, // 去掉index.html的空格
|
|
|
|
+ removeAttributeQuotes: isProd // 去掉引号
|
|
|
|
+ },
|
|
|
|
+ hash: true, // 去掉上次浏览器的缓存(使浏览器每次获取到的是最新的html)
|
|
|
|
+ // ,chunks:['vendor','main'] // 在产出的html文件里面引入哪些代码块,里面的名字要跟entry里面key对应(一般用于多文件入口)
|
|
|
|
+ inlineSource: '.(js|css)'
|
|
|
|
+ }),
|
|
|
|
+ new WebpackBar({
|
|
|
|
+ color: '#0091ff'
|
|
|
|
+ })
|
|
|
|
+ ],
|
|
|
|
+ externals: {
|
|
|
|
+ vue: 'Vue',
|
|
|
|
+ vuex: 'Vuex',
|
|
|
|
+ 'vue-router': 'VueRouter'
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+if (isProd) {
|
|
|
|
+ config.plugins.push(
|
|
|
|
+ new CleanWebpackPlugin({
|
|
|
|
+ verbose: true, // 打印被删除的文件
|
|
|
|
+ protectWebpackAssets: false, // 允许删除cleanOnceBeforeBuildPatterns中的文件
|
|
|
|
+ cleanOnceBeforeBuildPatterns: ['**/*', path.resolve(__dirname, 'production')]
|
|
|
|
+ }),
|
|
|
|
+ new MiniCssExtractPlugin({ // 分离css
|
|
|
|
+ filename: 'stylesheets/[name].[contenthash:8].css'
|
|
|
|
+ // chunkFilename: isProd?'stylesheets/[name].[contenthash:8].css':'[name].css'
|
|
|
|
+ })
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ config.optimization = { // 抽离第三方插件
|
|
|
|
+ splitChunks: {
|
|
|
|
+ chunks: 'all', // 必须三选一: "initial" | "all" | "async"(默认就是异步)
|
|
|
|
+ minSize: 10000, // 提高缓存利用率,这需要在http2/spdy
|
|
|
|
+ maxSize: 0, // 没有限制
|
|
|
|
+ minChunks: 3, // 共享最少的chunk数,使用次数超过这个值才会被提取
|
|
|
|
+ maxAsyncRequests: 5, // 最多的异步chunk数
|
|
|
|
+ maxInitialRequests: 5, // 最多的同步chunks数
|
|
|
|
+ name: true,
|
|
|
|
+ cacheGroups: { // 这里开始设置缓存的 chunks
|
|
|
|
+ vendor: { // key 为entry中定义的 入口名称,new webpack.ProvidePlugin中的库
|
|
|
|
+ test: /node_modules/, // 正则规则验证,如果符合就提取 chunk (指定是node_modules下的第三方包)
|
|
|
|
+ name: 'vendor', // 要缓存的 分隔出来的 chunk 名称
|
|
|
|
+ enforce: true
|
|
|
|
+ },
|
|
|
|
+ styles: {
|
|
|
|
+ test: /src\.(css|styl)$/,
|
|
|
|
+ name: 'main',
|
|
|
|
+ enforce: true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ runtimeChunk: { name: 'manifest' } // 为每个入口提取出webpack runtime模块
|
|
|
|
+ };
|
|
|
|
+} else {
|
|
|
|
+ config.devtool = 'source-map'; // 如果只用source-map开发环境出现错误定位源文件,生产环境会生成map文件
|
|
|
|
+ config.devServer = {
|
|
|
|
+ contentBase: path.join(__dirname, 'production'), // 将 dist 目录下的文件,作为可访问文件。
|
|
|
|
+ compress: true, // 开启Gzip压缩
|
|
|
|
+ // , host: 'localhost' // 设置服务器的ip地址,默认localhost
|
|
|
|
+ host: getIp, // 设置服务器的ip地址,默认localhost
|
|
|
|
+ port: 3002, // 端口号
|
|
|
|
+ open: true, // 自动打开浏览器
|
|
|
|
+ hot: true,
|
|
|
|
+ overlay: { // 当出现编译器错误或警告时,就在网页上显示一层黑色的背景层和错误信息
|
|
|
|
+ errors: true
|
|
|
|
+ },
|
|
|
|
+ disableHostCheck: true // 不检查主机
|
|
|
|
+ // historyApiFallback: { // 当使用 HTML5 History API 时,任意的 404 响应都可能需要被替代为 /
|
|
|
|
+ // rewrites: [{ from: /./, to: '/' }]
|
|
|
|
+ // }
|
|
|
|
+ };
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+module.exports = config;
|