vue-cli3 从搭建到优化的详细步骤


Posted in Javascript onJanuary 20, 2019

前言

github地址: https://github.com/LeeStaySmall/vue-project-demo (完整分支:optimize分支)

demo地址: vue-project-demo.eloco.cn

安装与初始化架构

安装

node >= 8.9 推荐:8.11.0 +

安装: npm install -g @vue/cli

检查: vue --version

如果已安装旧版本,需要先 npm uninstall vue-cli -g 卸载掉旧版本。

初始化架构

创建: vue create project-name

vue-cli3 从搭建到优化的详细步骤

注:项目名称不能驼峰命名。

选择一个预设(这里我选择更多功能):

vue-cli3 从搭建到优化的详细步骤

选择需要安装的(Babel、Router、Vuex、Pre-processors、Linter / Formatter):

vue-cli3 从搭建到优化的详细步骤

是否使用history路由模式(Yes):

vue-cli3 从搭建到优化的详细步骤

选择css 预处理器(Sass/SCSS):

vue-cli3 从搭建到优化的详细步骤

选择eslint 配置(ESLint + Standard config):

vue-cli3 从搭建到优化的详细步骤

选择什么时候执行eslint校验(Lint on save):

vue-cli3 从搭建到优化的详细步骤

选择以什么样的形式配置以上所选的功能(In dedicated config files):

vue-cli3 从搭建到优化的详细步骤

是否将之前的设置保存为一个预设模板(y):

vue-cli3 从搭建到优化的详细步骤

如果选择 y 会让输入名称,以便下次直接使用,否则直接开始初始化项目。

最后,看一下生成的基本架构目录:

vue-cli3 从搭建到优化的详细步骤

在项目中优雅的使用svg 首先在 /src/components 创建 SvgIcon.vue

vue-cli3 从搭建到优化的详细步骤

src/ 下创建 icons 文件夹,以及在其下创建 svg 文件夹用于存放svg文件,创建 index.js 作为入口文件:

vue-cli3 从搭建到优化的详细步骤

编写index.js 的脚本:

import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon.vue' // svg组件

// 全局注册
Vue.component('svg-icon', SvgIcon)

const requireAll = requireContext => requireContext.keys().map(requireContext)
const req = require.context('./svg', false, /\.svg$/)
requireAll(req)

使用 svg-sprite-loader 对项目中使用的 svg 进行处理:

npm install svg-sprite-loader --save-dev

修改默认的 webpack 配置, 在项目根目录创建 vue.config.js ,代码如下;

const path = require('path')

function resolve(dir) {
 return path.join(__dirname, './', dir)
}

module.exports = {
 chainWebpack: config => {
 // svg loader
 const svgRule = config.module.rule('svg') // 找到svg-loader
 svgRule.uses.clear() // 清除已有的loader, 如果不这样做会添加在此loader之后
 svgRule.exclude.add(/node_modules/) // 正则匹配排除node_modules目录
 svgRule // 添加svg新的loader处理
  .test(/\.svg$/)
  .use('svg-sprite-loader')
  .loader('svg-sprite-loader')
  .options({
  symbolId: 'icon-[name]'
  })

 // 修改images loader 添加svg处理
 const imagesRule = config.module.rule('images')
 imagesRule.exclude.add(resolve('src/icons'))
 config.module
  .rule('images')
  .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
 }
}

最后,在 main.js 中引入 import '@/icons' 即可;

// 使用示例
<svg-icon icon-class="add" />

PS:至于svg ,个人比较建议使用阿里开源的图标库iconFont

axios封装api、模块化vuex

axios篇

项目中安装 axiosnpm install axios

src 目录下创建 utils/ , 并创建 request.js 用来封装 axios ,上代码:

import axios from 'axios'

// 创建axios 实例
const service = axios.create({
 baseURL: process.env.BASE_API, // api的base_url
 timeout: 10000 // 请求超时时间
})

// request 拦截器
service.interceptors.request.use(
 config => {
 // 这里可以自定义一些config 配置

 return config
 },
 error => {
 // 这里处理一些请求出错的情况

 console.log(error)
 Promise.reject(error)
 }
)

// response 拦截器
service.interceptors.response.use(
 response => {
 const res = response.data
 // 这里处理一些response 正常放回时的逻辑

 return res
 },
 error => {
 // 这里处理一些response 出错时的逻辑

 return Promise.reject(error)
 }
)

