Vue 项目实战七 项目优化 以及 上线

1. 项目优化

实现步骤:

  1. 生成打包报告,根据报告优化项目
  2. 第三方库启用CDN
  3. Element-UI组件按需加载
  4. 路由懒加载
  5. 首页内容定制

2. 添加进度条(使用插件)

  1. 先安装依赖 nprogress,并在main里调用
// 导入 nprogress 插件 加载进度条
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
  1. 打开main,编写代码(使用 axios 请求和响应拦截器做判断)
    // 请求拦截器
axios.interceptors.request.use(config => {
        // console.log(config)
        // 使用 NProgress.start() 显示进度条
        NProgress.start()
        config.headers.Authorization = window.sessionStorage.getItem('token')
        return config
    })
    // 响应拦截器   使用 NProgress.done() 隐藏进度条
axios.interceptors.response.use(config => {
        NProgress.done()
        return config
    })

3. 根据报错修改代码

  1. 根据ESLint的警告提示更改对应的代码
  2. 在.prettierrc文件中更改设置"printWidth":200, 将每行代码的文字数量更改为200
{
    "semi":false,
    "singleQuote":true,
    "printWidth":200
}

4. 执行build (安装插件 babel-plugin-transform-remove-console)

  1. 安装一个插件(babel-plugin-transform-remove-console)在项目build阶段移除所有的console信息,打开babel.config.js,编辑代码
//项目发布阶段需要用到的babel插件
const productPlugins = []

//通过 process.env.NODE_ENV 判断当前的编译模式,
// 如果是 发布 就需要运行该插件,删除所有的 console
if(process.env.NODE_ENV === 'production'){
  //发布阶段
  productPlugins.push("transform-remove-console")
}

// 跟 这个插件没关系
module.exports = {
    presets: [
        '@vue/cli-plugin-babel/preset'
    ],
    plugins: [
        // 通过展开运算符,把这个数组里的数据放在 plugins里面
        ...prodPlugins,
        // 声明路由懒加载
        "@babel/plugin-syntax-dynamic-import"
    ]
}
  1. 我们在使用npm run serve等价于vue-cli-service serve这个命令本质上有个参数省略了 --mode development
  2. 我们使用npm run build就等价于vue-cli-service build --mode production
    在babel.config.js里面通过process.env.NODE_ENV的值是等于development,还是production来区分当前是开发环境还是生产环境
  3. 这些配置文件,一般文件,去网上赋值别人的,再根据自己项目的需求更改,参考网站就是babel和wepack官网

5. 生成打包报告

  1. 通过命令行的形式
vue-cli-service build --report
  1. 在vue 控制台 生成打包报告 vue ui
    点击“任务”=>“build”=>“运行”
    运行完毕之后点击右侧“分析”,“控制台”面板查看报告

6. 修改webpack的默认配置

  1. 默认情况下,vue-cli 3.0生成的项目,隐藏了webpack配置项,如果我们需要配置webpack需要通过vue.config.js来配置。
  2. 需要把 main.js 改成 main-prod.js(上线文件) 和 main-dev.js(开发文件)
    上线的时候使用 第一个, 开发的时候使用第二个
  3. 在项目根目录中创建vue.config.js文件,去里面去使用的条件判断(这里用chainWebpack 来做判断)
  4. 补充!!
    chainWebpack可以通过链式编程的形式,修改webpack配置
    configureWebpack可以通过操作对象的形式,修改webpack配置
module.exports = {
    devServer: {
        port: 8888,
        open: true
    },
    lintOnSave: false,

    devServer: {

        overlay: {

            warning: false,

            errors: false

        }

    },
    // 修改打包入口文件, 根据 开发阶段 和 发布阶段的不同  添加不同的打包入口文件
    // config.entry('app') 得到默认的打包入口文件,然后清空, 然后添加
    chainWebpack: config => {
        // 产品发布阶段
        config.when(process.env.NODE_ENV === 'production', config => {
                config.entry('app').clear().add('./src/main-prod.js')

                // 只有发布模式才需要使用 externals  (声明在externals 中的第三方依赖包,都不会被打包)  配置外部的 CDN 资源
                // 第一步
                config.set('externals', {
                    vue: 'Vue',
                    'vue-router': 'VueRouter',
                    axios: 'axios',
                    lodash: '_',
                    echarts: 'echarts',
                    nprogress: 'NProgress',
                    'vue-quill-editor': 'VueQuillEditor'
                })

            })
            // 产品开发阶段
        config.when(process.env.NODE_ENV === 'development', config => {
            config.entry('app').clear().add('./src/main-dev.js')

        })
    },
    //
}

