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%准确
- 分离打包echartsVendor后,需要将这加载顺序改为:manual,并且上述chunks中要把mainfest放在第一位