让前端飞Web前端之路收藏

好几步优化超大单页应用启动速度,3分钟=>30秒

2019-06-14  本文已影响23人  HuaRongSAO

em,要怎么才能不让文章那么枯燥呢?

序言

一篇好的文章,技术是不是不太必要,关键是不是要有好的故事呢?


image

故事开始:从前从前山上有座庙,庙里有个老和尚,和一群小和尚。那天老和尚对小和尚说:系统大了,速度慢了,臃肿了,是时候优化了。有个趋势叫“微前端”,就你了,搞着去吧。
小和尚:...
小和尚很努力的查找资料,查看书籍,准备demo,请教大佬。日子一天天的过去,眼瞅事情要黄了...
小和尚收拾收拾东西,赶紧下山...
end

image

故事环境

祖传代码,一代传一代。

# 进入项目
cd project/
# 查看项目下有多少文件
ls -lR| grep "^-" | wc -l
=> 43305 # 眉头一紧,事情不对,这么多文件
# 删除项目依赖
rm -rf node_modules
# 在看一次
ls -lR| grep "^-" | wc -l
=> 1408 # 眉头又是一紧,事情没有不对,就是文件真的多
const projectRoute = {
    path: "project",
    component: (resolve) => require(["@/vankely/sub-layout.vue"], resolve),
    children: [ {
        path: "shopConditions",
        meta: "/admin/project/shopConditions",
        component: ShopConditionsIndex
    }]
};

就简单的统计一下‘path’出现的次数吧,虽然不怎么严谨,但是,我们不是写技术文章的呀

grep -rn "path" src/router/ | wc -l
=> 474  # em,四百多个页面,教练,我要去学做菜
yarn  dev # 开始编译
=> 项目启动:2019-06-14 04:14:13
=> ...
=> 期间:我去上了个厕所
=> 期间:我去到了杯水
=> 期间:我发了个呆,比特币上100w美金了
=> ....
=> 项目成功:2019-06-14 04:18:56
=> 项目耗时:4分钟43秒
=> Listening at http://0.0.0.0:8080/

em,就只看我的电脑,是不是不严谨,找隔壁的小姐姐问了一下他的启动时间。

p2.jpg

11分钟,em.
em,对不起,公司发的我的笔记本,再也不嫌弃你性能差了。

后面发现是因为node版本太低,老年车,拖拉机。升级到最新的后,也是3分多钟。
em,垃圾笔记本,性能真差(嫌弃的敲了一下笔记本,结果删了点代码,隔天真开心)。

image

正文

本文不讲那些webpack升级,happyPack,DLLPlugin等等很多技巧。

主要是作用不大,量变引起质变,算以上能带来50%以上的时间优化,但是,文件数量在那,总和的时间也不会低。

关键原因:不会。

我们找到根本原因是文件数量太多,那我们启动的时候给他减肥减肥

/src/router/index.js
只留页面启动必要的页面,其他的删


const router = new Router({
    mode: "history",
    routes: [
        {
            path: "/login",
            meta: { permission: "public" },
            component: Login
        },
      {
            path: "/user",
            meta: { permission: "public" },
            component: User
        }
        
    ]
});
export default router;

启动一下:18秒。
em,快是真的快了,可怎么开发呢?
啥页面都没有。

image

哎呦,这可真的秀 ~~. ლ(・ω・ლ)

em,那就建文件专门存放路由模块吧!
然后,我们就写个脚本专门修改这个文件吧
src/router/routes-modules.js

import routes1 from "./routes1";
import routes2 from "./routes2";
import routes3 from "./routes3";
const syncRoutes = [
            ...routes1,
            ...routes2,
            ...routes3
];
export default syncRoutes;

修改 src/router/index.js

import syncRoutes from './routes-modules'
const router = new Router({
    mode: "history",
    routes: [
        {
            path: "/login",
            meta: { permission: "public" },
            component: Login
        },
      ... syncRoutes
    ]
});
export default router;

em,那我要怎么配置加载什么文件呢?
新增 src/router/router-config.json,为什么用json呢,因为开心。(主要是为了方便以后,方便es模块导入和node模块导入)