7. 加载外部 CDN

  1. 默认情况下,依赖项的所有第三方包都会被打包到js/chunk-vendors.******.js文件中,导致该js文件过大
  2. 那么我们可以通过externals排除这些包,使它们不被打包到js/chunk-vendors.******.js文件中
  3. 代码就是在上面vue.config.js文件中 externals
            //使用externals设置排除项
            config.set('externals',{
                vue:'Vue',
                'vue-router':'VueRouter',
                axios:'axios',
                lodash:'_',
                echarts:'echarts',
                nprogress:'NProgress',
                'vue-quill-editor':'VueQuillEditor'
            })
        })
  1. 设置好排除之后,为了使我们可以使用vue,axios等内容,我们需要加载外部CDN的形式解决引入依赖项。打开开发入口文件main-prod.js,删除掉默认的引入代码
把 element-ui、富文本编辑器、nprogress  的css样式 和 js 注释掉
import Vue from 'vue'
import App from './App.vue'
import router from './router'
// import './plugins/element.js'
//导入字体图标
import './assets/fonts/iconfont.css'
//导入全局样式
import './assets/css/global.css'
//导入第三方组件vue-table-with-tree-grid
import TreeTable from 'vue-table-with-tree-grid'
//导入进度条插件
import NProgress from 'nprogress'
//导入进度条样式
// import 'nprogress/nprogress.css'
// //导入axios
import axios from 'axios'
// //导入vue-quill-editor(富文本编辑器)
import VueQuillEditor from 'vue-quill-editor'
// //导入vue-quill-editor的样式
// import 'quill/dist/quill.core.css'
// import 'quill/dist/quill.snow.css'
// import 'quill/dist/quill.bubble.css'

axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/'
//请求在到达服务器之前,先会调用use中的这个回调函数来添加请求头信息
axios.interceptors.request.use(config => {
  //当进入request拦截器,表示发送了请求,我们就开启进度条
  NProgress.start()
  //为请求头对象,添加token验证的Authorization字段
  config.headers.Authorization = window.sessionStorage.getItem("token")
  //必须返回config
  return config
})
//在response拦截器中,隐藏进度条
axios.interceptors.response.use(config =>{
  //当进入response拦截器,表示请求已经结束,我们就结束进度条
  NProgress.done()
  return config
})
Vue.prototype.$http = axios

Vue.config.productionTip = false

//全局注册组件
Vue.component('tree-table', TreeTable)
//全局注册富文本组件
Vue.use(VueQuillEditor)
  1. 然后打开 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>电商后台管理系统</title>

    <!-- nprogress 的样式表文件 -->
    <link rel="stylesheet" href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" />
    <!-- 富文本编辑器 的样式表文件 -->
    <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.core.min.css" />
    <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.snow.min.css" />
    <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.bubble.min.css" />
    <!-- element-ui 的样式表文件 -->
    <link rel="stylesheet" href="https://cdn.staticfile.org/element-ui/2.8.2/theme-chalk/index.css" />

    <script src="https://cdn.staticfile.org/vue/2.5.22/vue.min.js"></script>
    <script src="https://cdn.staticfile.org/vue-router/3.0.1/vue-router.min.js"></script>
    <script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
    <script src="https://cdn.staticfile.org/lodash.js/4.17.11/lodash.min.js"></script>
    <script src="https://cdn.staticfile.org/echarts/4.1.0/echarts.min.js"></script>
    <script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js"></script>
    <!-- 富文本编辑器的 js 文件 -->
    <script src="https://cdn.staticfile.org/quill/1.3.4/quill.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue-quill-editor@3.0.4/dist/vue-quill-editor.js"></script>

    <!-- element-ui 的 js 文件 -->
    <script src="https://cdn.staticfile.org/element-ui/2.8.2/index.js"></script>
  </head>

