bundleless开发的一些思考

2020-11-12codingbundlelesssnowpack

在开发过程中,我们使用最新的语言特性,及支持最新特性的浏览器,同时,也使用sourcemap hot reloading, hot replacement 来提高开发效率。但在build产物时,则会开启混淆压缩,编译到es5环境。

​ 为什么会产生这种分歧呢?是因为服务对象的不同。在开发过程中,开发者倾向于提高开发效率和面向未来编程,而在使用过程中,用户需要稳定且兼容的服务,无论他使用的什么浏览设备,浏览器及任何版本都可以正常运行。因此开发中的编译处理是十分有必要的。

​ 但大部分编译都是有副作用的,为了避免这些问题,应该满足以下因素

  1. 尽可能的无副作用

在开启混淆压缩时,会对变量进行重命名,如果语句中有eval就可能会出现副作用。

在编译到es5环境中,某些特性没有完整的polyfill,也会带来副作用。

可以通过限制语法,来实现副作用的减少。

  1. 完备的测试

自动测试。

各个环境的测试。(有没有可能实现自动测试多个环境的工具?)

​ 而bundless也可以是开发中的一环。在开发过程中由于资源加载速度没有限制,我们完全可以不进行打包,而选择加载分离的js文件,在对应js变化时也可只编译对应js文件。

简单实现

独立编译

每一个文件都要进行对应的处理,比如不同的模块配置。

  1. 使用esm模块,浏览器支持此模块

  2. cjs模块,编译到esm模块

    cjs在限制部分语法的情况下,可以编译到esm模块

    // hello.js
    module.exports = function hello() {
        console.log('hello');
    } //====> export default function hello()
    // world.js
    module.exports = function hello() {
        console.log('world');
    } //====> export default function hello()
    // index.js
    const hello2 = () => {
        require('./hello.js')();
        require('./world.js')();
    }
    module.exports = hello2;
    // ===> 比如检测 require('xxx')的正则表达式,限制参数只能是字符串
    import hash1 from './hello.js';
    import hash2 from './world.js';
    const hello2 = () => {
        hash1();
        hash2();
    }
    module.exports = hello2;

    当然也可以自己不使用esm格式,像amd类似的格式也可以

    wrapper('./hello.js', './world.js', function() {
        const hello2 = () => {
            require('./hello.js')();
            require('./world.js')();
        }
        module.exports = hello2;
    });
    // 全局变量wrapper, 在加载完子依赖后再执行后续内容
    // 全局变量require, 加载文件,如果已经加载则返回缓存
    // module.exports 表明此模块最终加载结果。

按需编译

  • node_modules里的依赖

如果有esm格式可直接使用,如果没有可以编译到esm格式,并生成对应版本的缓存。只有在更新版本时才会重新生成缓存。(之前使用snowpack过程中,更新了软件包但还是使用旧版本的缓存,需用snowpack —reload清空,较为不方便)

  • 导入js文件
  1. 启动express服务, 最开始所有js文件都标记为dirty。
  2. 在访问到标记dirty的js文件时,对js文件进行编译,返回编译后的文件,清除dirty标记。
  3. 在访问没有dirty标记的文件时,直接返回上次编译文件。
  4. 通过watchFile(比如chokidar)监测js文件的更改,在更改后将此文件标记为dirty,刷新页面。

hot replacement 热重载

​ 文件改变时,触发该文件刷新

​ 该文件的父依赖接受到子依赖刷新事件

​ 因此父依赖代码中应包含对应的处理代码,如果处理不了则触发父依赖进一步刷新。

总结

​ bundleless是未来。目前受限的一个原因是因为部分现有的软件包并没有esm格式。

​ bundleless的思想也可应用到别的方面,比如在游戏开发中,直接导入分离的图片素材,而在发布时可以将图片自动打包成一张或多张图片,也可按需加载,在使用到某个素材时才加载对应的打包好的图片。不过需要增加一个处理层,确保分离导入和打包导入都能获得一致的返回结果。

​ 在这种开发模式中,测试驱动型开发(BDD)可以大展身手。因为有完备的测试逻辑,能在不合理地使用了被限制的语法时得到测试失败提示,从而可以更”冒进”地进行工程开发,在追求开发效率的路上狂奔。

The end