vue項目部署篇 -線上部署優化


打包注意事項

打包完的項目 dist文件夾如果 已經啟動服務,此時不能重新打包,(因為文件 在占用),需要停止服務,再進行重新打包。

vue打包上線移除 console

兩種插件可選擇

1、babel-plugin-transform-remove-console

比較流行的解決辦法是使用 babel 的一個插件,因為webpack 打包時會使用 babel 進行代碼降級,所以babel 插件可以在打包過程中,將 console 移除

安裝

npm install babel-plugin-transform-remove-console --save-dev

配置

在項目根目錄下的 babel.config 文件中加入如下代碼

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  // 配置插件的名稱
  plugins:['transform-remove-console']
}

2. terser-webpack-plugin

安裝

npm install terser-webpack-plugin --save-dev

注意: 項目根目錄下新建 webpack.config.js,(不是vue.config.js)注冊此插件

const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
  optimization: {
    minimize: true,
    minimizer: [new TerserPlugin()],
    terserOptions: {
      compress: {
        drop_console: true
      }
    }
  }
}

接下來就可以重新編譯了。。

判斷運行模式打包

使用 babel-plugin-transform-remove-console 插件會有一個問題(使用terser-webpack-plugin沒有此問題),就是一旦安裝並配置好后,無論運行

npm run build

還是運行

npm run serve

都會刪除 console,語句,因為我們開發階段都是使用 serve 命令啟動的,所以導致開發階段我們所有的console 語句都消失了

解決辦法就是明確告訴此插件當前是開發環境還是生產環境

修改 babel.config.js 中的代碼

const prodPlugins = []
if (process.env.NODE_ENV === 'production') {
  prodPlugins.push('transform-remove-console')
}
 
module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  plugins: [...prodPlugins]
}

此時,只有在生產環境下,才會去除 console

開發環境/部署環境打包

步驟

在 src 目錄下新建 prod_env.js 和 dev_env.js,將main.js 中代碼分別拷貝到這兩個文件中,現在就可以刪除 main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);

// import request from "./network/request"
// Vue.prototype.$http = request

import axios from "axios"
axios.defaults.baseURL='http://127.0.0.1:8888/api/private/v1/'
// 請求攔截
axios.interceptors.request.use(config=>{
  config.headers.Authorization=sessionStorage.getItem('token')
  // console.log(config);
  return config
})
// 響應攔截
axios.interceptors.response.use(res=>{
  return res.data
})
Vue.prototype.$http = axios

// 字體圖標
import './assets/font/iconfont.css'

// 時間格式化
// import moment from "moment"
// 全局的時間格式過濾器
Vue.filter('formatTime', v => {
  return moment.unix(v / 1000).format('YYYY-MM-DD HH:mm:SS')
})

// 富文本
import VueQuillEditor from 'vue-quill-editor'
// require styles
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
// 使用CSN方式使用插件,use不能省略,還需要使用use使用改插件
Vue.use(VueQuillEditor)


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

配置打包時的入口文件

項目根目錄下新建 vue.config.js

 module.exports={
 		// 鏈式操作
     chainWebpack:config=>{
         // 項目部署時的入口文件
        config.when(process.env.NODE_ENV === 'production',config=>{
            config.entry('app').clear().add('./src/prod_env.js')
        })
         // 配置開發時的入口文件
        config.when(process.env.NODE_ENV === 'development',config=>{
         // 使用開發階段的配置
            config.entry('app').clear().add('./src/dev_env.js')
        })
    }
}

開發時,使用 npm run serve 命令,NODE_ENV 的值就是 developmnent ,所以會將 dev.env.js 作為入口文件
部署時,使用 npm run build 命令,NODE_ENV 的值就是 production,所以會將 prod_evn.js 作為入口文件

項目打包減少體積

解決方法主要是兩個,一個是使用CDN,一個是路由的懶加載

項目運行 npm run build后使用vscode打開

