如何使得Svelte项目输出ES5代码

作者 happyWang 日期 2019-08-13 浏览量
如何使得Svelte项目输出ES5代码

为什么需要ES5的代码

最近在开发公司的一个项目时,为了最小化代码文件,就上手尝试了一下svelte,这个目前号称编译后代码包最小的框架,通过把大部分的计算放在编译时进行,而不是在运行时进行,从而极大程度上减少了运行时库文件的大小

目前来说,效果很棒,完成一些简单的功能开发之后,整个production模式下编译的代码包在70KB左右,gzip之后的体积是26.5KB,可以说是很惊艳了。不跟React比,跟同样号称代码包很小的Vue.js比,Vue.js项目,不说业务代码,单单库文件(v2.6.10版本)就有83KB了。

不过有一点问题是,svelte官方认为目前浏览器大部分都已经支持了ES6,所以他们提交到npm的runtime的代码也是直接输出的es6的代码。

一开始我也比较认可这个说法的,自己的项目代码也输出的es6,然后上线了。

之后我发现国外的浏览器跟国内还是不一样的进化程度。这个项目是有用fundebug来做错误监控的,上线没多久之后,错误就一直不断

所以还是需要面对现实,代码还是ES5的香,就像当初为了兼容IE6,7时候写ES3的代码一样

事情没那么简单

首先是自己的业务代码,是基于babel进行代码转换的,用的@babel/preset-env,配置的targets值为> 2% in CN, last 2 major versions, not dead

不过可能我们业务面对的用户群跟 browserslist-compatible 收集的数据不太匹配,编译后的代码里面const, arrow function, spread等等特性的代码都还在,没办法,又只好手动指定来一些plugin,最终的.babelrc内容如下:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": "> 2% in CN, last 2 major versions, not dead",
        "debug": true,
        "include": [
          "@babel/plugin-transform-block-scoping",
          "@babel/plugin-transform-spread",
          "@babel/plugin-transform-destructuring",
          "@babel/plugin-proposal-object-rest-spread",
          "@babel/plugin-transform-arrow-functions",
          "@babel/plugin-transform-parameters"
        ]
      }
    ]
  ]
}

这番配置之后,业务代码是已经都转换为ES5的了,可是从svelte import过来的代码,却没有被正确转换为ES5的。

在网上搜了一些解决方案,一个svelte-loader里面的issue给了一个解决方案,思路是使用loader进行相应格式文件处理的时候,把node_modules/svelte/模块下的文件也处理一下

尝试了一下,发现并不可以,也不知道是svelte的版本升级之后不兼容,还是我这边配置有问题

自行编译svelte

最后我想,既然我没法在项目里面把svelte的runtime代码丢给babel处理,那不如从源头解决这个问题。git clone下来svelte,编译为es5的代码,然后在用yarn link的方式引用到业务项目里面

因为svelte是基于typescript编写的,当时在我看来,改编译为es5很简单,直接在tsconfig.json里面把targets改成es5,然后运行npm run build命令来重新编译即可。

可是不行。

再仔细看了一下rollup.config.js

import sucrase from 'rollup-plugin-sucrase';
import typescript from 'rollup-plugin-typescript';
const ts_plugin = is_publish
    ? typescript({
        include: 'src/**',
        typescript: require('typescript')
    })
    : sucrase({
        transforms: ['typescript']
    });

在publish环境下使用typescript来编译ts文件,其他情况下使用Sucrase来编译ts文件

很奇怪的是,build命令并没有设定环境为publish。而Sucrase,看了一下,是一个Babel的替代品,为了加快编译速度,编译出来的代码都是面向现代浏览器,也就是没有什么语法转换和polyfill的。

为了能够使用typescript来编译,调整了一下package.json里面的build命令

rollup -c && npm run tsd改成PUBLISH=true rollup -c && npm run tsd

再重新执行build命令,成功。

然后再回到已经把svelte link到本地的业务项目,重新编译。

结果再次失败,原来直接已production环境执行build,会干扰svelte compiler的编译结果。

只好在本地svelte项目里面再回滚build命令,同时,单独调整rollup.config.js,隔离runtime和compiler所使用的ts文件的编译程序,使得runtime始终使用typescript来编译。

重新执行build命令,成功

在回到业务项目,重新编译,顺利通过,svelte runtime相关代码也都是es5的了