美文网首页让前端飞Web前端之路收藏
好几步优化超大单页应用启动速度,3分钟=>30秒

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

作者: HuaRongSAO | 来源:发表于2019-06-14 18:26 被阅读23次

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

    序言

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


    image

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

    image

    故事环境

    祖传代码,一代传一代。

    • 1.好的,我们先分析一下当前项目环境吧
    # 进入项目
    cd project/
    # 查看项目下有多少文件
    ls -lR| grep "^-" | wc -l
    => 43305 # 眉头一紧,事情不对,这么多文件
    # 删除项目依赖
    rm -rf node_modules
    # 在看一次
    ls -lR| grep "^-" | wc -l
    => 1408 # 眉头又是一紧,事情没有不对,就是文件真的多
    
    • 2.然后,em,我们统计一下有多少路由?em,怎么分析呢?
    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,四百多个页面,教练,我要去学做菜
    
    • 3.我们统计一下编译时间吧
      打开命令行,一顿操作。
    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%以上的时间优化,但是,文件数量在那,总和的时间也不会低。

    关键原因:不会。

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

    • 1.找到路由文件,删,代码全删了

    /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
    • 2.写个脚本动态修改路由文件,动态添加路由模块

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

    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;
    

    以上:就是优化的原理。

    • 3.脚本实现修改文件

    在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文件系统,监听到文件变化自动重启。

    • 4.脚本怎么用呢?需要的时候node build/init-router?

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

    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
    • 5.最终效果

    em,累死我了。

    p4.png

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

    • 1.window1o
      优化前:
      1975557014.jpg

    优化后:

    335275594.jpg
    • 2.linux-monjaro
      优化前:
    优化前

    优化后:

    优化后

    总结

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

    和尚是没头发的。

    em。

    相关文章

      网友评论

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

        本文链接:https://www.haomeiwen.com/subject/ejxpfctx.html