webpack3 打包大小优化 提高首屏加载速度

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

操作方法通用文章:
vue-cli4创建的项目打包优化
只是1.1中不是修改vue.config.js,而是修改build/webpack.prod.conf.js

1.1 webpack.prod.conf.js配置如下:
const webpackConfig = merge(baseWebpackConfig, {
  // ...
  devtool: config.build.productionSourceMap ? config.build.devtool : false,
  output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js'),
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
  },
  externals: {
    vue: 'Vue',
    'vue-router': 'VueRouter',
    axios: 'axios',
    vuex: 'Vuex',
    qs: 'Qs',
    'element-ui': 'ELEMENT',   // 使用发现这里写 ELEMENT或 ElementUI都可以,但是在使用时必须用ELEMENT,否则会报错
    'vue-baidu-map': 'VueBaiduMap'
  },
  // ...
})

在使用element-ui时,直接使用 ELEMENT
main.js

// import Vue from 'vue'
/*
  |
  |
  注释掉的vue/axios/element-ui/qs等不要打开
  已在index.html中引入链接,可正常运行
  |
  |
*/
// 若是没有开启Devtools工具,在开发环境中开启,在生产环境中关闭
if (process.env.NODE_ENV === 'development') {
  Vue.config.devtools = true
} else {
  Vue.config.devtools = false
}
import 'normalize.css/normalize.css'// A modern alternative to CSS resets

// import ElementUI 
// import 'element-ui/lib/theme-chalk/index.css'
// import 'element-ui/lib/theme-chalk/index.css'
// import locale from 'element-ui/lib/locale/lang/zh-CN' // lang i18n
import '@/assets/iconfont/iconfont.css'
import '@/styles/index.scss' // global css
import Navigation from 'vue-navigation'
import App from './App.vue'
import router from './router'
import store from './store'

import '@/icons' // icon
import '@/permission.js' // permission control
import 'viewerjs/dist/viewer.css'
import Viewer from 'v-viewer'
// import axios from 'axios'
Vue.prototype.$axios = axios
// echarts
import echarts from 'echarts'
import china from 'echarts/map/json/china.json'
echarts.registerMap('china', china)
Vue.prototype.$echarts = echarts
Vue.use(Viewer)
// 百度地图
// import BaiduMap from 'vue-baidu-map'
Vue.use(VueBaiduMap, { ak: '---------' })

// 这里是插件的默认设置
Viewer.setDefaults({ zIndexInline: 9999 })
Vue.use(ELEMENT, { size: 'mini' })
Vue.use(Navigation, { router, store, keyName: 'VKN' })
Vue.config.productionTip = false
// 注册全局指令判断权限信息
import permission from '@/directive/permission'
import LoginState from '@/directive/LoginState'
Vue.directive('permission', permission)
Vue.directive('LoginState', LoginState)

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

封装的request.js 用使用:ELEMENT.Message 注释 import { Message } from ‘element-ui’

// import axios from 'axios'
// import { Message } from 'element-ui'
// import qs from 'qs'
// 创建axios实例
const service = axios.create({
  baseURL: process.env.BASE_API, // api的base_url
  timeout: 150000 // 请求超时时间
})
// ...
// respone拦截器
service.interceptors.response.use(
  response => {
    const res = response.data
    if (res.code !== 200) { // 不等于200是错误异常
      if (res.code === 500) {
        ELEMENT.Message({
          message: '内部服务器错误',
          type: 'error',
          showClose: true,
          duration: 5 * 1000
        })
      }
      // ....
    } else {
      return response.data
    }
  },
  error => {
    console.log('err' + error)// for debug
    return Promise.reject(error)
  }
)
// ...
  

2. 将项目拆分为多入口

拆分后的模板文件
build/webpack.base.conf.js

const fs = require('fs')
const htmlArr = fs.readdirSync(path.resolve(__dirname, '../html'))  // 读取html文件夹目录
const entrys = {}
const htmlPlugins = []
for (let item of htmlArr) {
  // 我们只需要.html前面的文件名
  const name = item.split('.html')[0]
  htmlPlugins.push(new HtmlWebpackPlugin({
    filename: item,
    template: path.resolve(__dirname, `../html/${item}`),
    // common代表公共模块,name就是html对应的同名js文件
    // 这个配置将会自动在生成的html中插入你指定的js
    chunks: name === 'back' ? ['manifest', 'vendor', 'echartsVendor', 'common', name] : ['manifest', 'vendor', 'common', name],
    index: 'index.html',
    open: true,
    compress: true,
    port: 8080,
    chunksSortMode: 'manual',  
    // 分离打包echartsVendor后,需要将这加载顺序改为:manual,并且上述chunks中要把mainfest放在第一位
    path: config[isDev ? 'dev' : 'build'].assetsPublicPath + config[isDev ? 'dev' : 'build'].assetsSubDirectory
  }))

  // 配置入口
  entrys[name] = `./src/${name}.js`
}

