vue.config.js 9.08 KB
/* jshint esversion: 6 */
const path = require('path');
const webpack = require('webpack');
const CompressionWebpackPlugin = require('compression-webpack-plugin');

const assetsDir = 'static';
const resolve = dir => path.join(__dirname, dir);

// posix兼容方式处理路径
const posixJoin = _path => path.posix.join(assetsDir, _path);

const lastVersion = new Date().getTime();
const isProd = process.env.NODE_ENV === 'production';

// dns预加载,优化接口请求
const dnsPrefetch = [
  'https://cdn.jsdelivr.net',
  'https://cdn.bootcss.com'
];

// cdn预加载使用
const externals = {
  'vue': 'Vue',
  'vue-router': 'VueRouter',
  'vuex': 'Vuex',
  'axios': 'axios',
  'vant': 'vant',
  '$': 'jquery',
  'jquery': 'Jquery',
  'moment': 'moment',
  '_': 'lodash',
  'Fastclick': 'fastclick'
};

const cdn = {
  // 开发环境
  dev: {
    css: [],
    js: []
  },
  // 生产环境
  build: {
    css: [
      // 'https://cdn.jsdelivr.net/npm/vant@1.5/lib/index.css'
      'http://boh.onwall.cn/vant@1.5/lib/index.css'
    ],
    js: [
      'https://cdn.bootcss.com/vue/2.5.21/vue.min.js',
      'https://cdn.bootcss.com/vue-router/3.0.2/vue-router.min.js',
      'https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js',
      'https://cdn.bootcss.com/axios/0.18.0/axios.min.js',
      // 'https://cdn.jsdelivr.net/npm/vant@1.5/lib/vant.min.js',
      'http://boh.onwall.cn/vant@1.5/lib/vant.min.js',
      'https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js',
      'https://cdn.bootcss.com/moment.js/2.23.0/moment.min.js',
      'https://cdn.bootcss.com/lodash.js/4.17.11/lodash.core.min.js',
      // 'https://cdn.bootcss.com/lodash.js/4.17.11/lodash.min.js',
      'https://cdn.bootcss.com/fastclick/1.0.6/fastclick.min.js'
    ]
  }
};

// 是否使用gzip
const productionGzip = true;
// 需要gzip压缩的文件后缀
const productionGzipExtensions = ['js', 'css'];

// 多页模板页
var pages = {
  // 默认页
  index: {
    entry: 'src/index.js',
    template: 'public/index.html',
    filename: 'index.html',
    title: 'Index Page',
    chunks: ['chunk-vendors', 'chunk-common', 'index']
  }
};
var prod_custom = require('./config/prod-custom');
var dev_custom = require('./config/dev-custom');
function getEntryPages (array) {
  for (let i = 0; i < array.length; i++) {
    pages[array[i].page] = {
      // page 的入口
      entry: `src/multiPages/${array[i].page}/${array[i].page}.js`,
      // 模板来源
      template: `public/${array[i].page}.html`,
      // 在 dist/index.html 的输出
      filename: `${array[i].page}.html`,
      // 当使用 title 选项时,
      // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
      title: `${array[i].title}`,
      // 在这个页面中包含的块,默认情况下会包含
      // 提取出来的通用 chunk 和 vendor chunk。
      chunks: ['chunk-vendors', 'chunk-common', array[i].page]
    };
  }
  return pages;
}
if (process.env.NODE_ENV === 'production') {
  pages = getEntryPages(prod_custom);
}
if (process.env.NODE_ENV === 'development') {
  pages = getEntryPages(dev_custom);
}

