当前位置:   article > 正文

vue-cli4创建的项目打包优化_config.optimization.usedexports

config.optimization.usedexports

1. 将vue、vuex、vue-router、axios、qs等改为引用cnd资源

默认是将这些都打包到vendor文件中,拆分后打包vendor会小很多
看一些文章里面写的’vue-router’: ‘Router’,发现不能用,必须得写成’vue-router’: ‘VueRouter’,
同理qs: ‘Qs’,后面的Qs也得用大写的,小写qs报错

1.1 vue.config.js 配置如下:
chainWebpack: config => {
	// 因为项目需要history/hash两种模式下打包,history模式才使用cdn引用,因此加了isHistory判断
	// const isHistory = process.env.VUE_APP_ROUTER === 'history' 
    config.when(isHistory && (process.env.NODE_ENV === 'production'), config => {
      // 使用externals设置排除项
      config.set('externals', {
        vue: 'Vue',
        'vue-router': 'VueRouter',
        axios: 'axios',
        vuex: 'Vuex',
        qs: 'Qs'
      })
    })
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
1.2 在项目用到这些引用的地方,进行同步修改,将引用注释掉(看有的文章说不注释也可以,试了下不行,不知道哪里的问题)

如main.js中

// import Vue from 'vue'
  • 1

router/index.js

// import Vue from 'vue'
// import VueRouter from 'vue-router'
import web from './web'
Vue.use(VueRouter)  // 注意这里要使用VueRouter  Vue.use不能去掉
// ....
  • 1
  • 2
  • 3
  • 4
  • 5

fetch.js 注释掉import axios from ‘axios’ 和 import qs from ‘qs’;,并且引用时将qs改为Qs

// import axios from 'axios'  
// import qs from 'qs';
// 创建axios实例,请求超时时间10秒
const SERVICE = axios.create({
  timeout: 20000
});
// 拦截器
SERVICE.interceptors.request.use(
  (config) => {
    if (config.method === 'post') {
      if(jsonStr.indexOf(config.data.action)>-1){
        config.data = config.data.data;
      }
      else{
        config.data = Qs.stringify(config.data.data);  // 将qs改为Qs
      }
    }
    config.headers.common['ClientType'] = process.env.VUE_APP_ROUTER === 'history' ? 'web' : 'app'
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
1.3 模板文件index.html中添加cdn链接
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
    <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=Zgvao4zZE6L1DYqiGocXjkSSULStabdQ" ></script>
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <link rel="stylesheet" name="theme" href="">
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue-router/2.8.1/vue-router.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.19.2/axios.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/vuex/3.6.2/vuex.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/qs/6.9.4/qs.min.js"></script>
    <title>title</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

2. package.json 中配置sideEffects,只打包用到的模块

通过webpack的tree shaking,未使用模块检测能力。新的 webpack 4 正式版本扩展了此检测能力。
webpack文档:tree shaking
如果项目没有影响,可以直接设置:“sideEffects”: false, 但修改后发现页面样式受影响了
文档中提到应该将css文件排除检测,于是改为:

"sideEffects": ["*.css"],
  • 1

但是我自己写的公用样式还是没加载进来,发现是.styl格式的,于是再加入

"sideEffects": ["*.css", "*.styl"],
  • 1

但是.vue页面中写的样式还是没出现,于是:

"sideEffects": ["*.css", "*.styl", "*.vue"]
  • 1

这样,样式就可以正常显示了
后来测试发现,有部分js也受影响了
因为在main.js中这样引入了validator和draggable,但是打包时被扔掉了

import '@/validator'
import '@/draggable'
  • 1
  • 2

因此需要将其排除

"sideEffects": ["*.css", "*.styl", "*.vue", "src/validator/index.js", "src/draggable/index.js"],
  • 1

tips:

  1. package.json 文件添加 inspect命令,可输入webpack.js文件查看生成的webpack配置
"scripts": {
	// ...
    "serve": "vue-cli-service serve",
    "inspect": "vue inspect > webpack.js"
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  1. vue.config.js中添加打包分析插件,可查看打包后每个包里面都包含哪些文件,方便优化
config.plugin('webpack-bundle-analyzer').use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
  • 1

完整vue.config.js

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
  .BundleAnalyzerPlugin
// 代码压缩
// const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const path = require('path')

// const resolve = file => path.resolve(__dirname, file)
const poststylus = require('poststylus')
const pxtorem = require('postcss-pxtorem')
const IS_PRO = ['production', 'test'].includes(process.env.NODE_ENV)
// const path = require('path')

// function resolve(dir) {
//   return path.join(__dirname, dir)
// }
const isHistory = process.env.VUE_APP_ROUTER === 'history'
const masterPage = {
  login: {
    entry: 'src/login/login.js',
    template: 'public/login.html',
    chunks: ['vendors', 'vue', 'vuex', 'vue-router', 'login']
  },
  index: {
    entry: 'src/main.js',
    template: 'public/indexApp.html',
    chunks: ['vendors', 'vue', 'vuex', 'vue-router', 'echarts', 'index']
  }
}
const xjPage = {
  index: {
    entry: 'src/main.history.js',
    template: 'public/index.html',
    chunks: ['chunk-vendors', 'chunk-common', 'index']
  }
}
const baseUrl = '/'
module.exports = {
  publicPath: isHistory ? '/xj/' : './',
  outputDir: isHistory ? 'xj' : 'master',
  assetsDir: 'static',
  lintOnSave: true,
  pages: isHistory ? xjPage : masterPage,
  transpileDependencies: [
    'mand-mobile'
  ],
  productionSourceMap: false,
  chainWebpack: config => {
    config.optimization.usedExports = true
    config.when(isHistory && (process.env.NODE_ENV === 'production'), config => {
      // 使用externals设置排除项
      config.set('externals', {
        vue: 'Vue',
        'vue-router': 'VueRouter',
        axios: 'axios',
        vuex: 'Vuex',
        qs: 'Qs'
      })
    })
    config.module.rule('eslint')
    config.module.rule('eslint').use('eslint-loader')
    config.resolve.alias
      .set('@', path.join(__dirname, 'src'))
    config.module.rule('styl')
      .test('/\.styl$/')
      .use('css-loader')
      .loader('stylus-loader')
      .end()
    config.module.rule('images')
      .use('url-loader')
      .loader('url-loader')
      .tap(options => Object.assign(options, { limit: 2048 }))
    if (process.env.NODE_ENV === 'production') {
      config.plugin('optimize-css').tap(([{
        cssnanoOptions,
        ...args
      }]) => {
        const preset = cssnanoOptions.preset || []
        preset.forEach(item => {
          if (typeof item === 'object') {
            item.calc = false
          }
        })
        cssnanoOptions.preset = preset
        return [{
          cssnanoOptions,
          ...args
        }]
      })
    }
    // config.plugin('webpack-bundle-analyzer').use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
  },
  css: {
    extract: IS_PRO,
    sourceMap: false,
    requireModuleExtension: true,
    loaderOptions: {
      stylus: {
        use: [
          poststylus([
            pxtorem({
              rootValue: 100,
              propWhiteList: []
            }),
            'autoprefixer'
          ])
        ]
        // import: [
        //   resolve('./src/assets/theme.custom')
        // ]
      },
      postcss: {
        plugins: [
          require('postcss-pxtorem')({
            rootValue: 100,
            propWhiteList: [],
            minPixelValue: 2
          }),
          require('autoprefixer')()
        ]
      }
    }
  },
  parallel: require('os').cpus().length > 1,
  pwa: {},
  devServer: {
    host: '0.0.0.0',
    port: 8889,
    https: false,
    hotOnly: false,
    open: true,
    before: function(app) {
      const base = baseUrl.replace(/\/+$/, '') // 移除尾部斜杠
      app.get(`${base}/:page/*`, function(req, res, next) {
        if (['login', 'index'].includes(req.params.page)) {
          // 把 /<base>/<page>/* 重定向到 /<base>/<page>/
          req.url = `${base}/${req.params.page}/`
          next('route')
        } else {
          next()
        }
      })
    }
  },
  configureWebpack: config => {
    if (!isHistory) {
      config.optimization = {
        splitChunks: {
          chunks: 'all',
          maxInitialRequests: 6,
          cacheGroups: {
            vue: {
              name: 'vue',
              test: /[\\/]node_modules[\\/]vue[\\/]/,
              priority: -10
            },
            vuex: {
              name: 'vuex',
              test: /[\\/]node_modules[\\/]vuex[\\/]/,
              priority: -10
            },
            'vue-router': {
              name: 'vue-router',
              test: /[\\/]node_modules[\\/]vue-router[\\/]/,
              priority: -10
            },
            'echarts': {
              name: 'echarts',
              test: /[\\/]node_modules[\\/]echarts[\\/]/,
              priority: -10
            },
            'vendors': {
              name: 'vendors',
              test: /[\\/]node_modules[\\/]/,
              priority: -20
            }
          }
        }
      }
    }
    
    if (process.env.NODE_ENV === 'production') {
    } else {
      // 为开发环境修改配置...
      config.devtool = 'source-map'
    }
  },
  pluginOptions: {}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189

针对hash模式下的多页面(登录页、登录后页),进行优化,登录页只用到了几个登录、注册,因此无需引用echarts,所以将echarts单独打包,配置:
config.optimization 中的 splitChunks,如上代码:

  • priority: -20 值越小权重越低,优先打包到权重高的
  • maxInitialRequests: 6,这个值太小了会导致报错
const masterPage = {
  login: {
    entry: 'src/login/login.js',
    template: 'public/login.html',
    chunks: ['vendors', 'vue', 'vuex', 'vue-router', 'login']
  },
  index: {
    entry: 'src/main.js',
    template: 'public/indexApp.html',
    chunks: ['vendors', 'vue', 'vuex', 'vue-router', 'echarts', 'index']
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/324072?site
推荐阅读
相关标签
  

闽ICP备14008679号