feat: add es5 target

This commit is contained in:
EGOIST 2020-07-21 15:17:02 +08:00
parent 4f36b9df1a
commit 0ebb08dd8e
7 changed files with 230 additions and 25 deletions

View File

@ -72,6 +72,10 @@ dist
└── index.js
```
### ES5 support
You can `--target es5` or `"target": "es5" in `tsconfig.json` to compile the code down to es5, it's processed by [buble](http://buble.surge.sh/). Some features are supported by this target, namely: `for .. of`.
### Watch mode
```bash

View File

@ -29,6 +29,7 @@
},
"devDependencies": {
"@rollup/plugin-json": "^4.1.0",
"@types/buble": "^0.19.2",
"@types/fs-extra": "^9.0.1",
"@types/jest": "^26.0.5",
"@types/node": "^14.0.23",
@ -40,6 +41,8 @@
"rollup-plugin-hashbang": "^2.2.2",
"ts-jest": "^26.1.3",
"tsup": "^3.0.0",
"typescript": "^3.9.7"
"typescript": "^3.9.7",
"strip-json-comments": "^3.1.1",
"buble": "^0.20.0"
}
}

View File

@ -2,9 +2,11 @@ import fs from 'fs'
import { dirname, join } from 'path'
import { Worker } from 'worker_threads'
import colors from 'chalk'
import { transform as transformToEs5 } from 'buble'
import { Service, startService, BuildResult } from 'esbuild'
import { getDeps, resolveTsConfig } from './utils'
import { getDeps, loadTsConfig } from './utils'
import { FSWatcher } from 'chokidar'
import { PrettyError } from './errors'
const textDecoder = new TextDecoder('utf-8')
@ -63,11 +65,13 @@ export async function runEsbuild(
globalName: options.globalName,
jsxFactory: options.jsxFactory,
jsxFragment: options.jsxFragment,
target: options.target === 'es5' ? 'es2016' : options.target,
define: options.define,
external,
outdir: format === 'cjs' ? outDir : join(outDir, format),
write: false,
splitting: format === 'cjs' || format === 'esm',
logLevel: 'error'
}))
const timeInMs = Date.now() - startTime
console.log(
@ -91,25 +95,41 @@ export async function runEsbuild(
result.outputFiles.map(async (file) => {
const dir = dirname(file.path)
const outPath = file.path
if (!outPath.endsWith('.js')) return
await fs.promises.mkdir(dir, { recursive: true })
let mode: number | undefined
if (file.contents[0] === 35 && file.contents[1] === 33) {
mode = 0o755
}
// Cause we need to transform to code from esm to cjs first
if (format === 'cjs' && outPath.endsWith('.js')) {
const content = transform(textDecoder.decode(file.contents), {
transforms: ['imports'],
})
await fs.promises.writeFile(outPath, content.code, {
encoding: 'utf8',
mode,
})
} else {
await fs.promises.writeFile(outPath, file.contents, {
mode,
})
let contents = textDecoder.decode(file.contents)
if (options.target === 'es5') {
try {
contents = transformToEs5(contents, {
source: file.path,
file: file.path,
transforms: {
modules: false,
arrow: true,
dangerousTaggedTemplateString: true,
spreadRest: true,
},
}).code
} catch (error) {
throw new PrettyError(
`Error compiling to es5 target:\n${error.snippet}`
)
}
}
// Cause we need to transform to code from esm to cjs first
if (format === 'cjs') {
contents = transform(contents, {
transforms: ['imports'],
}).code
}
await fs.promises.writeFile(outPath, contents, {
encoding: 'utf8',
mode,
})
})
)
}
@ -124,6 +144,8 @@ function stopServices() {
}
export async function build(options: Options) {
options = { ...options }
let watcher: FSWatcher | undefined
let runServices: Array<() => Promise<BuildResult | void>> | undefined
@ -150,11 +172,25 @@ export async function build(options: Options) {
}
try {
const tsconfig = resolveTsConfig(process.cwd())
if (tsconfig) {
console.log(makeLabel('CLI', 'info'), `Using tsconfig: ${tsconfig}`)
const tsconfig = await loadTsConfig(process.cwd())
if (tsconfig.path && tsconfig.data) {
console.log(makeLabel('CLI', 'info'), `Using tsconfig: ${tsconfig.path}`)
if (!options.target) {
options.target = tsconfig.data.compilerOptions?.target
}
if (!options.jsxFactory) {
options.jsxFactory = tsconfig.data.compilerOptions?.jsxFactory
}
if (!options.jsxFragment) {
options.jsxFragment = tsconfig.data.compilerOptions?.jsxFragmentFactory
}
}
if (!options.target) {
options.target = 'es2018'
}
console.log(makeLabel('CLI', 'info'), `Target: ${options.target}`)
runServices = await Promise.all([
...options.format.map((format) => runEsbuild(options, { format })),
])
@ -164,7 +200,7 @@ export async function build(options: Options) {
worker.postMessage({
options,
})
worker.on('message', data => {
worker.on('message', (data) => {
if (data === 'exit') {
worker.unref()
}

View File

@ -1,7 +1,19 @@
import fs from 'fs'
import JoyCon from 'joycon'
import stripJsonComments from 'strip-json-comments'
const joycon = new JoyCon()
joycon.addLoader({
test: /\.json$/,
async load(filepath) {
const content = stripJsonComments(
await fs.promises.readFile(filepath, 'utf8')
)
return JSON.parse(content)
},
})
// No backslash in path
function slash(input: string) {
return input.replace(/\\/g, '/')
@ -45,8 +57,8 @@ export function isExternal(
return false
}
export function resolveTsConfig(cwd: string) {
return joycon.resolveSync(['tsconfig.build.json', 'tsconfig.json'], cwd)
export function loadTsConfig(cwd: string) {
return joycon.load(['tsconfig.build.json', 'tsconfig.json'], cwd)
}
export async function getDeps(cwd: string) {

View File

@ -1,5 +1,19 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`es5 target 1`] = `
"\\"use strict\\";Object.defineProperty(exports, \\"__esModule\\", {value: true});// input.ts
var Foo = function Foo () {};
Foo.prototype.hi = function hi () {
var a = function () { return \\"foo\\"; };
console.log(a());
};
exports.Foo = Foo;
"
`;
exports[`simple 1`] = `
"\\"use strict\\";Object.defineProperty(exports, \\"__esModule\\", {value: true});// foo.ts
var foo_default = \\"foo\\";