export default service

既然要使用 axios ,必不可少的需要配置环境变量以及需要请求的地址,这里可以简单的修改 poackage.json :

"scripts": {
 "dev": "vue-cli-service serve --project-mode dev",
 "test": "vue-cli-service serve --project-mode test",
 "pro": "vue-cli-service serve --project-mode pro",
 "pre": "vue-cli-service serve --project-mode pre",
 "build:dev": "vue-cli-service build --project-mode dev",
 "build:test": "vue-cli-service build --project-mode test",
 "build:pro": "vue-cli-service build --project-mode pro",
 "build:pre": "vue-cli-service build --project-mode pre",
 "build": "vue-cli-service build",
 "lint": "vue-cli-service lint"
 },

同时修改vue.config.js:

const path = require('path')

function resolve(dir) {
 return path.join(__dirname, './', dir)
}

module.exports = {
 chainWebpack: config => {
 // 这里是对环境的配置,不同环境对应不同的BASE_API,以便axios的请求地址不同
 config.plugin('define').tap(args => {
  const argv = process.argv
  const mode = argv[argv.indexOf('--project-mode') + 1]
  args[0]['process.env'].MODE = `"${mode}"`
  args[0]['process.env'].BASE_API = '"http://47.94.138.75:8000"'
  return args
 })

 // svg loader
 const svgRule = config.module.rule('svg') // 找到svg-loader
 svgRule.uses.clear() // 清除已有的loader, 如果不这样做会添加在此loader之后
 svgRule.exclude.add(/node_modules/) // 正则匹配排除node_modules目录
 svgRule // 添加svg新的loader处理
  .test(/\.svg$/)
  .use('svg-sprite-loader')
  .loader('svg-sprite-loader')
  .options({
  symbolId: 'icon-[name]'
  })

 // 修改images loader 添加svg处理
 const imagesRule = config.module.rule('images')
 imagesRule.exclude.add(resolve('src/icons'))
 config.module
  .rule('images')
  .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
 }
}

如何使用? 我比较建议在 src/ 下创建 api 目录,用来统一管理所有的请求,比如下面这样: ‘'

vue-cli3 从搭建到优化的详细步骤

这样的好处是方便管理、后期维护,还可以和后端的微服务对应,建立多文件存放不同模块的 api 。剩下的就是你使用到哪个api时,自己引入便可。

拓展:服务端的cors设置

牵涉到跨域,这里采用 cors ,很多朋友在面试中经常会被问到cors的实现原理,这个网上有很多理论大多是这样讲的:

vue-cli3 从搭建到优化的详细步骤

其实,这样理解很抽象,服务器端到底是怎么做验证的?

这里大家可以通俗的理解为后端在接收前端的 request 请求的时候,会有一个 request 拦截器,像 axios response 拦截器一样。下面以 php lumen 框架为例,来深入理解一下这个流程:

<?php

namespace App\Http\Middleware;

use App\Http\Utils\Code;
use Closure;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;

class CorsMiddleware
{
 private $headers;

 /**
  * 全局 : 解决跨域
  * @param $request
  * @param \Closure $next
  * @return mixed
  * @throws \HttpException
  */
 public function handle($request, Closure $next)
 {
  //请求参数
  Log::info('http request:'.json_encode(["request_all" => $request->all()]));

  $allowOrigin = [
   'http://47.94.138.75',
   'http://localhost',
  ];
  $Origin = $request->header("Origin");

  $this->headers = [
   'Access-Control-Allow-Headers'  => 'Origin,x-token,Content-Type',
   'Access-Control-Allow-Methods'  => 'GET, POST, PUT, DELETE, OPTIONS',
   'Access-Control-Allow-Credentials' => 'true',//允许客户端发送cookie
   'Access-Control-Allow-Origin'  => $Origin,
   //'Access-Control-Max-Age'   => 120, //该字段可选,间隔2分钟验证一次是否允许跨域。
  ];
  //获取请求方式
  if ($request->isMethod('options')) {
   if (in_array($Origin, $allowOrigin)) {
    return $this->setCorsHeaders(new Response(json_encode(['code' => Code::SUCCESS, "data" => 'success', "msg" => ""]), Code::SUCCESS));
   } else {
    return new Response(json_encode('fail', 405));
   }
  }
  $response = $next($request);
  //返回参数
  Log::info('http response:'.json_encode($response));
  return $this->setCorsHeaders($response);

 }