//項目運行時依賴文件,伴隨着在main.js中引入的插件增加,打包后的體積也會增加
chunk-vendors.b4c61135.js

默認情況下,凡是通過 import 方式引入的包,打包時都會被打包,這就會導致最后的包體積比較大,伴隨而來的就是程序的加載速度慢

使用CDN

注意: index.html中不能同時使用CDN和本地引入(會報錯,瀏覽器會首先使用script中引入的插件)

https://www.jsdelivr.com/ CDN網站

點擊搜索,vuecdn,復制或 HTML的script標簽

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-f5l8M8Cr-1588228759900)(images/image-20200429200418462.png)]

修改生產環境入口文件

凡是通過CDN節點方式引用的包,在這里都注釋掉,

注意: 使用CSN方式使用插件,use不能省略,還需要使用use使用改插件

// import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false

// import ElementUI from 'element-ui';
// import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);

// import request from "./network/request"
// Vue.prototype.$http = request

// import axios from "axios"
axios.defaults.baseURL='http://127.0.0.1:8888/api/private/v1/'
// 請求攔截
axios.interceptors.request.use(config=>{
  config.headers.Authorization=sessionStorage.getItem('token')
  // console.log(config);
  return config
})
// 響應攔截
axios.interceptors.response.use(res=>{
  return res.data
})
Vue.prototype.$http = axios

// 字體圖標
import './assets/font/iconfont.css'

// 時間格式化
// import moment from "moment"
// 全局的時間格式過濾器
Vue.filter('formatTime', v => {
  return moment.unix(v / 1000).format('YYYY-MM-DD HH:mm:SS')
})

// 富文本
// import VueQuillEditor from 'vue-quill-editor'
// require styles
// import 'quill/dist/quill.core.css'
// import 'quill/dist/quill.snow.css'
// import 'quill/dist/quill.bubble.css'
// 使用CSN方式使用插件,use不能省略,還需要使用use使用改插件
Vue.use(VueQuillEditor)

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

public/index.html 中引入CDN

<!DOCTYPE html>
<html lang="en">

<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">
  <link rel="icon" href="<%= BASE_URL %>favicon.ico">
  <title><%= htmlWebpackPlugin.options.title %></title>
  <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/quill@1.3.7/dist/quill.core.css" />
  <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/quill@1.3.7/dist/quill.snow.css" />
  <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/quill@1.3.7/dist/quill.bubble.css" />
  <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/element-ui@2.13.1/lib/theme-chalk/index.css">
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js"></script>
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/quill@1.3.7/dist/quill.min.js"></script>
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue-quill-editor@3.0.6/dist/vue-quill-editor.min.js"></script>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  <!-- <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> -->
  <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>
  <script src="https://cdn.bootcss.com/echarts/4.7.0/echarts.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/element-ui@2.13.1/lib/index.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/moment@2.24.0/moment.min.js"></script>
</head>

<body>
  <noscript>
    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
      Please enable it to continue.</strong>
  </noscript>
  <div id="app"></div>
  <!-- built files will be auto injected -->
</body>

</html>

vue.config.js 中添加配置

https://cli.vuejs.org/zh/config/#vue-config-js 官方腳手架 vue.config.js配置

module.exports = {
  // 配置webpack的解析配置項
  configureWebpack: {
    resolve: {
      alias: {
        "assets": "@/assets",
        "components": "@/components",
        "network": "@/network",
        'common': '@/common'
      }
    }
  },
  chainWebpack: config => {
    /** * 配置打包時使用CDN節點,左面放package.json中的擴展的名稱,右面放項目依賴的名稱(項目初始化要用的名稱) * externals外部擴展的意思,使用外部CDN節點進行打包 * 3、名稱帶中橫線的需使用引號包起來 * */
    config.set("externals", {
      vue: 'Vue',
      moment: 'moment',
      "element-ui": 'element-ui',
      axios: 'axios',
      "vue-quill-editor": "vue-quill-editor"
    })
  }
}