View File

@ -24,14 +24,16 @@ function runTest(
return fs.outputFile(join(testDir, name), files[name], 'utf8')
})
)
const { exitCode } = await execa(
const { exitCode, stdout, stderr } = await execa(
bin,
['input.ts', ...(options.flags || [])],
{
cwd: testDir,
}
)
expect(exitCode).toBe(0)
if (exitCode !== 0) {
throw new Error(stdout + stderr)
}
if (options.snapshot !== false) {
const output = await fs.readFile(join(testDir, 'dist/input.js'), 'utf8')
expect(output).toMatchSnapshot()
@ -51,6 +53,24 @@ runTest(
},
{
snapshot: false,
flags: ['--dts']
flags: ['--dts'],
}
)
runTest(
'es5 target',
{
'input.ts': `
export class Foo {
hi (): void {
let a = () => 'foo'
console.log(a())
}
}
`,
},
{
flags: ['--target', 'es5'],
}
)

118
yarn.lock
View File

@ -551,6 +551,13 @@
dependencies:
"@babel/types" "^7.3.0"
"@types/buble@^0.19.2":
version "0.19.2"
resolved "https://registry.yarnpkg.com/@types/buble/-/buble-0.19.2.tgz#a4289d20b175b3c206aaad80caabdabe3ecdfdd1"
integrity sha512-uUD8zIfXMKThmFkahTXDGI3CthFH1kMg2dOm3KLi4GlC5cbARA64bEcUMbbWdWdE73eoc/iBB9PiTMqH0dNS2Q==
dependencies:
magic-string "^0.25.0"
"@types/color-name@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
@ -647,6 +654,11 @@ abab@^2.0.3:
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a"
integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==
acorn-dynamic-import@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948"
integrity sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==
acorn-globals@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45"
@ -655,11 +667,21 @@ acorn-globals@^6.0.0:
acorn "^7.1.1"
acorn-walk "^7.1.1"
acorn-jsx@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe"
integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==
acorn-walk@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.1.1.tgz#345f0dffad5c735e7373d2fec9a1023e6a44b83e"
integrity sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==
acorn@^6.4.1:
version "6.4.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474"
integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==
acorn@^7.1.1:
version "7.2.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe"
@ -931,6 +953,19 @@ bser@2.1.1:
dependencies:
node-int64 "^0.4.0"
buble@^0.20.0:
version "0.20.0"
resolved "https://registry.yarnpkg.com/buble/-/buble-0.20.0.tgz#a143979a8d968b7f76b57f38f2e7ce7cfe938d1f"
integrity sha512-/1gnaMQE8xvd5qsNBl+iTuyjJ9XxeaVxAMF86dQ4EyxFJOZtsgOS8Ra+7WHgZTam5IFDtt4BguN0sH0tVTKrOw==
dependencies:
acorn "^6.4.1"
acorn-dynamic-import "^4.0.0"
acorn-jsx "^5.2.0"
chalk "^2.4.2"
magic-string "^0.25.7"
minimist "^1.2.5"
regexpu-core "4.5.4"
buffer-from@1.x, buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
@ -983,7 +1018,7 @@ caseless@~0.12.0:
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
chalk@^2.0.0:
chalk@^2.0.0, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@ -2430,6 +2465,11 @@ jsesc@^2.5.1:
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
jsesc@~0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
json-parse-better-errors@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
@ -2552,6 +2592,13 @@ magic-string@^0.22.4:
dependencies:
vlq "^0.2.2"
magic-string@^0.25.0, magic-string@^0.25.7:
version "0.25.7"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==
dependencies:
sourcemap-codec "^1.4.4"
make-dir@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
@ -3020,6 +3067,18 @@ readdirp@~3.4.0:
dependencies:
picomatch "^2.2.1"
regenerate-unicode-properties@^8.0.2:
version "8.2.0"
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==
dependencies:
regenerate "^1.4.0"
regenerate@^1.4.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f"
integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==
regex-not@^1.0.0, regex-not@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
@ -3028,6 +3087,30 @@ regex-not@^1.0.0, regex-not@^1.0.2:
extend-shallow "^3.0.2"
safe-regex "^1.1.0"
regexpu-core@4.5.4:
version "4.5.4"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.4.tgz#080d9d02289aa87fe1667a4f5136bc98a6aebaae"
integrity sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==
dependencies:
regenerate "^1.4.0"
regenerate-unicode-properties "^8.0.2"
regjsgen "^0.5.0"
regjsparser "^0.6.0"
unicode-match-property-ecmascript "^1.0.4"
unicode-match-property-value-ecmascript "^1.1.0"
regjsgen@^0.5.0:
version "0.5.2"
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733"
integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==
regjsparser@^0.6.0:
version "0.6.4"
resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272"
integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==
dependencies:
jsesc "~0.5.0"
remove-trailing-separator@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
@ -3344,6 +3427,11 @@ source-map@^0.7.3:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
sourcemap-codec@^1.4.4:
version "1.4.8"
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
spdx-correct@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
@ -3456,6 +3544,11 @@ strip-final-newline@^2.0.0:
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
strip-json-comments@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
sucrase@^3.15.0:
version "3.15.0"
resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.15.0.tgz#78596a78be7264a65b52ed8d873883413ef0220c"
@ -3683,6 +3776,29 @@ typescript@^3.9.7:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
unicode-canonical-property-names-ecmascript@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==
unicode-match-property-ecmascript@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c"
integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==
dependencies:
unicode-canonical-property-names-ecmascript "^1.0.4"
unicode-property-aliases-ecmascript "^1.0.4"
unicode-match-property-value-ecmascript@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531"
integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==
unicode-property-aliases-ecmascript@^1.0.4:
version "1.1.0"
resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4"
integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==
union-value@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"