 /**
  * @param $response
  * @return mixed
  */
 public function setCorsHeaders($response)
 {
  foreach ($this->headers as $key => $val) {
   $response->header($key, $val);
  }
  return $response;
 }
}

vuex 篇

如果创建项目的时候,选择了 vuex ,那么默认会在 src 目录下有一个 store.js 作为仓库文件。但在更多实际场景中,如果引入 vuex ,那么肯定避免不了分模块,先来看一下默认文件代码:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
 state: {

 },
 mutations: {

 },
 actions: {

 }
})

那么现在改造一下,比如先划分出 appuser 两个模块,可以这样:

import Vue from 'vue'
import Vuex from 'vuex'
import app from './store/modules/app'
import user from './store/modules/user'
import getters from './store/getters'

Vue.use(Vuex)

const store = new Vuex.Store({
 modules: {
 app,
 user
 },
 getters
})

export default store

src/ 下创建 store/ 目录:

vue-cli3 从搭建到优化的详细步骤

app module 可以用来存储应用的状态,比如接下来要讲到的全局 loading ,或者控制第三方组件的全局大小,比如 element ui 中的全局组件 size

user module 可以用来存储当前用户的信息;

当然,store 配合本地存储比较完美,这里采用 js-cookie

全局loading、合理利用vue router守卫

全局loading

上面说完了 axios、vuex ,现在结合之前说一下设置全局 loading 效果。

平常写代码每个请求之前一般都需要设置 loading ,成功之后结束 loading 效果,这就迫使我们不得不写大量重复代码,如果不想这样做,可以结合 axiosvuex 统一做了。

首先,在说 vuex 的时候,我在 src/ 下创建了一个 store ,现在就在 store/modules/app.js 写这个 Loading 效果的代码;

const app = {
 state: {
 requestLoading: 0
 },
 mutations: {
 SET_LOADING: (state, status) => {
  // error 的时候直接重置
  if (status === 0) {
  state.requestLoading = 0
  return
  }
  state.requestLoading = status ? ++state.requestLoading : --state.requestLoading
 }
 },
 actions: {
 SetLoading ({ commit }, status) {
  commit('SET_LOADING', status)
 }
 }
}

export default app

再来修改一下 utils/request.js

import axios from 'axios'
import store from '@/store'

// 创建axios 实例
const service = axios.create({
 baseURL: process.env.BASE_API, // api的base_url
 timeout: 10000 // 请求超时时间
})

// request 拦截器
service.interceptors.request.use(
 config => {
 // 这里可以自定义一些config 配置

 // loading + 1
 store.dispatch('SetLoading', true)

 return config
 },
 error => {
 // 这里处理一些请求出错的情况

 // loading 清 0 
 setTimeout(function () {
  store.dispatch('SetLoading', 0)
 }, 300)

 console.log(error)
 Promise.reject(error)
 }
)

// response 拦截器
service.interceptors.response.use(
 response => {
 const res = response.data
 // 这里处理一些response 正常放回时的逻辑

 // loading - 1
 store.dispatch('SetLoading', false)

 return res
 },
 error => {
 // 这里处理一些response 出错时的逻辑

 // loading - 1
 store.dispatch('SetLoading', false)

 return Promise.reject(error)
 }
)

export default service

其次,在 src/components/ 下创建 RequestLoading.vue 组件:

<template>
 <transition name="fade-transform" mode="out-in">
 <div class="request-loading-component" v-if="requestLoading">
  <svg-icon icon-class="loading" />
 </div>
 </transition>
</template>

<script>
import { mapGetters } from 'vuex'

export default {
 name: 'RequestLoading',
 computed: {
 ...mapGetters([
  'requestLoading'
 ])
 }
}
</script>

<style lang='scss' scoped>
.request-loading-component {
 position: fixed;
 left: 0;
 right: 0;
 top: 0;
 bottom: 0;
 //background-color: rgba(48, 65, 86, 0.2);
 background-color: transparent;
 font-size: 150px;
 display: flex;
 flex-direction: row;
 justify-content: center;
 align-items: center;
 z-index: 999999;
}
</style>

最后,在 app.vue 中引入即可。

附: 为了方便演示,项目里出了初始化包括 axiosvuexvue-router , 项目使用了 js-cookieelement-ui 等,此步骤之后,会改造一下 app.vue

vue router守卫

