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

  • 相关阅读:
    GitHub统计
    不错的第三方控件
    仿射变换(CGAffineTransform)使用小结
    AffineTransform(仿射变换)
    使用CAShapeLayer实现复杂的View的遮罩效果
    使用CAShapeLayer实现一个音量大小动态改变的控件
    window10 Docker仓库访问
    postgresql从timestamp(6)复制到timestamp(0),时间会变
    在编译Dll文件的时候遇到dll 链接不一致的问题
    qtquery 取列的值
  • 原文地址:https://www.cnblogs.com/huangcy/p/11418791.html
Copyright © 2011-2022 走看看