總結: webpack在打包時,是以public/index.html作為模板,CDN節點寫到其中,打包后,也就會在打包后的項目中引入cdn節點。

開發/部署階段自動判斷

部署的時候 index.html 中使用這些 CDN 節點的依賴,開發階段,不希望 index.html 中的這些引用存在,而是繼續使用本地的包,這就需要在 index.html 中根據當前的打包環境是開發還是部署,動態的決定 index.html 中是否顯示這些引用

步驟

使用 webpack中自帶的插件 html插件進行配置,在 index.html 中增加判斷,是否使用 CDN

htmlWebpackPlugin.options 使用的是vue.config中的config.plugin('html')的插件屬性

index.html

<!DOCTYPE html>
<html lang="en">

<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">
  <link rel="icon" href="<%= BASE_URL %>favicon.ico">
  <title><%= htmlWebpackPlugin.options.title %></title>
  <!-- 使用vue自帶的lodash語法,在這里進行判斷是否引入CDN -->
  <!-- htmlWebpackPlugin.options 使用的是vue.config中的config.plugin('html')的插件屬性 -->
  <% if( htmlWebpackPlugin.options.isProd) { %>
  <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/quill@1.3.7/dist/quill.core.css" />
  <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/quill@1.3.7/dist/quill.snow.css" />
  <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/quill@1.3.7/dist/quill.bubble.css" />
  <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/element-ui@2.13.1/lib/theme-chalk/index.css">
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js"></script>
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/quill@1.3.7/dist/quill.min.js"></script>
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue-quill-editor@3.0.6/dist/vue-quill-editor.min.js"></script>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  <!-- <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> -->
  <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>
  <script src="https://cdn.bootcss.com/echarts/4.7.0/echarts.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/element-ui@2.13.1/lib/index.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/moment@2.24.0/moment.min.js"></script>
  <% } %>

</head>

<body>
  <noscript>
    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
      Please enable it to continue.</strong>
  </noscript>
  <div id="app"></div>
  <!-- built files will be auto injected -->
</body>

</html>

vue.congfig.js

當前配置的自動判斷引入哪一個配置文件

module.exports = {
  // 配置webpack的解析配置項
  configureWebpack: {
    resolve: {
      alias: {
        "assets": "@/assets",
        "components": "@/components",
        "network": "@/network",
        'common': '@/common'
      }
    }
  },
  // 鏈式操作
  chainWebpack: config => {
    // 項目部署時的入口文件
    config.when(process.env.NODE_ENV === 'production', config => {
      // 使用部署階段的配置
      config.entry('app').clear().add('./src/prod.env.js')
      /** * 配置,項目部署打包時使用CDN節點的別名方式進行打包,而不用import本地引入(原理是使用CDN模塊中暴漏出來的對象,然后再這里配置在編譯時webpack要使用的模塊別名) * 1、配置打包時使用CDN節點,左面放package.json中的擴展的名稱,右面放項目依賴的名稱(項目初始化要用的名稱) * 2、externals外部擴展的意思,使用外部CDN節點進行打包 * 3、名稱帶中橫線的需使用引號包起來 * */
      config.set("externals", {
        vue: 'Vue',
        moment: 'moment',
        "element-ui": 'element-ui',
        axios: 'axios',
        "vue-quill-editor": "VueQuillEditor"
      })

      // 根據開發模式,自動判斷是否使用index.html中的CDN
      config.plugin('html').tap(args => {
        args[0].title = "超級商城后台管理"
        // 是否是生產模式
        args[0].isProd = true
        // 注意最后要把數組返回
        return args
      })
    })

    // 配置開發時的入口文件
    config.when(process.env.NODE_ENV === 'development', config => {
      // 使用開發階段的配置
      config.entry('app').clear().add('./src/dev_env.js')

      // 根據開發模式,自動判斷是否使用index.html中的CDN
      config.plugin('html').tap(args => {
        // 這里的title是index.html中的title的lodash模板變量的參數
        args[0].title = "dev模式 - 超級商城后台管理"
        // 是否是生產模式
        args[0].isProd = false
        console.log(args)  //args中包含當前plugin配置的參數
        // 注意最后要把數組返回
        return args
      })
    })
  }
}