vue-router 提供了非常方便的钩子,可以让我们在做路由跳转的时候做一些操作,比如常见的权限验证。

首先,需要在 src/utils/ 下创建 auth.js ,用于存储token;

import Cookies from 'js-cookie'

const TokenKey = 'project-token'

export function getToken () {
 return Cookies.get(TokenKey)
}

export function setToken (token) {
 return Cookies.set(TokenKey, token)
}

export function removeToken () {
 return Cookies.remove(TokenKey)
}

src/utils/ 下创建 permission.js :

import router from '@/router'
import store from '@/store'
import {
 getToken
} from './auth'
import NProgress from 'nprogress' // 进度条
import 'nprogress/nprogress.css' // 进度条样式
import {
 Message
} from 'element-ui'

const whiteList = ['/login'] // 不重定向白名单
router.beforeEach((to, from, next) => {
 NProgress.start()
 if (getToken()) {
 if (to.path === '/login') {
  next({
  path: '/'
  })
  NProgress.done()
 } else { // 实时拉取用户的信息
  store.dispatch('GetUserInfo').then(res => {
  next()
  }).catch(err => {
  store.dispatch('FedLogOut').then(() => {
   Message.error('拉取用户信息失败,请重新登录!' + err)
   next({
   path: '/'
   })
  })
  })
 }
 } else {
 if (whiteList.includes(to.path)) {
  next()
 } else {
  next('/login')
  NProgress.done()
 }
 }
})

router.afterEach(() => {
 NProgress.done() // 结束Progress
})

Nginx try_files 以及 404

nginx 配置如下:

location / {
  root /www/vue-project-demo/;
  try_files $uri $uri/ /index.html index.htm;
}

try_files : 可以理解为nginx 不处理你的这些url地址请求; 那么服务器如果不处理了,前端要自己做一些404 操作,比如下面这样:

// router.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'

Vue.use(Router)

export default new Router({
 mode: 'history',
 base: process.env.BASE_URL,
 routes: [
 { path: '/404', component: () => import('@/views/404') },
 {
  path: '/',
  name: 'home',
  component: Home
 },
 {
  path: '/about',
  name: 'about',
  // route level code-splitting
  // this generates a separate chunk (about.[hash].js) for this route
  // which is lazy-loaded when the route is visited.
  component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
 },
 { path: '*', redirect: '/404' }
 ]
})

然后写一个404 的view 就ok 。

常用的utils

到现在为止, utils/ 目录下应该有 auth.js 、permission.js、request.js

  • 那么对与一些常用的方法,你可以放到 utils/common.js 里,统一 installvue 实例上,并通过 Vue.use() 使用;
  • 对于一些全局的过滤器,你仍可以放到 utils/filters.js 里,使用 Vue.fileter() 注册到全局;
  • 对于一些全局方法,又不是很长用到的,可以放到 utils/index.js ,哪里使用哪里 import

mixin减少项目冗余代码

直接看代码吧,要写奔溃了....

使用cdn减少文件打包的体积

到此时,看我项目里都用了什么:

vue-cli3 从搭建到优化的详细步骤

主要就是这些,那么执行一下打包命令呢?

vue-cli3 从搭建到优化的详细步骤

可能这时候你还觉得没什么, 单文件最多的还没超过 800kb 呢...

我把项目通过 jenkins 部署到服务器上,看一下访问:

vue-cli3 从搭建到优化的详细步骤

可以看到, chunk-vendors 加载了将近12秒,这还是只有框架没有内容的前提下,当然你可能说你项目中用不到 vuex 、用不到 js-cookie ,但是随着项目的迭代维护,最后肯定不比现在小。

那么,有些文件在生产环境是不是可以尝试使用 cdn 呢?

为了方便对比,这里保持原代码不动( master 分支),再切出来一个分支改动优化( optimize 分支), 上代码:

// vue.config.js 修改
const path = require('path')

function resolve(dir) {
 return path.join(__dirname, './', dir)
}

// cdn预加载使用
const externals = {
 'vue': 'Vue',
 'vue-router': 'VueRouter',
 'vuex': 'Vuex',
 'axios': 'axios',
 'element-ui': 'ELEMENT',
 'js-cookie': 'Cookies',
 'nprogress': 'NProgress'
}