8. 订制首页的内容

开发环境的首页和发布环境的首页展示内容的形式有所不同
如开发环境中使用的是import加载第三方包,而发布环境则是使用CDN,那么首页也需根据环境不同来进行不同的实现

  1. 我们可以通过插件的方式来定制首页内容,打开vue.config.js,编写代码如下:
module.exports = {
    chainWebpack:config=>{
        config.when(process.env.NODE_ENV === 'production',config=>{
            ......
            
            //使用插件   在这里 
            config.plugin('html').tap(args=>{
                //添加参数isProd
                args[0].isProd = true
                return args
            })
        })

        config.when(process.env.NODE_ENV === 'development',config=>{
            config.entry('app').clear().add('./src/main-dev.js')

            //使用插件  在这里
            config.plugin('html').tap(args=>{
                //添加参数isProd
                args[0].isProd = false
                return args
            })
        })
    }
}
  1. 然后 打开 pubic 中的 index.html 使用插件做条件判断,为true 就使用
1.<!-- htmlWebpackPlugin  是参数的具体名称  <% = %> 是输出的意思 -->
<title><%= htmlWebpackPlugin.options.isProd ? '' : 'dev - ' %>电商后台管理系统</title>

2.<% { %> <% }%> 把所以的 js文件和css文件包起来, 这里没有 = 符号
<% if(htmlWebpackPlugin.options.isProd){ %>
    <!-- nprogress 的样式表文件 -->
    <link rel="stylesheet" href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" />
    ........
    <!-- element-ui 的 js 文件 -->
    <script src="https://cdn.staticfile.org/element-ui/2.8.2/index.js"></script>
    <% } %>

9. 路由懒加载

当路由被访问时才加载对应的路由文件,就是路由懒加载。
路由懒加载实现步骤:

  1. 安装 @babel/plugin-syntax-dynamic-import

2.在babel.config.js中声明该插件,打开babel.config.js

module.exports = {
  "presets": [
    "@vue/app"
  ],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ],
    ...productPlugins,
    //配置路由懒加载插件  在这里声明
    "@babel/plugin-syntax-dynamic-import"
  ]
}
  1. 将路由更改为按需加载的形式,打开router.js,更改引入组件代码如下:
import Vue from 'vue'
import VueRouter from 'vue-router'

// 这里就是路由的懒加载
// import Login from '../components/Login.vue'
const Login = () =>
    import ( /* webpackChunkName: "login_home_welcome" */ '../components/Login.vue')
    // import Home from '../components/Home.vue'
const Home = () =>
    import ( /* webpackChunkName: "login_home_welcome" */ '../components/Home.vue')
    // import Welcome from '../components/welcome.vue'
const Welcome = () =>
    import ( /* webpackChunkName: "login_home_welcome" */ '../components/welcome.vue')


// import User from '../components/user/user.vue'
const User = () =>
    import ( /* webpackChunkName: "user_rights_roles" */ '../components/user/user.vue')
    // import Rights from '../components/power/Rights.vue'
const Rights = () =>
    import ( /* webpackChunkName: "user_rights_roles" */ '../components/power/Rights.vue')
    // import Roles from '../components/power/Roles.vue'
const Roles = () =>
    import ( /* webpackChunkName: "user_rights_roles" */ '../components/power/Roles.vue')


// import Cate from '../components/goods/Cate.vue'
const Cate = () =>
    import ( /* webpackChunkName: "cate_roles" */ '../components/goods/Cate.vue')
    // import Params from '../components/goods/Params.vue'
const Params = () =>
    import ( /* webpackChunkName: "cate_roles" */ '../components/goods/Params.vue')