module.exports = {
  // 基本路径
  publicPath: process.env.NODE_ENV === 'production' ? '/boh/' : '/',
  // 输出文件目录
  outputDir: 'dist',
  // 放置生成的静态资源的目录
  assetsDir,
  // 指定生成的 index.html 的输出路径 (相对于 outputDir)。也可以是一个绝对路径。
  // indexPath: 'index.html',
  filenameHashing: true,
  pages,
  // eslint-loader 是否在保存的时候检查
  lintOnSave: 'error',
  // 是否使用包含运行时编译器的 Vue 构建版本。设置为 true 后你就可以在 Vue 组件中使用 template 选项了。
  runtimeCompiler: true,
  // 生产环境是否生成 sourceMap 文件
  productionSourceMap: false,
  // 如果这个值是一个对象,则会通过 webpack-merge 合并到最终的配置中。
  // 如果这个值是一个函数,则会接收被解析的配置作为参数。该函数及可以修改配置并不返回任何东西,也可以返回一个被克隆或合并过的配置版本。
  configureWebpack: config => {
    config.plugins.push(
      new webpack.ProvidePlugin({
        'vue': 'Vue',
        '$': 'jquery',
        'jQuery': 'jquery',
        '_': 'lodash',
        'axios': 'axios',
        'moment': 'moment'
      })
    );
    //
    config.resolve.extensions = ['.js', '.vue', '.json', '.less', '.css'];
    //
    // config.resolve.alias.assets = path.resolve(__dirname, './src/assets');
    // config.resolve.alias.components = path.resolve(__dirname, './src/components');
    // 修改webpack config, 使其不打包externals下的资源
    if (process.env.NODE_ENV === 'production') {
      // 生成环境执行task任务,写入版本号
      // const task = require('./task');
      // task.run(lastVersion);
      // 1. 生产环境npm包转CDN
      config.externals = externals;
      // 2. 构建时开启gzip,降低服务器压缩对CPU资源的占用,服务器也要相应开启gzip
      if (productionGzip) {
        config.plugins.push(
          new CompressionWebpackPlugin({
            test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
            threshold: 10240,
            minRatio: 0.8
          })
        );
      }
    }
    if (process.env.NODE_ENV === 'development') {
      // 1. 生产环境npm包转CDN
      config.externals = externals;
    }
  },
  // 是一个函数,会接收一个基于 webpack-chain 的 ChainableConfig 实例。允许对内部的 webpack 配置进行更细粒度的修改。
  chainWebpack: (config) => {
    /**
     * 删除懒加载模块的 prefetch preload,降低带宽压力
     */
    // config.plugins
    //   .delete('prefetch')
    //   .delete('preload');
    config.resolve.alias
      .set('vue$', 'vue/dist/vue.esm.js')
      .set('@', resolve('src'))
      .set('assets', resolve('src/assets'))
      .set('components', resolve('src/components'));
    // 清除警告
    config.performance
      .set('hints', false);
    // 将版本号写入环境变量
    config
      .plugin('define')
      .tap(args => {
        args[0].app_build_version = lastVersion;
        return args;
      });
    config
      .when(isProd, config =>
        // 生产环境js增加版本号
        config.output
          .set('filename', posixJoin(`js/${lastVersion}-[name].[chunkhash].js`))
          .set('chunkFilename', posixJoin(`js/${lastVersion}-[id].[chunkhash].js`))
      );
    /**
     * 添加CDN参数到htmlWebpackPlugin配置中, 详见public/index.html 修改
     * vue inspect --plugins 查询插件 使用pages会有多个html实例
     */
    config
      .plugin('html-index')
      .tap(args => {
        if (process.env.NODE_ENV === 'production') {
        }
        args[0].cdn = cdn.build;
        args[0].dnsPrefetch = dnsPrefetch;
        return args;
      })
      .end()
      .plugin('html-login')
      .tap(args => {
        if (process.env.NODE_ENV === 'production') {
        }
        args[0].cdn = cdn.build;
        args[0].dnsPrefetch = dnsPrefetch;
        return args;
      })
      .end();
  },
  // css相关配置
  css: {
    // 是否使用css分离插件 ExtractTextPlugin
    // 增加版本号
    extract: !isProd ? false : {
      filename: posixJoin(`css/${lastVersion}-[name].[contenthash:8].css`),
      chunkFilename: posixJoin(`css/${lastVersion}-[name].[contenthash:8].css`)
    },
    // 开启 CSS source maps?
    sourceMap: false,
    // css预设器配置项
    loaderOptions: {
      css: {
        // 这里的选项会传递给 css-loader
      },
      postcss: {
        // 这里的选项会传递给 postcss-loader
      }
    },
    // 默认情况下,只有 *.module.[ext] 结尾的文件才会被视作 CSS Modules 模块。设置为 true 后你就可以去掉文件名中的 .module 并将所有的 *.(css|scss|sass|less|styl(us)?) 文件视为 CSS Modules 模块。
    modules: false
  },
  // use thread-loader for babel & TS in production build
  // enabled by default if the machine has more than 1 cores
  parallel: require('os').cpus().length > 1,
  // PWA 插件相关配置
  // see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
  pwa: {},
  // webpack-dev-server 相关配置
  devServer: {
    open: false,
    // open: process.platform === 'darwin',
    host: '0.0.0.0',
    port: 8180,
    https: false,
    hotOnly: false,
    // 设置代理
    proxy: {
      'api': {
        filter: ['/op/', '/fi/', '/de/', '/st/', '/fr/', '/pr/', '/pu/', '/dl/', '/b/', '/t/', '/rpt/'],
        target: 'http://dev.kmlab.com/boh',
        // target: 'http://itomix-dev.kmlab.com/boh'
        changeOrigin: true,
        pathRewrite: {
          '^/(.*)': '/$1'
        },
        onProxyReq: function (proxyReq, req, res, options) {
          proxyReq.setHeader('X-Proxy-Host', req.header('host'));
          proxyReq.setHeader('X-Proxy-Request-URI', req.url);
        }
      }
    },
    before: app => {},
    overlay: {
      warnings: false,
      errors: true
    }
  },
  // 第三方插件配置
  pluginOptions: {
    // dll: {
    //   entry: ['vue', 'vue-route', 'vuex', 'axios', 'vant', 'moment', 'lodash', 'jquery']
    // }
  }
};