const cdn = {
 // 开发环境
 dev: {
 css: [
  'https://unpkg.com/element-ui/lib/theme-chalk/index.css',
  'https://cdn.bootcss.com/nprogress/0.2.0/nprogress.min.css'
 ],
 js: []
 },
 // 生产环境
 build: {
 css: [
  'https://unpkg.com/element-ui/lib/theme-chalk/index.css',
  'https://cdn.bootcss.com/nprogress/0.2.0/nprogress.min.css'
 ],
 js: [
  'https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.min.js',
  'https://cdn.jsdelivr.net/npm/vue-router@3.0.1/dist/vue-router.min.js',
  'https://cdn.jsdelivr.net/npm/vuex@3.0.1/dist/vuex.min.js',
  'https://cdn.jsdelivr.net/npm/axios@0.18.0/dist/axios.min.js',
  'https://unpkg.com/element-ui/lib/index.js',
  'https://cdn.bootcss.com/js-cookie/2.2.0/js.cookie.min.js',
  'https://cdn.bootcss.com/nprogress/0.2.0/nprogress.min.js'
 ]
 }
}

module.exports = {
 chainWebpack: config => {
 // 这里是对环境的配置,不同环境对应不同的BASE_API,以便axios的请求地址不同
 config.plugin('define').tap(args => {
  const argv = process.argv
  const mode = argv[argv.indexOf('--project-mode') + 1]
  args[0]['process.env'].MODE = `"${mode}"`
  args[0]['process.env'].BASE_API = '"http://47.94.138.75:8000"'
  return args
 })

 /**
  * 添加CDN参数到htmlWebpackPlugin配置中, 详见public/index.html 修改
  */
 config.plugin('html').tap(args => {
  if (process.env.NODE_ENV === 'production') {
  args[0].cdn = cdn.build
  }
  if (process.env.NODE_ENV === 'development') {
  args[0].cdn = cdn.dev
  }
  return args
 })

 // svg loader
 const svgRule = config.module.rule('svg') // 找到svg-loader
 svgRule.uses.clear() // 清除已有的loader, 如果不这样做会添加在此loader之后
 svgRule.exclude.add(/node_modules/) // 正则匹配排除node_modules目录
 svgRule // 添加svg新的loader处理
  .test(/\.svg$/)
  .use('svg-sprite-loader')
  .loader('svg-sprite-loader')
  .options({
  symbolId: 'icon-[name]'
  })

 // 修改images loader 添加svg处理
 const imagesRule = config.module.rule('images')
 imagesRule.exclude.add(resolve('src/icons'))
 config.module
  .rule('images')
  .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
 },

 // 修改webpack config, 使其不打包externals下的资源
 configureWebpack: config => {
 const myConfig = {}
 if (process.env.NODE_ENV === 'production') {
  // 1. 生产环境npm包转CDN
  myConfig.externals = externals
 }
 if (process.env.NODE_ENV === 'development') {
  /**
  * 关闭host check,方便使用ngrok之类的内网转发工具
  */
  myConfig.devServer = {
  disableHostCheck: true
  }
 }
 // open: true,
 // hot: true
 // // https: true,
 // // proxy: {
 // // '/proxy': {
 // //  target: 'http://47.94.138.75',
 // //  // changeOrigin: true,
 // //  pathRewrite: {
 // //  '^/proxy': ''
 // //  }
 // // }
 // // },
 // }
 return myConfig
 }
}

最后去除 main.js 中引入的 import 'element-ui/lib/theme-chalk/index.css'

OK ,现在执行一下 build

vue-cli3 从搭建到优化的详细步骤

可以看到,相对于 793.20KB61.94k 小了将近 13 倍!!!

把这个分支部署到服务器,话不多说,对比一下就好:

vue-cli3 从搭建到优化的详细步骤

使用Gzip 加速

引入 compression-webpack-plugin : npm i -D compression-webpack-plugin https://www.webpackjs.com/plugins/compression-webpack-plugin/

修改 vue.config.js ,老规矩,上最全的代码:

const path = require('path')
const CompressionWebpackPlugin = require('compression-webpack-plugin')

function resolve(dir) {
 return path.join(__dirname, './', dir)
}

// cdn预加载使用
const externals = {
 'vue': 'Vue',
 'vue-router': 'VueRouter',
 'vuex': 'Vuex',
 'axios': 'axios',
 'element-ui': 'ELEMENT',
 'js-cookie': 'Cookies',
 'nprogress': 'NProgress'
}