[
    {
        "name": "模块1",
        "key": "route1",
        "path": "./route1/index",
        "use": true
    },
    {
        "name": "模块1",
        "key": "route2",
        "path": "./route2/index",
        "use": false
    },
{
        "name": "模块1",
        "key": "route2",
        "path": "./route2/index",
        "use": false
    }
]

em,这个到底是干嘛用的?
经过脚本加工,然后修改src/router/routes-modules.js文件的内容,将“use”为true的输出到文件里面
得到:

import routes1 from "./routes1";
const syncRoutes = [
           ...routes1
];
export default syncRoutes;

以上:就是优化的原理。

在webpack配置文件里,新增一个脚本文件,伪代码,因为细节全上就太多了。
/build/init-route.js

const template = `
$$$___import___$$$
const syncRoutes = [
       $$$___routes___$$$
];
export default syncRoutes;
`;
const fs = require("fs");
const path = require("path");
const isProd = process.env.NODE_ENV === "production";
// 从项目根目录起
const resolve = dir => path.join(__dirname, "../..", dir);
const routesConf = resolve("src/router/router-config.json")
const routeModules = resolve("src/router/routes-modules.js")
const initRoute = (modules = []) => {
      let  content = template;
      // 文件是否存在, 不存在就生成
     if (fs.existsSync(routeModules)) {
           content=content.replace("$$$___import___$$$", "").replace("$$$___routes___$$$", "");
           // 创建文件,并写入内容
           createFile();
           return;
     }
     const contObj = {
        "$$$___import___$$$": "",
        "$$$___routes___$$$": ""
    }
    routesConf.forEach(r => {
        if (r.use || modules.includes(r.key)) {
             contObj["$$$___import___$$$"] += `\nimport ${rou.key} from "${rou.path}";`;
             contObj["$$$___routes___$$$"] += `\n ...${rou.key},`;
        }
    })
 content=content.replace("$$$___import___$$$", contObj["$$$___import___$$$"])
                     .replace("$$$___routes___$$$", contObj["$$$___routes___$$$"]);
    // 将文字内容替换到  src/router/routes-modules.js
    updateFile(content);
};
module.exports = initRoute;

说明:
脚本暴露的方法,用于传入数组,然后更新src/router/routes-modules.js,然后webpack文件系统,监听到文件变化自动重启。

为了更有好的开发,就想着写个快捷入口,放页面。

p3.png

biubiu,biubiu生成
组件上的选项来自"src/router/router-config.json"
当我点击 ‘生效’ 的时候,将中的key传给后端?
em,没后端!
当我点击生成的时候,将中的key传给谁?
em,那我当个后端,牛逼前后端,全栈(不接受反驳)。
em,webpack是express起的服务。

找到启动webpack的express文件,我的叫devServer.js。
你的叫什么,不要问我,我也不知道。

/*eslint no-console: 0 */

const express = require("express");
const webpack = require("webpack");
const webpackConfig = require("./webpack.config");
const bodyParser = require("body-parser");

const initRoute = require("./sync-router/init-router");
initRoute([]);


const app = express();
app.use(bodyParser.json());

// 添加一个post拦截请求  用来监听是否要修改  src/router/routes-modules.js  文件
app.post("/__setting", async (req, res) => {
    await initRoute(req.body.routes);
    res.send("hello world"});
});

const compiler = webpack(webpackConfig);
const port = appConfig.devServer.port;
const devMiddleware = require("webpack-dev-middleware")(compiler,);
const hotMiddleware = require("webpack-hot-middleware")(compiler);

app.use(require("connect-history-api-fallback")());
app.use(devMiddleware);
app.use(hotMiddleware);

app.use("/", express.static(utils.resolve("static")));

app.listen(port, (err) => {
    console.log(`Listening at http://0.0.0.0:${appConfig.devServer.port}/`);
    opn(`http://127.0.0.1:${port}`);
});
image

em,累死我了。

p4.png

上点优化后的启动时间变化:

优化后:

335275594.jpg 优化前

优化后:

优化后

总结

微前端没做成,倒是达成一项新成就,逗逼的写了一篇文章。

和尚是没头发的。

em。

上一篇下一篇

猜你喜欢

热点阅读