zoukankan      html  css  js  c++  java
  • 写一个自己的打包工具-打包原生项目

    背景

    早期写了一个很老的项目,目前一直在迭代维护。

    没有用到模块化的思想,也没有用到目前流行的框架,就是引入了一些简单的样式库。

    目前遇到的问题有:

    1、代码未做压缩等处理,占用空间比较大

    2、每次更新版本都需要清一下缓存才能读取到最新的静态资源

    3、有一些新的ES6语法和老的语法混用之后兼容性不佳

    所以就想着自己写一个简单的打包工具吧

    需求分析

    1、循环读取本地文件,分离不同类型文件

    2、用babel对JS文件做一次转换后压缩,压缩CSS文件

    3、对JS、CSS文件做hash计算,并在输出的文件名后面添加hash小尾巴

    4、修改HTML中的引用链接,压缩HTML

    功能实现

    1、循环读取本地文件,分离不同类型文件。

    这里用的最简单的正则表达式来区分不同的文件类型,主要用到了node中的fs模块和path模块。

    const readRegDirSync = (filePath, reg, pathArray) => {
        const pa = fs.readdirSync(filePath);
        if (!pathArray) {
            pathArray = [];
        }
        pa.forEach(function (ele) {
            let info = fs.statSync(path.join(filePath, ele));
            if (info.isDirectory()) {
                return pathArray.concat(readRegDirSync(path.join(filePath, ele), reg, pathArray));
            } else {
                let newPath = path.join(filePath, ele);
                if (reg.test(ele)) {
                    pathArray.push(newPath);
                }
            }
        });
        return pathArray
    };

    对于node我也还是个小白,就不分享自己的心得,具体使用说明最好看文档。

    具体的文档点这里:fs | Node.js API 文档     path | Node.js API 文档

    另外需要注意的是,不同操作系统的路径分隔符有所不同。

    最后会得到类似这样的文件路径数组:["my_sourcecssglobal.css", "my_sourcecssindex.css"]

    2-3、对文件进行处理

    JS使用babel对语法进行处理,用babel-minify压缩整个文件,CSS用clean-css来进行压缩

    然后用crypto模块来计算文件内容的hash值,给文件添加一个hash的小尾巴。

    最后把对应的文件名返回,建立一个依赖对应表,方面我们后续替换路径使用。

    const fileAnalyser = (filePath, dirPath, fileType) => {
        let fileContent = getScript(filePath);
        let writeCode;
        if (fileType === 'script') {
            fileContent = babel.transformSync(fileContent, {
                presets: ["@babel/preset-env"]
            }).code;
            if (mode === 'production') {
                const {code} = babelMinify(fileContent, {
                    mangle: {
                        keepClassName: true
                    }
                });
                writeCode = code;
            } else if (mode === 'development') {
                writeCode = fileContent;
            }
        } else if (fileType === 'css') {
            if (mode === 'production') {
                writeCode = new CleanCSS({}).minify(fileContent).styles;
            } else if (mode === 'development') {
                writeCode = fileContent;
            }
        }
        let dir = path.parse(filePath).dir;
        let sourceDir = dir.slice(dir.indexOf("\") + 1);
        let nowName = path.parse(filePath).name + '.' + crypto.createHash('md5').update(writeCode).digest('hex') + (fileType === 'script' ? '.js' : '.css');
        let fileDir = path.join(dirPath, sourceDir);
        let filename = path.join(fileDir, nowName);
        if (mkdirsSync(fileDir)) {
            fs.writeFileSync(filename, writeCode);
            return filename
        }
    };

    我在这里区分了不同的环境的打包模式,这个模式的值是命令行传入可修改的,默认值为development

    然后将得到的文件名和原始的文件名建立一个依赖对应表

    cssDependencies[path.parse(cssArray[i]).base] = path.parse(cssPath).base;

    我们就会得到类似这样的对应关系

    {global.css: "global.ac2aa87fad6ff0ced8abd4d300013047.css"
    ,index.css: "index.3261ae5739c390959d2105336d2b2733.css"}

    4、修改HTML中的引用链接

    用cheerio来解析HTML,然后根据刚才我们存下来的依赖对应表来修改其中的链接引用。

    最后再用html-minifier压缩一下HTML。

    const htmlAnalyseScript = (filePath, scriptDependencies, cssDependencies, dirPath) => {
        const content = fs.readFileSync(filePath, 'utf-8');
        const $ = cheerio.load(content);
        const getScript = $('script');
        for (let i = 0; i < getScript.length; i++) {
            if (getScript[i].attribs.src) {
                let pathIndex = getScript[i].attribs.src.lastIndexOf("/") + 1;
                let prePath = getScript[i].attribs.src.slice(0, pathIndex);
                let scriptPath = getScript[i].attribs.src.slice(pathIndex);
                let scriptKey = Object.keys(scriptDependencies);
                let scriptIndex = scriptKey.indexOf(scriptPath);
                if (scriptIndex > -1) {
                    $(getScript[i]).attr('src', prePath + scriptDependencies[scriptPath])
                }
            }
        }
        const getCSS = $('link');
        for (let i = 0; i < getCSS.length; i++) {
            if (getCSS[i].attribs.href) {
                let pathIndex = getCSS[i].attribs.href.lastIndexOf("/") + 1;
                let prePath = getCSS[i].attribs.href.slice(0, pathIndex);
                let cssPath = getCSS[i].attribs.href.slice(pathIndex);
                let cssKey = Object.keys(cssDependencies);
                let cssIndex = cssKey.indexOf(cssPath);
                if (cssIndex > -1) {
                    $(getCSS[i]).attr('href', prePath + cssDependencies[cssPath])
                }
            }
        }
        let dir = path.parse(filePath).dir;
        let sourceDir = dir.slice(dir.indexOf("\") > -1 ? dir.indexOf("\") + 1 : dir.length);
        let fileDir = path.join(dirPath, sourceDir);
        let filename = path.join(fileDir, path.parse(filePath).base);
        if (mkdirsSync(fileDir)) {
            fs.writeFileSync(filename, minifyHTML($.html(), {
                removeComments: true,
                collapseWhitespace: true,
                minifyCSS: true
            }));
            return filename
        }
    };

    需要注意的是cheerio会将HTML中的中文转换为unicode字符,因为对项目没有影响,也就没有再去做处理。

    来看看最后的效果

    对于我自己的项目来说,还是很有用的,每次更版本不用清一些缓存,也不用担心一些简单的兼容性问题,最主要的是整个项目的大小缩小了很多。

    当然最好的情况自然是用模块化的方式来写项目。

    总结一下:node真滴好用!很多模块已经很成熟了,文档也很完整,想做什么功能一搜就有!

    目前做的功能还是很单薄的,希望能给想自己写一个小工具的人,提供一些可行的思路。

    这个小工具的不足之处:

    1、只对JS、HTML、CSS文件做了处理,下面应该还要对图片等静态资源做处理。

    2、打包速度还是有点慢原因在于:读取文件的时候是每读一种文件都循环一次的,这个逻辑应该可以改成读一个文件识别为某个文件类型就进行处理。

    源码地址:https://github.com/Chellyyy/myBundler

  • 相关阅读:
    Algorithm Gossip (48) 上三角、下三角、对称矩阵
    .Algorithm Gossip (47) 多维矩阵转一维矩阵
    Algorithm Gossip (46) 稀疏矩阵存储
    Algorithm Gossip (45) 费氏搜寻法
    Algorithm Gossip (44) 插补搜寻法
    Algorithm Gossip (43) 二分搜寻法
    Algorithm Gossip (42) 循序搜寻法(使用卫兵)
    Algorithm Gossip (41) 基数排序法
    Algorithm Gossip (40) 合并排序法
    AlgorithmGossip (39) 快速排序法 ( 三 )
  • 原文地址:https://www.cnblogs.com/huangcy/p/11418791.html
Copyright © 2011-2022 走看看