const cdn = {
 // 开发环境
 dev: {
 css: [
  'https://unpkg.com/element-ui/lib/theme-chalk/index.css',
  'https://cdn.bootcss.com/nprogress/0.2.0/nprogress.min.css'
 ],
 js: []
 },
 // 生产环境
 build: {
 css: [
  'https://unpkg.com/element-ui/lib/theme-chalk/index.css',
  'https://cdn.bootcss.com/nprogress/0.2.0/nprogress.min.css'
 ],
 js: [
  'https://cdn.bootcss.com/vue/2.5.21/vue.min.js',
  'https://cdn.bootcss.com/vue-router/3.0.2/vue-router.min.js',
  'https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js',
  'https://cdn.bootcss.com/axios/0.18.0/axios.min.js',
  'https://unpkg.com/element-ui/lib/index.js',
  'https://cdn.bootcss.com/js-cookie/2.2.0/js.cookie.min.js',
  'https://cdn.bootcss.com/nprogress/0.2.0/nprogress.min.js'
 ]
 }
}

// 是否使用gzip
const productionGzip = true
// 需要gzip压缩的文件后缀
const productionGzipExtensions = ['js', 'css']

module.exports = {
 chainWebpack: config => {
 // 这里是对环境的配置,不同环境对应不同的BASE_API,以便axios的请求地址不同
 config.plugin('define').tap(args => {
  const argv = process.argv
  const mode = argv[argv.indexOf('--project-mode') + 1]
  args[0]['process.env'].MODE = `"${mode}"`
  args[0]['process.env'].BASE_API = '"http://47.94.138.75:8000"'
  return args
 })

 /**
  * 添加CDN参数到htmlWebpackPlugin配置中, 详见public/index.html 修改
  */
 config.plugin('html').tap(args => {
  if (process.env.NODE_ENV === 'production') {
  args[0].cdn = cdn.build
  }
  if (process.env.NODE_ENV === 'development') {
  args[0].cdn = cdn.dev
  }
  return args
 })

 // svg loader
 const svgRule = config.module.rule('svg') // 找到svg-loader
 svgRule.uses.clear() // 清除已有的loader, 如果不这样做会添加在此loader之后
 svgRule.exclude.add(/node_modules/) // 正则匹配排除node_modules目录
 svgRule // 添加svg新的loader处理
  .test(/\.svg$/)
  .use('svg-sprite-loader')
  .loader('svg-sprite-loader')
  .options({
  symbolId: 'icon-[name]'
  })

 // 修改images loader 添加svg处理
 const imagesRule = config.module.rule('images')
 imagesRule.exclude.add(resolve('src/icons'))
 config.module
  .rule('images')
  .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
 },

 // 修改webpack config, 使其不打包externals下的资源
 configureWebpack: config => {
 const myConfig = {}
 if (process.env.NODE_ENV === 'production') {
  // 1. 生产环境npm包转CDN
  myConfig.externals = externals

  myConfig.plugins = []
  // 2. 构建时开启gzip,降低服务器压缩对CPU资源的占用,服务器也要相应开启gzip
  productionGzip && myConfig.plugins.push(
  new CompressionWebpackPlugin({
   test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
   threshold: 8192,
   minRatio: 0.8
  })
  )
 }
 if (process.env.NODE_ENV === 'development') {
  /**
  * 关闭host check,方便使用ngrok之类的内网转发工具
  */
  myConfig.devServer = {
  disableHostCheck: true
  }
 }
 // open: true,
 // hot: true
 // // https: true,
 // // proxy: {
 // // '/proxy': {
 // //  target: 'http://47.94.138.75',
 // //  // changeOrigin: true,
 // //  pathRewrite: {
 // //  '^/proxy': ''
 // //  }
 // // }
 // // },
 // }
 return myConfig
 }
}

再次运行 build ,我们会发现 dist/ 下所有的 .js.css 都会多出一个 .js.gz、.css.gz 的文件,这就是我们需要的压缩文件,可以看到最大的只有 18.05KB ,想想是不是比较激动...

vue-cli3 从搭建到优化的详细步骤

当然,这玩意还需要服务端支持,也就是配置 nginx

gzip on;
gzip_static on;
gzip_min_length 1024;
gzip_buffers 4 16k;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php application/vnd.ms-fontobject font/ttf font/opentype font/x-woff image/svg+xml;
gzip_vary off;
gzip_disable "MSIE [1-6]\.";

配置完重启 nginx

vue-cli3 从搭建到优化的详细步骤