// import GoodsList from '../components/goods/GoodsList.vue'
const GoodsList = () =>
    import ( /* webpackChunkName: "goodslist_goodsadd" */ '../components/goods/GoodsList.vue')
    // import GoodsAdd from '../components/goods/GoodsAdd.vue'
const GoodsAdd = () =>
    import ( /* webpackChunkName: "goodslist_goodsadd" */ '../components/goods/GoodsAdd.vue')


// import Orders from '../components/orders/Orders.vue'
const Orders = () =>
    import ( /* webpackChunkName: "orders_reports" */ '../components/orders/Orders.vue')
    // import Reports from '../components/reports/Reports.vue'
const Reports = () =>
    import ( /* webpackChunkName: "orders_reports" */ '../components/reports/Reports.vue')


Vue.use(VueRouter)

const routes = [
        { path: '/', redirect: '/login' },
        { path: '/login', component: Login },
        {
            path: '/home',
            component: Home,
            redirect: '/welcome',
            children: [
                { path: '/welcome', component: Welcome },
                { path: '/users', component: User },
                { path: '/rights', component: Rights },
                { path: '/roles', component: Roles },
                { path: '/categories', component: Cate },
                { path: '/params', component: Params },
                { path: '/goods', component: GoodsList },
                { path: '/goods/add', component: GoodsAdd },
                { path: '/orders', component: Orders },
                { path: '/reports', component: Reports }
            ]
        }
    ]
    // 在Vue导航菜单中,重复点击一个菜单,即重复触发一个相同的路由,会报错,但不影响功能  需要以下代码来解决
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
    return originalPush.call(this, location).catch(err => err)
}

const router = new VueRouter({
    routes
})

router.beforeEach((to, from, next) => {
    if (to.path == '/login') return next()
    const tokenStr = window.sessionStorage.getItem('token')
    if (!tokenStr) return next('/login')
    next()
})

export default router

10. 项目上线

  1. 通过node创建服务器
    在vue_shop同级创建一个文件夹vue_shop_server存放node服务器
    使用终端打开vue_shop_server文件夹,输入命令 npm init -y
    初始化包之后,输入命令 npm i express -S
    打开vue_shop目录,复制dist文件夹,粘贴到vue_shop_server中
    在vue_shop_server文件夹中创建app.js文件,编写代码如下:
const express = require('express')

const app = express()

app.use(express.static('./dist'))

app.listen(8998,()=>{
    console.log("server running at http://127.0.0.1:8998")
})

然后再次在终端中输入 node app.js

  1. 开启gzip压缩
    打开vue_shop_server文件夹的终端,输入命令:npm i compression -D
    打开app.js,编写代码:
const express = require('express')

const compression = require('compression')

const app = express()

app.use(compression())
app.use(express.static('./dist'))

app.listen(8998,()=>{
    console.log("server running at http://127.0.0.1:8998")
})

  1. 配置https服务
    配置https服务一般是后台进行处理,前端开发人员了解即可。
    首先,需要申请SSL证书,进入https://freessl.cn官网
    在后台导入证书,打开今天资料/素材,复制素材中的两个文件到vue_shop_server中
    打开app.js文件,编写代码导入证书,并开启https服务
const express = require('express')
const compression = require('compression')
const https = require('https')
const fs = require('fs')

const app = express()
//创建配置对象设置公钥和私钥
const options = {
    cert:fs.readFileSync('./full_chain.pem'),
    key:fs.readFileSync('./private.key')
}

app.use(compression())
app.use(express.static('./dist'))

// app.listen(8998,()=>{
//     console.log("server running at http://127.0.0.1:8998")
// })

//启动https服务
https.createServer(options,app).listen(443)

注意:因为我们使用的证书有问题,所以无法正常使用https服务

  1. 使用pm2管理应用
    打开vue_shop_server文件夹的终端,输入命令:npm i pm2 -g
    使用pm2启动项目,在终端中输入命令:pm2 start app.js --name 自定义名称
    查看项目列表命令:pm2 ls
    重启项目:pm2 restart 自定义名称
    停止项目:pm2 stop 自定义名称
    删除项目:pm2 delete 自定义名称
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值