module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: entrys,
  // ...
}

为了将首页变得更小单独拆分出来一小部分路由到index.html对应的路由中,这样index.html中用不到echarts,所以将echarts单独打一个包,首页(index)不引入,back页引入:chunks: name === ‘back’ ? [‘manifest’, ‘vendor’, ‘echartsVendor’, ‘common’, name] : [‘manifest’, ‘vendor’, ‘common’, name]

单独分离echartsVendor的配置:build/webpack.prod.conf.js

const webpackConfig = merge(baseWebpackConfig, {
  module: {
    rules: utils.styleLoaders({
      sourceMap: config.build.productionSourceMap,
      extract: true,
      usePostCSS: true
    })
  },
  devtool: config.build.productionSourceMap ? config.build.devtool : false,
  output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js'),
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
  },
  externals: {
    vue: 'Vue',
    'vue-router': 'VueRouter',
    axios: 'axios',
    vuex: 'Vuex',
    qs: 'Qs',
    'element-ui': 'ElementUI',
    'vue-baidu-map': 'VueBaiduMap'
  },
  plugins: [
  	new webpack.DefinePlugin({
      'process.env': env
    }),
    new UglifyJsPlugin({
      uglifyOptions: {
        compress: {
          warnings: false
        }
      },
      sourceMap: config.build.productionSourceMap,
      parallel: true
    }),
    // extract css into its own file
    new ExtractTextPlugin({
      filename: utils.assetsPath('css/[name].[contenthash].css'),
      allChunks: false,
    }),
    new OptimizeCSSPlugin({
      cssProcessorOptions: config.build.productionSourceMap
        ? { safe: true, map: { inline: false } }
        : { safe: true }
    }),
    // keep module.id stable when vender modules does not change
    new webpack.HashedModuleIdsPlugin(),
    // enable scope hoisting
    new webpack.optimize.ModuleConcatenationPlugin(),
    // split vendor js into its own file
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks (module) {
        // any required modules inside node_modules are extracted to vendor
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, '../node_modules')
          ) === 0
        )
      }
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      minChunks: Infinity
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'app',
      async: 'vendor-async',
      children: true,
      minChunks: 3
    }),
    // 单独打包echarts---------------------
    new webpack.optimize.CommonsChunkPlugin({
      name: 'echartsVendor',
      chunks: ['vendor'],
      minChunks(module) {
        return module.resource && /echarts/.test(module.resource)
      }
    }),
    // copy custom static assets
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../static'),
        to: config.build.assetsSubDirectory,
        ignore: ['.*']
      },
      {
        from: path.resolve(__dirname, '../src/sdk'),
        to: config.build.assetsSubDirectory,
        ignore: ['plusCommon.js']
      }
    ])
  ]
})

打包后分析发现他们公用的store里面还引入了NIM_Web_SDK_v5.0.0.js,400多KB,现在想只让back引入这个,index不引入,
NIM_Web_SDK_v5.0.0.js放在src/sdk中,所以设置:将这个文件复制到打包后的文件夹中
在这里插入图片描述
在用到SDK的地方直接使用,去掉原来的引入// const SDK = require(’@/sdk/’ + sdkrul);
在这里插入图片描述
想直接使用SDK,还需要重要的一步,
.eslintrc.js中添加:“SDK”: true

module.exports = {
  root: true,
  parser: 'babel-eslint',
  parserOptions: {
    sourceType: 'module'
  },
  "globals": {
    "BMap": true,
    "BMAP_NORMAL_MAP": true,
    "BMAP_HYBRID_MAP":true,
    "BMAP_ANCHOR_TOP_LEFT":true,
    "BMAP_ANCHOR_TOP_RIGHT":true,
    "BMAP_ANCHOR_BOTTOM_RIGHT":true,
    "BMAP_NAVIGATION_CONTROL_SMALL":true,
    "SDK": true
  },
 // ...
}

tips

1、使用cdn引入后,开发时devtool会加载不到组件信息和vuex信息
在main.js 中加入以下代码,组件那里就能正常使用了,但vuex信息还是不行,需要在store/index.js也加入以下代码,即可正常使用调试工具

if (process.env.NODE_ENV === 'development') {
  Vue.config.devtools = true
} else {
  Vue.config.devtools = false
}

2、 改为cdn后,全局使用的变量名如何确定
打开源代码大概第一行的位置会有,不确定这方法100%准确
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 分离打包echartsVendor后,需要将这加载顺序改为:manual,并且上述chunks中要把mainfest放在第一位
    在这里插入图片描述
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值