配置成功的话,可以看到加载的是比较小的 Gzip

vue-cli3 从搭建到优化的详细步骤

response headers 里会有一个 Content-Encoding:gzip

vue-cli3 从搭建到优化的详细步骤

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
深入理解javascript的执行顺序
Apr 04 Javascript
在JavaScript中构建ArrayList示例代码
Sep 17 Javascript
基于javascript实现全国省市二级联动下拉选择菜单
Jan 28 Javascript
Bootstrap模态框水平垂直居中与增加拖拽功能
Nov 09 Javascript
微信小程序 实现拖拽事件监听实例详解
Nov 16 Javascript
纯js仿淘宝京东商品放大镜功能
Mar 02 Javascript
JS中SetTimeout和SetInterval使用初探
Mar 23 Javascript
详解webpack es6 to es5支持配置
May 04 Javascript
js实现倒计时关键代码
May 05 Javascript
对vue事件的延迟执行实例讲解
Aug 28 Javascript
webpack自动打包和热更新的实现方法
Jun 24 Javascript
layui写后台表格思路和赋值用法详解
Nov 14 Javascript
微信小程序实现富文本图片宽度自适应的方法
Jan 20 #Javascript
实例介绍JavaScript中多种组合继承
Jan 20 #Javascript
VUE简单的定时器实时刷新的实现方法
Jan 20 #Javascript
小程序开发中如何使用async-await并封装公共异步请求的方法
Jan 20 #Javascript
Django+vue跨域问题解决的详细步骤
Jan 20 #Javascript
如何在vue里面优雅的解决跨域(路由冲突问题)
Jan 20 #Javascript
JavaScript禁用右键单击优缺点分析
Jan 20 #Javascript
You might like
xml在joomla表单中的应用详解分享
2012/07/19 PHP
探讨php define()函数及defined()函数使用详解
2013/06/09 PHP
php json_encode与json_decode详解及实例
2016/12/13 PHP
ThinkPHP3.1.x修改成功与失败跳转页面的方法
2017/09/29 PHP
PHP优化之批量操作MySQL实例分析
2020/04/23 PHP
用javascript动态调整iframe高度的代码
2007/04/10 Javascript
对xmlHttp对象方法和属性的理解
2011/01/17 Javascript
toggle一个div显示或隐藏且可扩展成自定义下拉框
2013/09/12 Javascript
JQuery的$命名冲突详细解析
2013/12/28 Javascript
jquery实现点击消失的代码
2014/03/03 Javascript
JS中产生标识符方式的演变
2015/06/12 Javascript
JavaScript 经典实例日常收集整理(常用经典)
2016/03/30 Javascript
Bootstrap菜单按钮及导航实例解析
2016/09/09 Javascript
Bootstrap Navbar Component实现响应式导航
2016/10/08 Javascript
Jquery实现跨域异步上传文件总结
2017/02/03 Javascript
浅谈$_FILES数组为空的原因
2017/02/16 Javascript
vue双向绑定简要分析
2017/03/23 Javascript
JavaScript 值类型和引用类型的初次研究(推荐)
2017/07/19 Javascript
JS随机排序数组实现方法分析
2017/10/11 Javascript
ES6 对象的新功能与解构赋值介绍
2019/02/05 Javascript
vue-quill-editor 自定义工具栏和自定义图片上传路径操作
2020/08/03 Javascript
python使用线程封装的一个简单定时器类实例
2015/05/16 Python
Python中遇到的小问题及解决方法汇总
2017/01/11 Python
python导入csv文件出现SyntaxError问题分析
2017/12/15 Python
Python及Pycharm安装方法图文教程
2019/08/05 Python
Python语法之精妙的十个知识点(装B语法)
2020/01/18 Python
解决html5中video标签无法播放mp4问题的办法
2017/05/07 HTML / CSS
AmazeUI 单选框和多选框的实现示例
2020/08/18 HTML / CSS
英国网上自行车商店:Tredz Bikes
2019/10/29 全球购物
工程地质勘察专业大学生求职信
2013/10/13 职场文书
年会搞笑主持词
2014/03/27 职场文书
2014年中秋节活动总结
2014/08/29 职场文书
机动车交通事故协议书
2015/01/29 职场文书
业务员年终工作总结2015
2015/05/28 职场文书
python状态机transitions库详解
2021/06/02 Python
Java设计模式中的命令模式
2022/04/28 Java/Android