关于VUE前端项目的优化

邱秋 • 2018年03月20日 • 阅读:4931 • vue

今天终于得空了,我要把 kui 说明文档这个项目优化下。打开太慢了,就是这个 http://k-ui.cn

10 几秒才能展示完全,真受不了。来张图就明白了

看到这个就没啥好意外了,为什么会这么慢。

因为说明文档的 webpack 配置没用 vue-cli 脚手架,自己手动配置的,所以问题估计会多些吧

1)webpack 配置出错,导致库重复被编译到一个文件里

逐步检查了编译后比较大的文件,发现 index.js 也就是入口文件,其内容有 vue 库被重复打包了。如下图

一句句排查 webpack 配置,没有发现问题,那么到底问题出在哪里呢,搜索了下 vue 的引入,发现有 3 个文件有引入 vue ,但是这并不影响编译重复啊,不应该的,最后终于发现了问题,由于是 mac 环境大小写敏感所致,手一抖 “import Vue from 'vue'” 写成了 “import Vue from 'Vue'”

看似没有任何问题 debug 调试也不会出错。但是问题就出现在这里,把 from 后面的 “Vue” 改位 首字母 小写的 “vue” 问题解决了。重新编译后文件小了 130 多 kb。从 945kb 到 800 多 kb,继续优化吧。

2)第三方裤文件过大造成的

由于说明文档有部分要代码高亮展示,文中用到了 highlight.js 代码高亮库。自行写了个组件,代码如下:

<!-- code.vue -->
<template>
  <div v-high class="k-code">
    <pre: style="styles" ref="rel">
      <code: class="lang">
        <slot> </slot>
      </code>
    </pre>
  </div>
</template>
//code.js
import Hljs from "highlight.js";
import "highlight.js/styles/atom-one-light.css";
const vueHljs = {};
vueHljs.install = (Vue) => {
  Vue.directive("high", function (el, binding) {
    let blocks = el.querySelectorAll("pre code");
    Array.prototype.forEach.call(blocks, Hljs.highlightBlock);
  });
};
export default vueHljs;
<!-- 调用 -->
<code lang="xml html">
  {{ code }}
</code>

事实上代码这么写也不会有什么问题,但是编译后文件为什么会这么大呢,800 多 kb,于是乎我把关键的代码高亮代码注释,也就是引入 highlight.js 那里干掉。再次编译:

编译后的文件才 130kb,找到问题的根源了。

之前用谷歌的代码高亮,这次不用它了, markdown 也不想折腾。

node_modules 仔细的探究下,因为代码高亮包含了太多的语言和语法,我每次编译过后是全量包, pythonsqlc++ 等 50 几种高亮语言全在里面,但是我只要 js 和 html 语法高亮,所以就从库里提出了我想要的:

var Hljs = require("./highlight");
//只要这2个高亮语言库,其他干掉
Hljs.registerLanguage("xml", require("./lang/xml"));
Hljs.registerLanguage("javascript", require("./lang/javascript"));

再次编译,编译后 180kb,尚在接受范围。

3)js 模块没有做按需加 ​​ 载

因为 vue 是单页 web ,靠 router 来驱动 view ,随着项目越来越庞大,所以按需加载这个是必须的,不然所有的页面必然会打包在同一个 js 文件里。造成加载缓慢。

按需加载(也就是懒加载)有 3 种实现方式

1)vue 自带的异步方式

在 router push 的时候做修改即可

{
  path: '/test',
  name: 'test',
  component: resolve => require(['../components/test'], resolve)
}

2)es 提案的 import()

官方文档

注意注视内的内容,名字一样的会被打包进一个文件

const test = () => import( /* webpackChunkName: "test" */ '../components/test') {
    path: '/test',
    name: 'test',
    component: test
  },

3)webpack 提供的 require.ensure()

注意 ensure 传参,最后一个 chunkname ,不传 output 配置 chunkFilename :将会是 [id].build.js

{
  path: '/test',
  name: 'test',
  component: resolve => require.ensure([], () => resolve(require('../components/test')), 'test')
},

注:require.ensure() 是 webpack 特有的,已经被 import() 取代。

以上 3 种方式都能实现按需加载,最后在 webpack config 里面配置 chunkFilename

output: {

  path: path.resolve(__dirname, '../dist'),
  filename: 'js/[name].js', //.[hash].js',
  publicPath: '/',
  chunkFilename: 'js/[name].[chunkhash:3].js',

},

当然,我在项目里是做了按需加载的,但是最终打包的文件还是合并了。那么看看问题出现在哪里

我的路由是这么干的:

import Vue from "vue";
import Router from "vue-router";

Vue.use(Router);

let routes = [];

let r = [
  "",
  "install",
  "start",
  "log",
  "input",
  "button",
  "select",
  "switch",
  "form",
  "colorpicker",
  "loading",
  "icon",
  "timeline",
  "theme",
  "react-kui",
  "angular-kui",
  "alert",
  "message",
  "notice",
  "upload",
  "poptip",
  "menu",
  "tabs",
  "badge",
  "checkbox",
  "radio",
  "datepicker",
  "table",
  "layout",
  "page",
  "modal",
  "kyui-loader",
  "sponsor",
  "about",
];

r.forEach((x) => {
  routes.push({
    path: `/${x}`,
    component: (resolve) =>
      require([x == "" ? "./ui/index" : `./ui/${x}`], resolve),
    // component: r => require.ensure([], () => r(require(x==''?'/ui/index': `./ui/${x}` )), x)
  });
});

let routers = new Router({
  routes: routes,
  mode: "history",
});
export default routers;

按需加载看似没有问题吧,但是最后打包出来的 chunkFilename 有 300kb,而且页面全部都打进了一个 js 文件。

探究了一番,因为是异步加载,所以不能动态传值的, map 遍历的时候路径组合 x 值是动态传入,导致打包后无法识别。最后修改为静态的,问题解决了。重新编译后多个页面路由分割成单个 js 文件,每个约 10kb 左右,路由改变时,动态加载对应的 js 文件

import xx from '/dev/test‘   //这里的abc 是静态的值 如 ‘/ui/abc.vue’ {

path: 'xx',
  component: xx
}

至此,问题解决了,页面加载正常情况下延时 1-2 秒,时间缩短了将近 10 陪。

[完]

我,秦始皇,打钱!