zoukankan      html  css  js  c++  java
  • 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 会将任何一个异步模块与相同的块名称组合到相同的异步块中。

  • 相关阅读:
    学习使用linux下tags文件
    uboot常用命令详解
    U-boot中TFTP 解释
    eth0: ERROR while getting interface flags: No such device 没有eth0 有其他的eth
    取消挂载 umount 时出现的 “Device is busy”
    Linux的log日志功能
    oracle的安装
    SOA架构设计分析
    立方体模型
    质量属性的六个常见属性场景(淘宝网)
  • 原文地址:https://www.cnblogs.com/wjlbk/p/12884651.html
Copyright © 2011-2022 走看看