diff --git a/docs/README.md b/docs/README.md index 3631b7bf..fe354c97 100644 --- a/docs/README.md +++ b/docs/README.md @@ -72,7 +72,7 @@ All other CLI flags still apply to this command. You can also use `tsup` using file configurations or in a property inside your `package.json`, and you can even use `TypeScript` and have type-safety while you are using it. -> Most of these options can be overwritten using the CLI options +> INFO: Most of these options can be overwritten using the CLI options You can use any of these files: @@ -82,7 +82,7 @@ You can use any of these files: - `tsup.config.json` - `tsup` property in your `package.json` -> In all the custom files you can export the options either as `tsup`, `default` or `module.exports =` +> INFO: In all the custom files you can export the options either as `tsup`, `default` or `module.exports =` [Check out all available options](https://github.com/egoist/tsup/blob/master/src/options.ts). @@ -218,7 +218,7 @@ To disable code splitting altogether, try the `--no-splitting` flag instead. ### ES5 support -You can use `--target es5` to compile the code down to es5, it's processed by [buble](http://buble.surge.sh/). Some features are NOT supported by this target, namely: `for .. of`. +You can use `--target es5` to compile the code down to es5, in this target your code will be transpiled by esbuild to es2020 first, and then transpiled to es5 by [SWC](https://swc.rc). ### Compile-time environment variables @@ -240,24 +240,24 @@ tsup src/index.ts --watch Turn on watch mode. This means that after the initial build, tsup will continue to watch for changes in any of the resolved files. -> By default it always ignores `dist`, `node_modules` & `.git` +> INFO: By default it always ignores `dist`, `node_modules` & `.git` ```bash tsup src/index.ts --watch --ignore-watch ignore-this-folder-too ``` -> You can specify more than a folder repeating "--ignore-watch", for example: `tsup src src/index.ts --watch --ignore-watch folder1 --ignore-watch folder2` +> INFO: You can specify more than a folder repeating "--ignore-watch", for example: `tsup src src/index.ts --watch --ignore-watch folder1 --ignore-watch folder2` ### onSuccess You can specify command to be executed after a successful build, specially useful for **Watch mode** -> You should not use shell scripts, if you need to specify shell scripts you can add it in your "scripts" field and set for example `tsup src/index.ts --watch --onSuccess \"npm run dev\"` - ```bash tsup src/index.ts --watch --onSuccess "node dist/index.js" ``` +> Warning: You should not use shell scripts, if you need to specify shell scripts you can add it in your "scripts" field and set for example `tsup src/index.ts --watch --onSuccess \"npm run dev\"` + ### Minify output You can also minify the output, resulting into lower bundle sizes by using the `--minify` flag. @@ -364,6 +364,12 @@ For more details: tsup --help ``` +## Troubleshooting + +### error: No matching export in "xxx.ts" for import "xxx" + +This usualy happens when you have `emitDecoratorMetadata` enabled in your tsconfig.json, in this mode we use [SWC](https://swc.rc) to transpile decorators to JavaScript so exported types will be eliminated, that's why esbuild won't be able to find corresponding exports. You can fix this by changing your import statement from `import { SomeType }` to `import { type SomeType }` or `import type { SomeType }`. + ## License MIT © [EGOIST](https://github.com/sponsors/egoist) diff --git a/docs/index.html b/docs/index.html index 32d7ca93..209fb24c 100644 --- a/docs/index.html +++ b/docs/index.html @@ -12,7 +12,7 @@ diff --git a/package.json b/package.json index 9a24e4ef..9e319aeb 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "ts" ], "require": [ - "sucrase//register" + "sucrase/register" ] }, "dependencies": { @@ -44,22 +44,19 @@ "postcss-load-config": "^3.0.1", "resolve-from": "^5.0.0", "rollup": "^2.60.0", - "sucrase": "^3.20.1", - "tree-kill": "^1.2.2" + "tree-kill": "^1.2.2", + "source-map": "^0.7.3", + "sucrase": "^3.20.3" }, "devDependencies": { - "@babel/core": "^7.13.15", "@rollup/plugin-json": "^4.1.0", "@swc/core": "^1.2.112", - "@types/babel__core": "^7.1.16", - "@types/buble": "^0.19.2", "@types/debug": "^4.1.5", "@types/flat": "^5.0.2", "@types/fs-extra": "^9.0.11", "@types/node": "^14.14.41", "@types/resolve": "^1.20.0", "ava": "^4.0.0-rc.1", - "buble": "^0.20.0", "colorette": "^2.0.16", "consola": "^2.15.3", "flat": "^5.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 52cb173c..6a195594 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,18 +1,14 @@ lockfileVersion: 5.3 specifiers: - '@babel/core': ^7.13.15 '@rollup/plugin-json': ^4.1.0 '@swc/core': ^1.2.112 - '@types/babel__core': ^7.1.16 - '@types/buble': ^0.19.2 '@types/debug': ^4.1.5 '@types/flat': ^5.0.2 '@types/fs-extra': ^9.0.11 '@types/node': ^14.14.41 '@types/resolve': ^1.20.0 ava: ^4.0.0-rc.1 - buble: ^0.20.0 bundle-require: ^2.1.7 cac: ^6.7.12 chokidar: ^3.5.1 @@ -34,8 +30,9 @@ specifiers: rollup: ^2.60.0 rollup-plugin-dts: ^3.0.2 rollup-plugin-hashbang: ^2.2.2 + source-map: ^0.7.3 string-argv: ^0.3.1 - sucrase: ^3.20.1 + sucrase: ^3.20.3 svelte: 3.37.0 tree-kill: ^1.2.2 ts-essentials: ^7.0.1 @@ -56,22 +53,19 @@ dependencies: postcss-load-config: 3.1.0 resolve-from: 5.0.0 rollup: 2.60.1 + source-map: 0.7.3 sucrase: 3.20.3 tree-kill: 1.2.2 devDependencies: - '@babel/core': 7.16.0 '@rollup/plugin-json': 4.1.0_rollup@2.60.1 '@swc/core': 1.2.112 - '@types/babel__core': 7.1.16 - '@types/buble': 0.19.2 '@types/debug': 4.1.7 '@types/flat': 5.0.2 '@types/fs-extra': 9.0.13 '@types/node': 14.17.34 '@types/resolve': 1.20.1 ava: 4.0.0-rc.1 - buble: 0.20.0 colorette: 2.0.16 consola: 2.15.3 flat: 5.0.2 @@ -98,163 +92,13 @@ packages: dependencies: '@babel/highlight': 7.16.0 dev: true - - /@babel/compat-data/7.16.4: - resolution: {integrity: sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/core/7.16.0: - resolution: {integrity: sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.16.0 - '@babel/generator': 7.16.0 - '@babel/helper-compilation-targets': 7.16.3_@babel+core@7.16.0 - '@babel/helper-module-transforms': 7.16.0 - '@babel/helpers': 7.16.3 - '@babel/parser': 7.16.4 - '@babel/template': 7.16.0 - '@babel/traverse': 7.16.3 - '@babel/types': 7.16.0 - convert-source-map: 1.8.0 - debug: 4.3.2 - gensync: 1.0.0-beta.2 - json5: 2.2.0 - semver: 6.3.0 - source-map: 0.5.7 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/generator/7.16.0: - resolution: {integrity: sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.16.0 - jsesc: 2.5.2 - source-map: 0.5.7 - dev: true - - /@babel/helper-compilation-targets/7.16.3_@babel+core@7.16.0: - resolution: {integrity: sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/compat-data': 7.16.4 - '@babel/core': 7.16.0 - '@babel/helper-validator-option': 7.14.5 - browserslist: 4.18.1 - semver: 6.3.0 - dev: true - - /@babel/helper-function-name/7.16.0: - resolution: {integrity: sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-get-function-arity': 7.16.0 - '@babel/template': 7.16.0 - '@babel/types': 7.16.0 - dev: true - - /@babel/helper-get-function-arity/7.16.0: - resolution: {integrity: sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.16.0 - dev: true - - /@babel/helper-hoist-variables/7.16.0: - resolution: {integrity: sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.16.0 - dev: true - - /@babel/helper-member-expression-to-functions/7.16.0: - resolution: {integrity: sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.16.0 - dev: true - - /@babel/helper-module-imports/7.16.0: - resolution: {integrity: sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.16.0 - dev: true - - /@babel/helper-module-transforms/7.16.0: - resolution: {integrity: sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-module-imports': 7.16.0 - '@babel/helper-replace-supers': 7.16.0 - '@babel/helper-simple-access': 7.16.0 - '@babel/helper-split-export-declaration': 7.16.0 - '@babel/helper-validator-identifier': 7.15.7 - '@babel/template': 7.16.0 - '@babel/traverse': 7.16.3 - '@babel/types': 7.16.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-optimise-call-expression/7.16.0: - resolution: {integrity: sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.16.0 - dev: true - - /@babel/helper-replace-supers/7.16.0: - resolution: {integrity: sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-member-expression-to-functions': 7.16.0 - '@babel/helper-optimise-call-expression': 7.16.0 - '@babel/traverse': 7.16.3 - '@babel/types': 7.16.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-simple-access/7.16.0: - resolution: {integrity: sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.16.0 - dev: true - - /@babel/helper-split-export-declaration/7.16.0: - resolution: {integrity: sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.16.0 - dev: true + optional: true /@babel/helper-validator-identifier/7.15.7: resolution: {integrity: sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==} engines: {node: '>=6.9.0'} dev: true - - /@babel/helper-validator-option/7.14.5: - resolution: {integrity: sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helpers/7.16.3: - resolution: {integrity: sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.16.0 - '@babel/traverse': 7.16.3 - '@babel/types': 7.16.0 - transitivePeerDependencies: - - supports-color - dev: true + optional: true /@babel/highlight/7.16.0: resolution: {integrity: sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==} @@ -264,46 +108,7 @@ packages: chalk: 2.4.2 js-tokens: 4.0.0 dev: true - - /@babel/parser/7.16.4: - resolution: {integrity: sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng==} - engines: {node: '>=6.0.0'} - hasBin: true - dev: true - - /@babel/template/7.16.0: - resolution: {integrity: sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.16.0 - '@babel/parser': 7.16.4 - '@babel/types': 7.16.0 - dev: true - - /@babel/traverse/7.16.3: - resolution: {integrity: sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.16.0 - '@babel/generator': 7.16.0 - '@babel/helper-function-name': 7.16.0 - '@babel/helper-hoist-variables': 7.16.0 - '@babel/helper-split-export-declaration': 7.16.0 - '@babel/parser': 7.16.4 - '@babel/types': 7.16.0 - debug: 4.3.2 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/types/7.16.0: - resolution: {integrity: sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.15.7 - to-fast-properties: 2.0.0 - dev: true + optional: true /@napi-rs/triples/1.0.3: resolution: {integrity: sha512-jDJTpta+P4p1NZTFVLHJ/TLFVYVcOqv6l8xwOeBKNPMgY/zDYH/YH7SJbvrr/h1RcS9GzbPcLKGzpuK9cV56UA==} @@ -482,41 +287,6 @@ packages: '@swc/core-win32-x64-msvc': 1.2.112 dev: true - /@types/babel__core/7.1.16: - resolution: {integrity: sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==} - dependencies: - '@babel/parser': 7.16.4 - '@babel/types': 7.16.0 - '@types/babel__generator': 7.6.3 - '@types/babel__template': 7.4.1 - '@types/babel__traverse': 7.14.2 - dev: true - - /@types/babel__generator/7.6.3: - resolution: {integrity: sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==} - dependencies: - '@babel/types': 7.16.0 - dev: true - - /@types/babel__template/7.4.1: - resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} - dependencies: - '@babel/parser': 7.16.4 - '@babel/types': 7.16.0 - dev: true - - /@types/babel__traverse/7.14.2: - resolution: {integrity: sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==} - dependencies: - '@babel/types': 7.16.0 - dev: true - - /@types/buble/0.19.2: - resolution: {integrity: sha512-uUD8zIfXMKThmFkahTXDGI3CthFH1kMg2dOm3KLi4GlC5cbARA64bEcUMbbWdWdE73eoc/iBB9PiTMqH0dNS2Q==} - dependencies: - magic-string: 0.25.7 - dev: true - /@types/debug/4.1.7: resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} dependencies: @@ -553,33 +323,11 @@ packages: resolution: {integrity: sha512-Ku5+GPFa12S3W26Uwtw+xyrtIpaZsGYHH6zxNbZlstmlvMYSZRzOwzwsXbxlVUbHyUucctSyuFtu6bNxwYomIw==} dev: true - /acorn-dynamic-import/4.0.0_acorn@6.4.2: - resolution: {integrity: sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==} - peerDependencies: - acorn: ^6.0.0 - dependencies: - acorn: 6.4.2 - dev: true - - /acorn-jsx/5.3.2_acorn@6.4.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - acorn: 6.4.2 - dev: true - /acorn-walk/8.2.0: resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} engines: {node: '>=0.4.0'} dev: true - /acorn/6.4.2: - resolution: {integrity: sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - /acorn/8.6.0: resolution: {integrity: sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==} engines: {node: '>=0.4.0'} @@ -618,6 +366,7 @@ packages: dependencies: color-convert: 1.9.3 dev: true + optional: true /ansi-styles/4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} @@ -764,31 +513,6 @@ packages: dependencies: fill-range: 7.0.1 - /browserslist/4.18.1: - resolution: {integrity: sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - dependencies: - caniuse-lite: 1.0.30001283 - electron-to-chromium: 1.4.1 - escalade: 3.1.1 - node-releases: 2.0.1 - picocolors: 1.0.0 - dev: true - - /buble/0.20.0: - resolution: {integrity: sha512-/1gnaMQE8xvd5qsNBl+iTuyjJ9XxeaVxAMF86dQ4EyxFJOZtsgOS8Ra+7WHgZTam5IFDtt4BguN0sH0tVTKrOw==} - hasBin: true - dependencies: - acorn: 6.4.2 - acorn-dynamic-import: 4.0.0_acorn@6.4.2 - acorn-jsx: 5.3.2_acorn@6.4.2 - chalk: 2.4.2 - magic-string: 0.25.7 - minimist: 1.2.5 - regexpu-core: 4.5.4 - dev: true - /bundle-require/2.1.8_esbuild@0.13.15: resolution: {integrity: sha512-oOEg3A0hy/YzvNWNowtKD0pmhZKseOFweCbgyMqTIih4gRY1nJWsvrOCT27L9NbIyL5jMjTFrAUpGxxpW68Puw==} peerDependencies: @@ -805,10 +529,6 @@ packages: engines: {node: '>=12.20'} dev: true - /caniuse-lite/1.0.30001283: - resolution: {integrity: sha512-9RoKo841j1GQFSJz/nCXOj0sD7tHBtlowjYlrqIUS812x9/emfBLBt6IyMz1zIaYc/eRL8Cs6HPUVi2Hzq4sIg==} - dev: true - /cbor/8.1.0: resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} engines: {node: '>=12.19'} @@ -824,6 +544,7 @@ packages: escape-string-regexp: 1.0.5 supports-color: 5.5.0 dev: true + optional: true /chalk/4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -904,6 +625,7 @@ packages: dependencies: color-name: 1.1.3 dev: true + optional: true /color-convert/2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} @@ -915,6 +637,7 @@ packages: /color-name/1.1.3: resolution: {integrity: sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=} dev: true + optional: true /color-name/1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -953,12 +676,6 @@ packages: resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==} dev: true - /convert-source-map/1.8.0: - resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} - dependencies: - safe-buffer: 5.1.2 - dev: true - /convert-to-spaces/1.0.2: resolution: {integrity: sha1-fj5Iu+bZl7FBfdyihoIEtNPYVxU=} engines: {node: '>= 4'} @@ -1017,10 +734,6 @@ packages: dependencies: path-type: 4.0.0 - /electron-to-chromium/1.4.1: - resolution: {integrity: sha512-9ldvb6QMHiDpUNF1iSwBTiTT0qXEN+xIO5WlCJrC5gt0z74ofOiqR698vaJqYWnri0XZiF0YmnrFmGq/EmpGAA==} - dev: true - /emittery/0.10.0: resolution: {integrity: sha512-AGvFfs+d0JKCJQ4o01ASQLGPmSCxgfU9RFXvzPvZdjKK8oscynksuJhWrSTSw7j7Ep/sZct5b5ZhYCi8S/t0HQ==} engines: {node: '>=12'} @@ -1190,6 +903,7 @@ packages: resolution: {integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=} engines: {node: '>=0.8.0'} dev: true + optional: true /escape-string-regexp/2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} @@ -1300,11 +1014,6 @@ packages: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} dev: true - /gensync/1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - dev: true - /get-caller-file/2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -1341,11 +1050,6 @@ packages: path-is-absolute: 1.0.1 dev: true - /globals/11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - dev: true - /globby/11.0.4: resolution: {integrity: sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==} engines: {node: '>=10'} @@ -1377,6 +1081,7 @@ packages: resolution: {integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0=} engines: {node: '>=4'} dev: true + optional: true /has-flag/4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} @@ -1531,6 +1236,7 @@ packages: /js-tokens/4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} dev: true + optional: true /js-yaml/3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} @@ -1540,17 +1246,6 @@ packages: esprima: 4.0.1 dev: true - /jsesc/0.5.0: - resolution: {integrity: sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=} - hasBin: true - dev: true - - /jsesc/2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} - hasBin: true - dev: true - /json5/1.0.1: resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==} hasBin: true @@ -1558,14 +1253,6 @@ packages: minimist: 1.2.5 dev: true - /json5/2.2.0: - resolution: {integrity: sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==} - engines: {node: '>=6'} - hasBin: true - dependencies: - minimist: 1.2.5 - dev: true - /jsonfile/6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: @@ -1701,10 +1388,6 @@ packages: resolution: {integrity: sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=} engines: {node: '>=0.10.0'} - /node-releases/2.0.1: - resolution: {integrity: sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==} - dev: true - /nofilter/3.1.0: resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} engines: {node: '>=12.19'} @@ -1895,40 +1578,6 @@ packages: dependencies: picomatch: 2.3.0 - /regenerate-unicode-properties/8.2.0: - resolution: {integrity: sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==} - engines: {node: '>=4'} - dependencies: - regenerate: 1.4.2 - dev: true - - /regenerate/1.4.2: - resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} - dev: true - - /regexpu-core/4.5.4: - resolution: {integrity: sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==} - engines: {node: '>=4'} - dependencies: - regenerate: 1.4.2 - regenerate-unicode-properties: 8.2.0 - regjsgen: 0.5.2 - regjsparser: 0.6.9 - unicode-match-property-ecmascript: 1.0.4 - unicode-match-property-value-ecmascript: 1.2.0 - dev: true - - /regjsgen/0.5.2: - resolution: {integrity: sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==} - dev: true - - /regjsparser/0.6.9: - resolution: {integrity: sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==} - hasBin: true - dependencies: - jsesc: 0.5.0 - dev: true - /require-directory/2.1.1: resolution: {integrity: sha1-jGStX9MNqxyXbiNE/+f3kqam30I=} engines: {node: '>=0.10.0'} @@ -1996,15 +1645,6 @@ packages: dependencies: queue-microtask: 1.2.3 - /safe-buffer/5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - dev: true - - /semver/6.3.0: - resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} - hasBin: true - dev: true - /semver/7.3.5: resolution: {integrity: sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==} engines: {node: '>=10'} @@ -2055,10 +1695,10 @@ packages: engines: {node: '>=0.10.0'} dev: true - /source-map/0.5.7: - resolution: {integrity: sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=} - engines: {node: '>=0.10.0'} - dev: true + /source-map/0.7.3: + resolution: {integrity: sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==} + engines: {node: '>= 8'} + dev: false /sourcemap-codec/1.4.8: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} @@ -2150,6 +1790,7 @@ packages: dependencies: has-flag: 3.0.0 dev: true + optional: true /supports-color/7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} @@ -2184,11 +1825,6 @@ packages: engines: {node: '>=4'} dev: true - /to-fast-properties/2.0.0: - resolution: {integrity: sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=} - engines: {node: '>=4'} - dev: true - /to-regex-range/5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -2264,29 +1900,6 @@ packages: hasBin: true dev: true - /unicode-canonical-property-names-ecmascript/1.0.4: - resolution: {integrity: sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==} - engines: {node: '>=4'} - dev: true - - /unicode-match-property-ecmascript/1.0.4: - resolution: {integrity: sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==} - engines: {node: '>=4'} - dependencies: - unicode-canonical-property-names-ecmascript: 1.0.4 - unicode-property-aliases-ecmascript: 1.1.0 - dev: true - - /unicode-match-property-value-ecmascript/1.2.0: - resolution: {integrity: sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==} - engines: {node: '>=4'} - dev: true - - /unicode-property-aliases-ecmascript/1.1.0: - resolution: {integrity: sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==} - engines: {node: '>=4'} - dev: true - /universalify/2.0.0: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} diff --git a/src/cli-main.ts b/src/cli-main.ts index dfd72878..f59e6d61 100644 --- a/src/cli-main.ts +++ b/src/cli-main.ts @@ -31,7 +31,6 @@ export async function main(options: Options = {}) { .option('--target ', 'Bundle target, "es20XX" or "esnext"', { default: 'es2017', }) - .option('--babel', 'Transform the result with Babel') .option( '--legacy-output', 'Output different formats to different folder instead of using different extensions' diff --git a/src/esbuild/index.ts b/src/esbuild/index.ts index 7ec68586..73c822cc 100644 --- a/src/esbuild/index.ts +++ b/src/esbuild/index.ts @@ -1,6 +1,5 @@ import fs from 'fs' import path from 'path' -import { transform as transformToEs5 } from 'buble' import { build as esbuild, BuildResult, @@ -15,11 +14,10 @@ import { externalPlugin } from './external' import { postcssPlugin } from './postcss' import { sveltePlugin } from './svelte' import consola from 'consola' -import { getBabel, truthy } from '../utils' -import { PrettyError } from '../errors' -import { transform } from 'sucrase' +import { truthy } from '../utils' import { swcPlugin } from './swc' import { nativeNodeModulesPlugin } from './native-node-module' +import { PluginContainer } from '../plugin' const getOutputExtensionMap = ( pkgTypeField: string | undefined, @@ -46,11 +44,13 @@ export async function runEsbuild( css, logger, buildDependencies, + pluginContainer, }: { format: Format css?: Map buildDependencies: Set logger: Logger + pluginContainer: PluginContainer } ) { const pkg = await loadPkg(process.cwd()) @@ -94,6 +94,7 @@ export async function runEsbuild( { name: 'modify-options', setup(build) { + pluginContainer.modifyEsbuildOptions(build.initialOptions, { format }) if (options.esbuildOptions) { options.esbuildOptions(build.initialOptions, { format }) } @@ -123,8 +124,8 @@ export async function runEsbuild( globalName: options.globalName, jsxFactory: options.jsxFactory, jsxFragment: options.jsxFragment, - sourcemap: options.sourcemap, - target: options.target === 'es5' ? 'es2016' : options.target, + sourcemap: options.sourcemap ? 'external' : false, + target: options.target, footer: options.footer, banner: options.banner, tsconfig: options.tsconfig, @@ -228,74 +229,14 @@ export async function runEsbuild( const timeInMs = Date.now() - startTime logger.success(format, `⚡️ Build success in ${Math.floor(timeInMs)}ms`) - await Promise.all( - result.outputFiles.map(async (file) => { - const dir = path.dirname(file.path) - const outPath = file.path - const ext = path.extname(outPath) - const comeFromSource = ext === '.js' || ext === outExtension['.js'] - await fs.promises.mkdir(dir, { recursive: true }) - let contents = file.text - let mode: number | undefined - if (contents[0] === '#' && contents[1] === '!') { - mode = 0o755 - } - if (comeFromSource) { - if (options.babel) { - const babel = getBabel() - if (babel) { - contents = await babel - .transformAsync(contents, { - filename: file.path, - }) - .then((res) => res?.code || contents) - } else { - throw new PrettyError( - `@babel/core is not found in ${process.cwd()}` - ) - } - } - 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) { - if (error instanceof Error) { - throw new PrettyError( - `Error compiling to es5 target:\n${ - // @ts-expect-error not sure how to type error.snippet - error.snippet || error.message - }` - ) - } else { - throw error - } - } - } - // Workaround to enable code splitting for cjs format - // Manually transform esm to cjs - // TODO: remove this once esbuild supports code splitting for cjs natively - if (splitting && format === 'cjs') { - contents = transform(contents, { - filePath: file.path, - transforms: ['imports'], - }).code - } - } - await fs.promises.writeFile(outPath, contents, { - encoding: 'utf8', - mode, - }) - }) - ) + await pluginContainer.buildFinished({ + files: result.outputFiles, + context: { + format, + splitting, + options, + }, + }) } if (result.metafile) { diff --git a/src/fs.ts b/src/fs.ts new file mode 100644 index 00000000..f498cade --- /dev/null +++ b/src/fs.ts @@ -0,0 +1,11 @@ +import path from 'path' +import fs from 'fs' + +export const outputFile = async ( + filepath: string, + data: any, + options?: { mode?: fs.Mode } +) => { + await fs.promises.mkdir(path.dirname(filepath), { recursive: true }) + await fs.promises.writeFile(filepath, data, options) +} diff --git a/src/index.ts b/src/index.ts index 9681bee3..2e7e7c65 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,6 +16,10 @@ import { version } from '../package.json' import { createLogger, setSilent } from './log' import { DtsConfig, Format, Options } from './options' import { runEsbuild } from './esbuild' +import { shebang } from './plugins/shebang' +import { cjsSplitting } from './plugins/cjs-splitting' +import { PluginContainer } from './plugin' +import { es5 } from './plugins/es5' export type { Format, Options } @@ -178,14 +182,22 @@ export async function build(_options: Options) { const css: Map = new Map() await Promise.all([ - ...options.format.map((format, index) => - runEsbuild(options, { + ...options.format.map(async (format, index) => { + const pluginContainer = new PluginContainer([ + shebang(), + cjsSplitting(), + es5(), + ...(options.plugins || []), + ]) + await pluginContainer.buildStarted() + await runEsbuild(options, { + pluginContainer, format, css: index === 0 ? css : undefined, logger, buildDependencies, }) - ), + }), ]) await killPromise if (options.onSuccess) { diff --git a/src/options.ts b/src/options.ts index f86be0ae..5ccbe66e 100644 --- a/src/options.ts +++ b/src/options.ts @@ -1,5 +1,6 @@ import type { BuildOptions, Plugin as EsbuildPlugin, Loader } from 'esbuild' import type { InputOption } from 'rollup' +import { Plugin } from './plugin' export type Format = 'cjs' | 'esm' | 'iife' @@ -53,13 +54,11 @@ export type Options = { [k: string]: string } dts?: boolean | string | DtsConfig - sourcemap?: BuildOptions['sourcemap'] + sourcemap?: boolean /** Always bundle modules matching given patterns */ noExternal?: (string | RegExp)[] /** Don't bundle these modules */ external?: (string | RegExp)[] - /** Transform the result with `@babel/core` */ - babel?: boolean /** * Replace `process.env.NODE_ENV` with `production` or `development` * `production` when the bundled is minified, `development` otherwise @@ -122,14 +121,20 @@ export type Options = { * Use a custom tsconfig */ tsconfig?: string - /** - * CJS and ESM shims - * @default `true` - */ - shims?: boolean /** * Inject CSS as style tags to document head * @default {false} */ injectStyle?: boolean + /** + * Inject cjs and esm shims if needed + * @default {true} + */ + shims?: boolean + /** + * TSUP plugins + * @experimental + * @alpha + */ + plugins?: Plugin[] } diff --git a/src/plugin.ts b/src/plugin.ts new file mode 100644 index 00000000..75718184 --- /dev/null +++ b/src/plugin.ts @@ -0,0 +1,173 @@ +import path from 'path' +import { OutputFile, BuildOptions as EsbuildOptions } from 'esbuild' +import { SourceMapConsumer, SourceMapGenerator, RawSourceMap } from 'source-map' +import { Format, NormalizedOptions } from '.' +import { outputFile } from './fs' + +export type ChunkInfo = { + type: 'chunk' + code: string + map?: string | RawSourceMap | null + path: string + /** + * Sets the file mode + */ + mode?: number +} + +export type AssetInfo = { + type: 'asset' + path: string + contents: Uint8Array +} + +type MaybePromise = T | Promise + +export type RenderChunk = ( + this: PluginContext, + code: string, + chunkInfo: ChunkInfo +) => MaybePromise< + | { + code: string + map?: object | string + } + | undefined + | null + | void +> + +export type BuildStart = () => MaybePromise +export type BuildEnd = () => MaybePromise + +export type ModifyEsbuildOptions = ( + options: EsbuildOptions, + context: { format: Format } +) => void + +export type Plugin = { + name: string + + esbuildOptions?: ModifyEsbuildOptions + + buildStart?: BuildStart + + renderChunk?: RenderChunk + + buildEnd?: BuildEnd +} + +export type PluginContext = { + format: Format + splitting?: boolean + options: NormalizedOptions +} + +const parseSourceMap = (map?: string | object | null) => { + return typeof map === 'string' ? JSON.parse(map) : map +} + +const isJS = (path: string) => /\.(js|mjs|cjs)$/.test(path) +const isCSS = (path: string) => /\.css$/.test(path) + +export class PluginContainer { + plugins: Plugin[] + + constructor(plugins: Plugin[]) { + this.plugins = plugins + } + + modifyEsbuildOptions(options: EsbuildOptions, context: { format: Format }) { + for (const plugin of this.plugins) { + if (plugin.esbuildOptions) { + plugin.esbuildOptions(options, context) + } + } + } + + async buildStarted() { + for (const plugin of this.plugins) { + if (plugin.buildStart) { + await plugin.buildStart() + } + } + } + + async buildFinished({ + files, + context, + }: { + files: OutputFile[] + context: PluginContext + }) { + await Promise.all( + files.map(async (file) => { + const info: AssetInfo | ChunkInfo = + isJS(file.path) || isCSS(file.path) + ? { + type: 'chunk', + path: file.path, + code: file.text, + map: files.find((f) => f.path === `${file.path}.map`)?.text, + } + : { + type: 'asset', + path: file.path, + contents: file.contents, + } + for (const plugin of this.plugins) { + if (info.type === 'chunk' && plugin.renderChunk) { + const result = await plugin.renderChunk.call( + context, + info.code, + info + ) + if (result) { + info.code = result.code + if (result.map) { + const originalConsumer = await new SourceMapConsumer( + parseSourceMap(info.map) + ) + const newConsumer = await new SourceMapConsumer( + parseSourceMap(result.map) + ) + const generator = + SourceMapGenerator.fromSourceMap(originalConsumer) + generator.applySourceMap(newConsumer) + info.map = generator.toJSON() + originalConsumer.destroy() + newConsumer.destroy() + } + } + } + } + + await outputFile( + info.path, + info.type === 'chunk' + ? info.code + getSourcemapComment(!!info.map, info.path) + : info.contents, + { mode: info.type === 'chunk' ? info.mode : undefined } + ) + if (info.type === 'chunk' && info.map) { + const map = + typeof info.map === 'string' ? JSON.parse(info.map) : info.map + // map.sources = map.sources?.map((name: string) => + // path.relative(path.dirname(info.path), name) + // ) + await outputFile(`${info.path}.map`, JSON.stringify(map)) + } + }) + ) + + for (const plugin of this.plugins) { + if (plugin.buildEnd) { + await plugin.buildEnd() + } + } + } +} + +const getSourcemapComment = (hasMap: boolean, filepath: string) => { + return hasMap ? `//# sourceMappingURL=${path.basename(filepath)}.map` : '' +} diff --git a/src/plugins/cjs-splitting.ts b/src/plugins/cjs-splitting.ts new file mode 100644 index 00000000..26558d8f --- /dev/null +++ b/src/plugins/cjs-splitting.ts @@ -0,0 +1,39 @@ +// Workaround to enable code splitting for cjs format +// Manually transform esm to cjs +// TODO: remove this once esbuild supports code splitting for cjs natively +import path from 'path' +import { Plugin } from '../plugin' + +export const cjsSplitting = (): Plugin => { + return { + name: 'cjs-splitting', + + async renderChunk(code, info) { + if ( + !this.splitting || + this.format !== 'cjs' || + info.type !== 'chunk' || + !/\.(js|cjs)$/.test(info.path) + ) { + return + } + + const { transform } = await import('sucrase') + + const result = transform(code, { + filePath: info.path, + transforms: ['imports'], + sourceMapOptions: this.options.sourcemap + ? { + compiledFilename: info.path, + } + : undefined, + }) + + return { + code: result.code, + map: result.sourceMap, + } + }, + } +} diff --git a/src/plugins/es5.ts b/src/plugins/es5.ts new file mode 100644 index 00000000..4d1c263c --- /dev/null +++ b/src/plugins/es5.ts @@ -0,0 +1,37 @@ +import { Plugin } from '../plugin' +import { localRequire } from '../utils' + +export const es5 = (): Plugin => { + let enabled = false + return { + name: 'es5-target', + + esbuildOptions(options) { + if (options.target === 'es5') { + options.target = 'es2020' + enabled = true + } + }, + + async renderChunk(code, info) { + if (!enabled || !/\.(cjs|js)$/.test(info.path)) { + return + } + const swc: typeof import('@swc/core') = localRequire('@swc/core') + const result = await swc.transform(code, { + filename: info.path, + sourceMaps: this.options.sourcemap, + jsc: { + target: 'es5', + parser: { + syntax: 'ecmascript', + }, + }, + }) + return { + code: result.code, + map: result.map, + } + }, + } +} diff --git a/src/plugins/shebang.ts b/src/plugins/shebang.ts new file mode 100644 index 00000000..8869fdb8 --- /dev/null +++ b/src/plugins/shebang.ts @@ -0,0 +1,15 @@ +import { Plugin } from '../plugin' + +export const shebang = (): Plugin => { + return { + name: 'shebang', + + renderChunk(_, info) { + if (info.type === 'chunk' && /\.(cjs|js|mjs)$/.test(info.path)) { + if (info.code.startsWith('#!')) { + info.mode = 0o755 + } + } + }, + } +} diff --git a/src/utils.ts b/src/utils.ts index 506980ae..cc77ac94 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -40,11 +40,6 @@ export function isExternal( return false } -export function getBabel(): null | typeof import('@babel/core') { - const p = resolveFrom.silent(process.cwd(), '@babel/core') - return p && require(p) -} - export function getPostcss(): null | typeof import('postcss') { const p = resolveFrom.silent(process.cwd(), 'postcss') return p && require(p) diff --git a/test/index.test.ts b/test/index.test.ts index 98deeabd..fff059b8 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -1,5 +1,5 @@ import test from 'ava' -import { resolve } from 'path' +import { join, resolve } from 'path' import execa from 'execa' import fs from 'fs-extra' import glob from 'globby' @@ -65,6 +65,7 @@ async function run( }, outFiles, logs, + outDir: resolve(testDir, 'dist'), getFileContent(filename: string) { return fs.readFile(resolve(testDir, filename), 'utf8') }, @@ -187,28 +188,6 @@ test('bundle graphql-tools with --sourcemap inline flag', async (t) => { t.assert(output.includes('//# sourceMappingURL=')) }) -test('es5 target', async (t) => { - const { output, outFiles } = await run( - t.title, - { - 'input.ts': ` - export class Foo { - hi (): void { - let a = () => 'foo' - - console.log(a()) - } - } - `, - }, - { - flags: ['--target', 'es5'], - } - ) - t.snapshot(output) - t.deepEqual(outFiles, ['input.js']) -}) - test('multiple formats', async (t) => { const { output, outFiles } = await run( t.title, @@ -703,7 +682,7 @@ test('inject style', async (t) => { t.title, { 'input.ts': `import './style.css'`, - 'style.css': `.hello { color: red }` + 'style.css': `.hello { color: red }`, }, { flags: ['--inject-style', '--minify'], @@ -712,3 +691,49 @@ test('inject style', async (t) => { t.deepEqual(outFiles, ['input.js']) t.assert(output.includes('.hello{color:red}')) }) + +test('shebang', async (t) => { + const { outDir } = await run( + t.title, + { + 'a.ts': `#!/usr/bin/env node\bconsole.log('a')`, + 'b.ts': `console.log('b')`, + }, + { + entry: ['a.ts', 'b.ts'], + } + ) + + if (process.platform === 'win32') { + return t.pass() + } + + t.notThrows(() => { + fs.accessSync(join(outDir, 'a.js'), fs.constants.X_OK) + }) + t.throws(() => { + fs.accessSync(join(outDir, 'b.js'), fs.constants.X_OK) + }) +}) + +test('es5 target', async (t) => { + const { output, outFiles } = await run( + t.title, + { + 'input.ts': ` + export class Foo { + hi (): void { + let a = () => 'foo' + + console.log(a()) + } + } + `, + }, + { + flags: ['--target', 'es5'], + } + ) + t.regex(output, /createClass/) + t.deepEqual(outFiles, ['input.js']) +}) diff --git a/types.d.ts b/types.d.ts index 807ad76e..f1f085a8 100644 --- a/types.d.ts +++ b/types.d.ts @@ -1,3 +1,2 @@ declare module 'rollup-plugin-hashbang' declare module 'postcss-load-config' -declare module 'jju/lib/parse'