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学习笔记(二) js一些基本概念
Jun 18 Javascript
用javascript模仿ie的自动完成类似自动完成功的表单
Dec 12 Javascript
JS图片根据鼠标滚动延时加载的实例代码
Jul 13 Javascript
js或jquery实现页面打印可局部打印
Mar 27 Javascript
如何在MVC应用程序中使用Jquery
Nov 17 Javascript
Javascript递归打印Document层次关系实例分析
May 15 Javascript
Javascript中arguments用法实例分析
Jun 13 Javascript
JavaScript中的pow()方法使用详解
Jun 15 Javascript
Angualrjs 表单验证的两种方式(失去焦点验证和点击提交验证)
May 09 Javascript
Javascript实现时间倒计时效果
Jul 15 Javascript
自适应布局meta标签中viewport、content、width、initial-scale、minimum-scale、maximum-scale总结
Aug 18 Javascript
使用Angular9和TypeScript开发RPG游戏的方法
Mar 25 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
图象函数中的中文显示
2006/10/09 PHP
php实现将字符串按照指定距离进行分割的方法
2015/03/14 PHP
php给一组指定关键词添加span标签的方法
2015/03/31 PHP
Yii核心验证器api详解
2016/11/23 PHP
Windows下wamp php单元测试工具PHPUnit安装及生成日志文件配置方法
2018/05/28 PHP
PHP实现将上传图片自动缩放到指定分辨率,并保持清晰度封装类示例
2019/06/17 PHP
PHP sdk实现在线打包代码示例
2020/12/09 PHP
js中复制行和删除行的操作实例
2013/06/25 Javascript
jquery模拟SELECT下拉框取值效果
2013/10/23 Javascript
关于onchange事件在IE和FF下的表现及解决方法
2014/03/08 Javascript
Javascript基础教程之break和continue语句
2015/01/18 Javascript
javascript中hasOwnProperty() 方法使用指南
2015/03/09 Javascript
简化版手机端照片预览组件
2015/04/13 Javascript
最精简的JavaScript实现鼠标拖动效果的方法
2015/05/11 Javascript
NodeJS配置CORS实现过程详解
2020/12/02 NodeJs
python循环监控远程端口的方法
2015/03/14 Python
Python的网络编程库Gevent的安装及使用技巧
2016/06/24 Python
Python引用类型和值类型的区别与使用解析
2017/10/17 Python
tf.truncated_normal与tf.random_normal的详细用法
2018/03/05 Python
pip安装时ReadTimeoutError的解决方法
2018/06/12 Python
keras 读取多标签图像数据方式
2020/06/12 Python
python中常见错误及解决方法
2020/06/21 Python
python rsa-oaep加密的示例代码
2020/09/23 Python
scrapy结合selenium解析动态页面的实现
2020/09/28 Python
python 两种方法删除空文件夹
2020/09/29 Python
python 数据类型强制转换的总结
2021/01/25 Python
瑞士香水购物网站:Parfumcity.ch
2017/01/14 全球购物
澳大利亚首屈一指的在线购物目的地:Kogan.com
2017/02/02 全球购物
Stefania Mode英国:奢华设计师和时尚服装
2017/10/23 全球购物
Speedo澳大利亚官网:全球领先游泳品牌
2018/02/04 全球购物
全球高级音频和视频专家:HiDef Lifestyle
2019/08/02 全球购物
外企测试工程师面试题
2015/02/01 面试题
高中校园广播稿3篇
2014/09/29 职场文书
2014大学辅导员工作总结
2014/12/02 职场文书
投资意向协议书
2015/01/29 职场文书
写作技巧:怎样写好一份优秀工作总结?
2019/08/14 职场文书