args中包含當前plugin配置的參數,其打印出結果如下。

 config.plugin('html').tap(args => {
        // 這里的title是index.html中的title的lodash模板變量的參數
        args[0].title = "dev模式 - 超級商城后台管理"
        // 是否是生產模式
        args[0].isProd=false
        console.log(args)  //args中包含當前plugin配置的參數
        // 注意最后要把數組返回
        return args
      })
[
  {
    title: 'dev模式 - 超級商城后台管理',
    templateParameters: [Function: templateParameters],
    template: 'D:\\Users\\王金龍\\Desktop\\shop_manage\\public\\index.html',
    isProd: false
  }
]

prod.env.js

既然增加了自動判斷是否引入CDN那么引入本地的代碼就注釋/刪掉,根據配置(如果在開發階段就使用dev.env.js,生產階段就使用的是 prod.env.js

// import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false

// import ElementUI from 'element-ui';
// import 'element-ui/lib/theme-chalk/index.css';
// Vue.use(ElementUI);

// import request from "./network/request"
// Vue.prototype.$http = request

// import axios from "axios"
axios.defaults.baseURL='http://127.0.0.1:8888/api/private/v1/'
// 請求攔截
axios.interceptors.request.use(config=>{
  config.headers.Authorization=sessionStorage.getItem('token')
  // console.log(config);
  return config
})
// 響應攔截
axios.interceptors.response.use(res=>{
  return res.data
})
Vue.prototype.$http = axios

// 字體圖標
import './assets/font/iconfont.css'

// 時間格式化
// import moment from "moment"
// 全局的時間格式過濾器
Vue.filter('formatTime', v => {
  return moment.unix(v / 1000).format('YYYY-MM-DD HH:mm:SS')
})

// 富文本
// import VueQuillEditor from 'vue-quill-editor'
// // require styles
// import 'quill/dist/quill.core.css'
// import 'quill/dist/quill.snow.css'
// import 'quill/dist/quill.bubble.css'
// 使用CSN方式使用插件,use不能省略,還需要使用use使用改插件
Vue.use(VueQuillEditor)


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

dev.env.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);

// import request from "./network/request"
// Vue.prototype.$http = request

import axios from "axios"
axios.defaults.baseURL='http://127.0.0.1:8888/api/private/v1/'
// 請求攔截
axios.interceptors.request.use(config=>{
  config.headers.Authorization=sessionStorage.getItem('token')
  // console.log(config);
  return config
})
// 響應攔截
axios.interceptors.response.use(res=>{
  return res.data
})
Vue.prototype.$http = axios

// 字體圖標
import './assets/font/iconfont.css'

// 時間格式化
// import moment from "moment"
// 全局的時間格式過濾器
Vue.filter('formatTime', v => {
  return moment.unix(v / 1000).format('YYYY-MM-DD HH:mm:SS')
})

// 富文本
import VueQuillEditor from 'vue-quill-editor'
// require styles
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
// 使用CSN方式使用插件,use不能省略,還需要使用use使用改插件
Vue.use(VueQuillEditor)


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

優化之路由懶加載

https://router.vuejs.org/zh/guide/advanced/lazy-loading.html

const Foo = () => import('./Foo.vue')

在路由配置中什么都不需要改變,只需要像往常一樣使用 Foo

const router = new VueRouter({
  routes: [
    { path: '/foo', component: Foo }
  ]
})

把組件按組分塊

有時候我們想把某個路由下的所有組件都打包在同個異步塊 (chunk) 中。只需要使用 命名 chunk,一個特殊的注釋語法來提供 chunk name (需要 Webpack > 2.4)。

const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')

Webpack 會將任何一個異步模塊與相同的塊名稱組合到相同的異步塊中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM