From 671ffc302c31719894c02244dd1b108891044b8d Mon Sep 17 00:00:00 2001 From: EGOIST <0x142857@gmail.com> Date: Sun, 26 Dec 2021 17:37:30 +0800 Subject: [PATCH] feat(experimental): add `optimizeDeps` option --- README.md | 20 ++- bench.sh | 1 + example/index.js | 6 +- example/rollup.config.js | 19 ++- package.json | 15 +- pnpm-lock.yaml | 291 ++++++++++++++++++++++++++++++++-- src/bundle.ts | 246 ---------------------------- src/index.ts | 106 ++++++------- src/minify.ts | 7 + src/optimizer/optmize-deps.ts | 92 +++++++++++ test/index.test.ts | 74 +-------- 11 files changed, 479 insertions(+), 398 deletions(-) create mode 100644 bench.sh delete mode 100644 src/bundle.ts create mode 100644 src/optimizer/optmize-deps.ts diff --git a/README.md b/README.md index c8317ec..320ede9 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ export default { // All options are optional include: /\.[jt]sx?$/, // default, inferred from `loaders` option exclude: /node_modules/, // default - sourceMap: false, // default + sourceMap: false, // by default inferred from rollup's `output.sourcemap` option minify: process.env.NODE_ENV === 'production', target: 'es2017', // default, or 'es20XX', 'esnext' jsx: 'transform', // default, or 'preserve' @@ -93,13 +93,23 @@ export default { } ``` -### Bundle mode +### Optimizing Deps -This plugin also includes an experimental `bundle` mode which lets rollup `resolve`, `load`, and `transform` imported files but leaves bundling to esbuild. In my simple test it's around 50% faster than non-bundle mode, but still 10x slower than raw esbuild. +You can use this plugin to pre-bundle dependencies using esbuild and inline them in the Rollup-generated bundle: -To enable this mode, passing `experimentalBundling: true` to the options. +```js +esbuild({ + optimizeDeps: { + include: ['vue', 'vue-router'], + }, +}) +``` + +This eliminates the need of `@rollup/plugin-node-modules` and `@rollup/plugin-commonjs`. + +Note that this is an **experimental features**, breaking changes might happen across minor version bump. -Current limitation: no code splitting yet. +TODO: Maybe we can scan Rollup input files to get a list of deps to optimize automatically. ## Sponsors diff --git a/bench.sh b/bench.sh new file mode 100644 index 0000000..fcf2cf0 --- /dev/null +++ b/bench.sh @@ -0,0 +1 @@ +hyperfine "dum example:rollup-node-resolve" "dum example:esbuild-optimize-deps" --warmup 2 \ No newline at end of file diff --git a/example/index.js b/example/index.js index d09757c..6389130 100644 --- a/example/index.js +++ b/example/index.js @@ -1,3 +1,7 @@ import Foo from './foo' +import * as Vue from 'vue' +import React from 'react' +import * as Three from 'three' +import * as _ from 'lodash' -console.log(Foo) \ No newline at end of file +export { Foo, Vue, React, Three, _ } diff --git a/example/rollup.config.js b/example/rollup.config.js index 73a18d1..7ad02ee 100644 --- a/example/rollup.config.js +++ b/example/rollup.config.js @@ -1,14 +1,25 @@ +import path from 'path' +import nodeResolve from '@rollup/plugin-node-resolve' +import cjs from '@rollup/plugin-commonjs' + +// @ts-check const esbuild = require('../dist/index') +const optimize = !!process.env.OPTIMIZE export default { - input: 'example/index.js', + input: path.join(__dirname, 'index.js'), output: { - file: 'example/dist/index.js', + dir: path.join(__dirname, 'dist'), format: 'cjs', }, plugins: [ - esbuild({ - minify: !isDev, + esbuild.default({ + minify: process.env.NODE_ENV === 'production', + optimizeDeps: { + include: optimize ? ['vue', 'react', 'three', 'lodash'] : [], + }, }), + !optimize && cjs(), + !optimize && nodeResolve(), ], } diff --git a/package.json b/package.json index 2a30093..010e0d1 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "repository": "https://github.com/egoist/rollup-plugin-esbuild", "scripts": { "test": "jest", - "example": "npm run build && rollup -c example/rollup.config.js", + "example:rollup-node-resolve": "rollup -c example/rollup.config.js", + "example:esbuild-optimize-deps": "OPTIMIZE=true rollup -c example/rollup.config.js", "build": "rm -rf dist && tsup src/index.ts --format esm,cjs --dts", "prepublishOnly": "npm run build" }, @@ -21,19 +22,29 @@ "dist" ], "devDependencies": { + "@rollup/plugin-commonjs": "^21.0.1", + "@rollup/plugin-node-resolve": "^13.1.1", + "@types/debug": "^4.1.7", "@types/jest": "^27.0.2", "@types/node": "14.14.37", "esbuild": "^0.14.8", "istextorbinary": "^6.0.0", "jest": "^27.3.1", + "lodash": "^4.17.21", "prettier": "^2.4.1", + "react": "^17.0.2", "rollup": "^2.59.0", + "three": "^0.136.0", + "ts-essentials": "^9.1.0", "ts-jest": "^27.0.7", "tsup": "^5.7.2", - "typescript": "^4.4.4" + "typescript": "^4.4.4", + "vue": "^3.2.26" }, "dependencies": { "@rollup/pluginutils": "^4.1.1", + "debug": "^4.3.3", + "es-module-lexer": "^0.9.3", "joycon": "^3.0.1", "jsonc-parser": "^3.0.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2eb86f1..4f1218d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,36 +1,56 @@ lockfileVersion: 5.3 specifiers: + '@rollup/plugin-commonjs': ^21.0.1 + '@rollup/plugin-node-resolve': ^13.1.1 '@rollup/pluginutils': ^4.1.1 + '@types/debug': ^4.1.7 '@types/jest': ^27.0.2 '@types/node': 14.14.37 + debug: ^4.3.3 + es-module-lexer: ^0.9.3 esbuild: ^0.14.8 istextorbinary: ^6.0.0 jest: ^27.3.1 joycon: ^3.0.1 jsonc-parser: ^3.0.0 + lodash: ^4.17.21 prettier: ^2.4.1 + react: ^17.0.2 rollup: ^2.59.0 + three: ^0.136.0 + ts-essentials: ^9.1.0 ts-jest: ^27.0.7 tsup: ^5.7.2 typescript: ^4.4.4 + vue: ^3.2.26 dependencies: '@rollup/pluginutils': 4.1.1 + debug: 4.3.3 + es-module-lexer: 0.9.3 joycon: 3.0.1 jsonc-parser: 3.0.0 devDependencies: + '@rollup/plugin-commonjs': 21.0.1_rollup@2.59.0 + '@rollup/plugin-node-resolve': 13.1.1_rollup@2.59.0 + '@types/debug': 4.1.7 '@types/jest': 27.0.2 '@types/node': 14.14.37 esbuild: 0.14.8 istextorbinary: 6.0.0 jest: 27.3.1 + lodash: 4.17.21 prettier: 2.4.1 + react: 17.0.2 rollup: 2.59.0 + three: 0.136.0 + ts-essentials: 9.1.0_typescript@4.4.4 ts-jest: 27.0.7_2c4ca6574207836d1023f54689cc81ac tsup: 5.7.2_typescript@4.4.4 typescript: 4.4.4 + vue: 3.2.26 packages: @@ -60,7 +80,7 @@ packages: '@babel/traverse': 7.16.0 '@babel/types': 7.16.0 convert-source-map: 1.8.0 - debug: 4.3.2 + debug: 4.3.3 gensync: 1.0.0-beta.2 json5: 2.2.0 semver: 6.3.0 @@ -218,6 +238,12 @@ packages: hasBin: true dev: true + /@babel/parser/7.16.6: + resolution: {integrity: sha512-Gr86ujcNuPDnNOY8mi383Hvi8IYrJVJYuf3XcuBM/Dgd+bINn/7tHqsj+tKkoreMbmGsFLsltI/JJd8fOFWGDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + dev: true + /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.16.0: resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: @@ -357,7 +383,7 @@ packages: '@babel/helper-split-export-declaration': 7.16.0 '@babel/parser': 7.16.2 '@babel/types': 7.16.0 - debug: 4.3.2 + debug: 4.3.3 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -603,6 +629,49 @@ packages: fastq: 1.13.0 dev: true + /@rollup/plugin-commonjs/21.0.1_rollup@2.59.0: + resolution: {integrity: sha512-EA+g22lbNJ8p5kuZJUYyhhDK7WgJckW5g4pNN7n4mAFUM96VuwUnNT3xr2Db2iCZPI1pJPbGyfT5mS9T1dHfMg==} + engines: {node: '>= 8.0.0'} + peerDependencies: + rollup: ^2.38.3 + dependencies: + '@rollup/pluginutils': 3.1.0_rollup@2.59.0 + commondir: 1.0.1 + estree-walker: 2.0.2 + glob: 7.2.0 + is-reference: 1.2.1 + magic-string: 0.25.7 + resolve: 1.20.0 + rollup: 2.59.0 + dev: true + + /@rollup/plugin-node-resolve/13.1.1_rollup@2.59.0: + resolution: {integrity: sha512-6QKtRevXLrmEig9UiMYt2fSvee9TyltGRfw+qSs6xjUnxwjOzTOqy+/Lpxsgjb8mJn1EQNbCDAvt89O4uzL5kw==} + engines: {node: '>= 10.0.0'} + peerDependencies: + rollup: ^2.42.0 + dependencies: + '@rollup/pluginutils': 3.1.0_rollup@2.59.0 + '@types/resolve': 1.17.1 + builtin-modules: 3.2.0 + deepmerge: 4.2.2 + is-module: 1.0.0 + resolve: 1.20.0 + rollup: 2.59.0 + dev: true + + /@rollup/pluginutils/3.1.0_rollup@2.59.0: + resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} + engines: {node: '>= 8.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0 + dependencies: + '@types/estree': 0.0.39 + estree-walker: 1.0.1 + picomatch: 2.3.0 + rollup: 2.59.0 + dev: true + /@rollup/pluginutils/4.1.1: resolution: {integrity: sha512-clDjivHqWGXi7u+0d2r2sBi4Ie6VLEAzWMIkvJLnDmxoOhBYOTfzGbOQBA32THHm11/LiJbd01tJUpJsbshSWQ==} engines: {node: '>= 8.0.0'} @@ -657,6 +726,16 @@ packages: '@babel/types': 7.16.0 dev: true + /@types/debug/4.1.7: + resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} + dependencies: + '@types/ms': 0.7.31 + dev: true + + /@types/estree/0.0.39: + resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} + dev: true + /@types/graceful-fs/4.1.5: resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} dependencies: @@ -686,6 +765,10 @@ packages: pretty-format: 27.3.1 dev: true + /@types/ms/0.7.31: + resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} + dev: true + /@types/node/14.14.37: resolution: {integrity: sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==} dev: true @@ -694,6 +777,12 @@ packages: resolution: {integrity: sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==} dev: true + /@types/resolve/1.17.1: + resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} + dependencies: + '@types/node': 14.14.37 + dev: true + /@types/stack-utils/2.0.1: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} dev: true @@ -708,6 +797,89 @@ packages: '@types/yargs-parser': 20.2.1 dev: true + /@vue/compiler-core/3.2.26: + resolution: {integrity: sha512-N5XNBobZbaASdzY9Lga2D9Lul5vdCIOXvUMd6ThcN8zgqQhPKfCV+wfAJNNJKQkSHudnYRO2gEB+lp0iN3g2Tw==} + dependencies: + '@babel/parser': 7.16.6 + '@vue/shared': 3.2.26 + estree-walker: 2.0.2 + source-map: 0.6.1 + dev: true + + /@vue/compiler-dom/3.2.26: + resolution: {integrity: sha512-smBfaOW6mQDxcT3p9TKT6mE22vjxjJL50GFVJiI0chXYGU/xzC05QRGrW3HHVuJrmLTLx5zBhsZ2dIATERbarg==} + dependencies: + '@vue/compiler-core': 3.2.26 + '@vue/shared': 3.2.26 + dev: true + + /@vue/compiler-sfc/3.2.26: + resolution: {integrity: sha512-ePpnfktV90UcLdsDQUh2JdiTuhV0Skv2iYXxfNMOK/F3Q+2BO0AulcVcfoksOpTJGmhhfosWfMyEaEf0UaWpIw==} + dependencies: + '@babel/parser': 7.16.6 + '@vue/compiler-core': 3.2.26 + '@vue/compiler-dom': 3.2.26 + '@vue/compiler-ssr': 3.2.26 + '@vue/reactivity-transform': 3.2.26 + '@vue/shared': 3.2.26 + estree-walker: 2.0.2 + magic-string: 0.25.7 + postcss: 8.4.5 + source-map: 0.6.1 + dev: true + + /@vue/compiler-ssr/3.2.26: + resolution: {integrity: sha512-2mywLX0ODc4Zn8qBoA2PDCsLEZfpUGZcyoFRLSOjyGGK6wDy2/5kyDOWtf0S0UvtoyVq95OTSGIALjZ4k2q/ag==} + dependencies: + '@vue/compiler-dom': 3.2.26 + '@vue/shared': 3.2.26 + dev: true + + /@vue/reactivity-transform/3.2.26: + resolution: {integrity: sha512-XKMyuCmzNA7nvFlYhdKwD78rcnmPb7q46uoR00zkX6yZrUmcCQ5OikiwUEVbvNhL5hBJuvbSO95jB5zkUon+eQ==} + dependencies: + '@babel/parser': 7.16.6 + '@vue/compiler-core': 3.2.26 + '@vue/shared': 3.2.26 + estree-walker: 2.0.2 + magic-string: 0.25.7 + dev: true + + /@vue/reactivity/3.2.26: + resolution: {integrity: sha512-h38bxCZLW6oFJVDlCcAiUKFnXI8xP8d+eO0pcDxx+7dQfSPje2AO6M9S9QO6MrxQB7fGP0DH0dYQ8ksf6hrXKQ==} + dependencies: + '@vue/shared': 3.2.26 + dev: true + + /@vue/runtime-core/3.2.26: + resolution: {integrity: sha512-BcYi7qZ9Nn+CJDJrHQ6Zsmxei2hDW0L6AB4vPvUQGBm2fZyC0GXd/4nVbyA2ubmuhctD5RbYY8L+5GUJszv9mQ==} + dependencies: + '@vue/reactivity': 3.2.26 + '@vue/shared': 3.2.26 + dev: true + + /@vue/runtime-dom/3.2.26: + resolution: {integrity: sha512-dY56UIiZI+gjc4e8JQBwAifljyexfVCkIAu/WX8snh8vSOt/gMSEGwPRcl2UpYpBYeyExV8WCbgvwWRNt9cHhQ==} + dependencies: + '@vue/runtime-core': 3.2.26 + '@vue/shared': 3.2.26 + csstype: 2.6.19 + dev: true + + /@vue/server-renderer/3.2.26_vue@3.2.26: + resolution: {integrity: sha512-Jp5SggDUvvUYSBIvYEhy76t4nr1vapY/FIFloWmQzn7UxqaHrrBpbxrqPcTrSgGrcaglj0VBp22BKJNre4aA1w==} + peerDependencies: + vue: 3.2.26 + dependencies: + '@vue/compiler-ssr': 3.2.26 + '@vue/shared': 3.2.26 + vue: 3.2.26 + dev: true + + /@vue/shared/3.2.26: + resolution: {integrity: sha512-vPV6Cq+NIWbH5pZu+V+2QHE9y1qfuTq49uNWw4f7FDEeZaDU2H2cx5jcUZOAKW7qTrUS4k6qZPbMy1x4N96nbA==} + dev: true + /abab/2.0.5: resolution: {integrity: sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==} dev: true @@ -740,7 +912,7 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} dependencies: - debug: 4.3.2 + debug: 4.3.3 transitivePeerDependencies: - supports-color dev: true @@ -937,6 +1109,11 @@ packages: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: true + /builtin-modules/3.2.0: + resolution: {integrity: sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==} + engines: {node: '>=6'} + dev: true + /cac/6.7.12: resolution: {integrity: sha512-rM7E2ygtMkJqD9c7WnFU6fruFcN3xe4FM5yUmgxhZzIKJk4uHl9U/fhwdajGFQbQuv43FAUo1Fe8gX/oIKDeSA==} engines: {node: '>=8'} @@ -1056,6 +1233,10 @@ packages: engines: {node: '>= 6'} dev: true + /commondir/1.0.1: + resolution: {integrity: sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=} + dev: true + /concat-map/0.0.1: resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} dev: true @@ -1090,6 +1271,10 @@ packages: cssom: 0.3.8 dev: true + /csstype/2.6.19: + resolution: {integrity: sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==} + dev: true + /data-urls/2.0.0: resolution: {integrity: sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==} engines: {node: '>=10'} @@ -1099,8 +1284,8 @@ packages: whatwg-url: 8.7.0 dev: true - /debug/4.3.2: - resolution: {integrity: sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==} + /debug/4.3.3: + resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -1109,7 +1294,6 @@ packages: optional: true dependencies: ms: 2.1.2 - dev: true /decimal.js/10.3.1: resolution: {integrity: sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==} @@ -1170,6 +1354,10 @@ packages: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true + /es-module-lexer/0.9.3: + resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==} + dev: false + /esbuild-android-arm64/0.13.13: resolution: {integrity: sha512-T02aneWWguJrF082jZworjU6vm8f4UQ+IH2K3HREtlqoY9voiJUwHLRL6khRlsNLzVglqgqb7a3HfGx7hAADCQ==} cpu: [arm64] @@ -1538,9 +1726,12 @@ packages: engines: {node: '>=4.0'} dev: true + /estree-walker/1.0.1: + resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} + dev: true + /estree-walker/2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - dev: false /esutils/2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} @@ -1754,7 +1945,7 @@ packages: dependencies: '@tootallnate/once': 1.1.2 agent-base: 6.0.2 - debug: 4.3.2 + debug: 4.3.3 transitivePeerDependencies: - supports-color dev: true @@ -1764,7 +1955,7 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2 - debug: 4.3.2 + debug: 4.3.3 transitivePeerDependencies: - supports-color dev: true @@ -1860,6 +2051,10 @@ packages: is-extglob: 2.1.1 dev: true + /is-module/1.0.0: + resolution: {integrity: sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=} + dev: true + /is-number/7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -1869,6 +2064,12 @@ packages: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} dev: true + /is-reference/1.2.1: + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + dependencies: + '@types/estree': 0.0.39 + dev: true + /is-stream/2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -1925,7 +2126,7 @@ packages: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} dependencies: - debug: 4.3.2 + debug: 4.3.3 istanbul-lib-coverage: 3.2.0 source-map: 0.6.1 transitivePeerDependencies: @@ -2537,6 +2738,13 @@ packages: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true + /loose-envify/1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + dependencies: + js-tokens: 4.0.0 + dev: true + /lru-cache/6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -2544,6 +2752,12 @@ packages: yallist: 4.0.0 dev: true + /magic-string/0.25.7: + resolution: {integrity: sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==} + dependencies: + sourcemap-codec: 1.4.8 + dev: true + /make-dir/3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} @@ -2607,7 +2821,6 @@ packages: /ms/2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true /mz/2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -2617,6 +2830,12 @@ packages: thenify-all: 1.6.0 dev: true + /nanoid/3.1.30: + resolution: {integrity: sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + /natural-compare/1.4.0: resolution: {integrity: sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=} dev: true @@ -2763,6 +2982,15 @@ packages: yaml: 1.10.2 dev: true + /postcss/8.4.5: + resolution: {integrity: sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.1.30 + picocolors: 1.0.0 + source-map-js: 1.0.1 + dev: true + /prelude-ls/1.1.2: resolution: {integrity: sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=} engines: {node: '>= 0.8.0'} @@ -2809,6 +3037,14 @@ packages: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} dev: true + /react/17.0.2: + resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==} + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + dev: true + /readdirp/3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -2924,6 +3160,11 @@ packages: engines: {node: '>=8'} dev: true + /source-map-js/1.0.1: + resolution: {integrity: sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==} + engines: {node: '>=0.10.0'} + dev: true + /source-map-support/0.5.20: resolution: {integrity: sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==} dependencies: @@ -2946,6 +3187,10 @@ packages: engines: {node: '>= 8'} dev: true + /sourcemap-codec/1.4.8: + resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} + dev: true + /sprintf-js/1.0.3: resolution: {integrity: sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=} dev: true @@ -3072,6 +3317,10 @@ packages: any-promise: 1.3.0 dev: true + /three/0.136.0: + resolution: {integrity: sha512-+fEMX7nYLz2ZesVP/dyifli5Jf8gR3XPAnFJveQ80aMhibFduzrADnjMbARXh8+W9qLK7rshJCjAIL/6cDxC+A==} + dev: true + /throat/6.0.1: resolution: {integrity: sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==} dev: true @@ -3113,6 +3362,14 @@ packages: hasBin: true dev: true + /ts-essentials/9.1.0_typescript@4.4.4: + resolution: {integrity: sha512-L0ggCct1zrW4qoVs3+sVZvT3upDdbPGJTsfIau9kiZxlyRFaMWDZxAI/VsM1HX9fCJWgoNoynxYm2GcxwQtDMg==} + peerDependencies: + typescript: '>=4.1.0' + dependencies: + typescript: 4.4.4 + dev: true + /ts-interface-checker/0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} dev: true @@ -3160,7 +3417,7 @@ packages: cac: 6.7.12 chalk: 4.1.2 chokidar: 3.5.2 - debug: 4.3.2 + debug: 4.3.3 esbuild: 0.13.13 execa: 5.1.1 globby: 11.0.4 @@ -3219,6 +3476,16 @@ packages: source-map: 0.7.3 dev: true + /vue/3.2.26: + resolution: {integrity: sha512-KD4lULmskL5cCsEkfhERVRIOEDrfEL9CwAsLYpzptOGjaGFNWo3BQ9g8MAb7RaIO71rmVOziZ/uEN/rHwcUIhg==} + dependencies: + '@vue/compiler-dom': 3.2.26 + '@vue/compiler-sfc': 3.2.26 + '@vue/runtime-dom': 3.2.26 + '@vue/server-renderer': 3.2.26_vue@3.2.26 + '@vue/shared': 3.2.26 + dev: true + /w3c-hr-time/1.0.2: resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} dependencies: diff --git a/src/bundle.ts b/src/bundle.ts deleted file mode 100644 index 9ee9d4a..0000000 --- a/src/bundle.ts +++ /dev/null @@ -1,246 +0,0 @@ -import { - build, - Loader, - OnLoadArgs, - OnLoadOptions, - OnLoadResult, - OnResolveArgs, - OnResolveOptions, - OnResolveResult, - Plugin as EsbuildPlugin, - PluginBuild, -} from 'esbuild' -import { - PluginContext as RollupPluginContext, - Plugin as RollupPlugin, - LoadResult, -} from 'rollup' -import { isBinary } from 'istextorbinary' -import path from 'path' - -export type BundleOptions = { - cwd: string - loaders?: { - [ext: string]: Loader - } - target?: string | string[] - esbuildPlugins?: EsbuildPlugin[] - rollupPlugins?: RollupPlugin[] - rollupPluginContext: RollupPluginContext - isEntry?: boolean -} - -type MaybePromise = T | Promise - -const JS_RE = /\.(js|mjs|json|jsx|tsx|ts|cjs)$/ - -export type Bundled = { - code: string - map?: string - id: string -} - -export const bundleWithEsbuild = async ( - id: string, - options: BundleOptions -): Promise => { - const rollupPlugins = options.rollupPlugins || [] - const esbuildPlugins = options.esbuildPlugins || [] - - const result = await build({ - entryPoints: [id], - format: 'esm', - target: options.target, - bundle: true, - write: false, - sourcemap: 'external', - outdir: 'dist', - platform: 'node', - loader: options.loaders, - plugins: [ - { - name: 'rollup', - setup: (build) => { - const onResolves: { - pluginName: string - options: OnResolveOptions - callback: ( - args: OnResolveArgs - ) => MaybePromise - }[] = [] - const onLoads: { - pluginName: string - options: OnLoadOptions - callback: ( - args: OnLoadArgs - ) => MaybePromise - }[] = [] - - for (const plugin of esbuildPlugins) { - const buildProxy: PluginBuild = { - ...build, - onResolve(options, callback) { - onResolves.push({ pluginName: plugin.name, options, callback }) - }, - onLoad(options, callback) { - onLoads.push({ pluginName: plugin.name, options, callback }) - }, - } - plugin.setup(buildProxy) - } - - // Try to resolve id with Esbuild plugins - for (const onResolve of onResolves) { - build.onResolve(onResolve.options, async (args) => { - const result = await Promise.resolve( - onResolve.callback(args) - ).catch((error) => { - return { - errors: [ - { text: error.message, pluginName: onResolve.pluginName }, - ], - } as OnResolveResult - }) - if (result) { - result.pluginName = onResolve.pluginName - } - if (result?.watchFiles) { - result.watchFiles.forEach((id) => - options.rollupPluginContext.addWatchFile(id) - ) - } - return result - }) - } - - // Try to resolve id with Rollup plugins - build.onResolve({ filter: /.+/ }, async (args) => { - for (const plugin of rollupPlugins) { - if (plugin.resolveId) { - const resolved = await plugin.resolveId.call( - options.rollupPluginContext, - args.path, - args.importer, - { isEntry: !!options.isEntry } - ) - if (resolved == null) continue - if (resolved === false) { - return { external: true } - } - if (typeof resolved === 'string') { - return { path: resolved } - } - return { - path: resolved.id, - external: !!resolved.external, - } - } - } - }) - - build.onLoad({ filter: /.+/ }, async (args) => { - if (isBinary(args.path)) { - return - } - - let contents: string | Uint8Array | undefined - let resolveDir: string | undefined - - // Try loading the contents with rollup plugins - for (const plugin of rollupPlugins) { - if (plugin.load && plugin.name !== 'esbuild') { - const loaded = (await plugin.load.call( - options.rollupPluginContext, - args.path - )) as LoadResult - if (loaded == null) { - continue - } else if (typeof loaded === 'string') { - contents = loaded - break - } else if (loaded) { - contents = loaded.code - break - } - } - } - - if (contents == null) { - // Try loading the contents with esbuild plugins - for (const onLoad of onLoads) { - if ( - onLoad.options.filter.test(args.path) && - (onLoad.options.namespace || 'file') === args.namespace - ) { - const result = await Promise.resolve( - onLoad.callback(args) - ).catch((error) => { - return { - errors: [ - { text: error.message, pluginName: onLoad.pluginName }, - ], - } as OnLoadResult - }) - if (result?.watchFiles) { - result.watchFiles.forEach((id) => - options.rollupPluginContext.addWatchFile(id) - ) - } - - if (result) { - if ( - (result.errors || []).length > 0 || - (result.warnings || []).length > 0 - ) { - return result - } - result.pluginName = onLoad.pluginName - if (result.contents) { - contents = result.contents - } - if (result.resolveDir) { - resolveDir = result.resolveDir - } - break - } - } - } - } - - // No contents - // Let esbuild handle it - if (contents == null) { - return - } - - return { - contents, - resolveDir, - } - }) - }, - }, - ], - }) - - const jsFile = result.outputFiles.find((file) => file.path.endsWith('.js')) - - if (!jsFile) return null - - for (const file of result.outputFiles) { - if (!JS_RE.test(file.path) && !file.path.endsWith('.map')) { - options.rollupPluginContext.emitFile({ - type: 'asset', - // TODO: the filename is mostly wrong - fileName: file.path, - source: file.contents, - }) - } - } - - return { - id: jsFile.path, - code: jsFile.text, - map: result.outputFiles.find((file) => file.path.endsWith('.map'))?.text, - } -} diff --git a/src/index.ts b/src/index.ts index aaca570..a8acd0b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,20 +1,23 @@ import { existsSync, statSync } from 'fs' import { extname, resolve, dirname, join } from 'path' import { Plugin as RollupPlugin } from 'rollup' -import { - transform, - Loader, - CommonOptions, - Plugin as EsbuildPlugin, -} from 'esbuild' +import { transform, Loader, CommonOptions } from 'esbuild' +import { MarkOptional } from 'ts-essentials' import { createFilter, FilterPattern } from '@rollup/pluginutils' +import createDebug from 'debug' import { getOptions } from './options' -import { Bundled, bundleWithEsbuild } from './bundle' import { minify, getRenderChunk } from './minify' import { warn } from './warn' +import { + optimizeDeps, + OptimizeDepsOptions, + OptimizeDepsResult, +} from './optimizer/optmize-deps' export { minify } +const debugOptimizeDeps = createDebug('rpe:optimize-deps') + const defaultLoaders: { [ext: string]: Loader } = { '.js': 'js', '.jsx': 'jsx', @@ -42,13 +45,7 @@ export type Options = { define?: { [k: string]: string } - experimentalBundling?: { - filter: - | (string | RegExp)[] - | ((id: string, importer: string | undefined) => boolean) - esbuildPlugins?: EsbuildPlugin[] - rollupPlugins?: RollupPlugin[] - } + optimizeDeps?: MarkOptional /** * Use this tsconfig file instead * Disable it by setting to `false` @@ -101,45 +98,42 @@ export default (options: Options = {}): RollupPlugin => { return null } - const experimentalBundling = options.experimentalBundling - const bundleCache: Map = new Map() - - const enabledExperimentalBundling = ( - id: string, - importer: string | undefined - ) => { - if (!experimentalBundling) return - if (Array.isArray(experimentalBundling.filter)) { - return experimentalBundling.filter.some((pattern) => - typeof pattern === 'string' ? pattern === id : pattern.test(id) - ) - } - if (typeof experimentalBundling.filter === 'function') { - return experimentalBundling.filter(id, importer) - } - } + let optimizeDepsResult: OptimizeDepsResult | undefined + let cwd = process.cwd() + let sourceMap = false return { name: 'esbuild', - buildStart() { - bundleCache.clear() + options({ context }) { + if (context) { + cwd = context + options + } + return null + }, + outputOptions({ sourcemap }) { + sourceMap = options.sourceMap ?? !!sourcemap + return null + }, + + async buildStart() { + if (!options.optimizeDeps || optimizeDepsResult) return + + optimizeDepsResult = await optimizeDeps({ + cwd, + sourceMap, + ...options.optimizeDeps, + }) + + debugOptimizeDeps('optimized %O', optimizeDepsResult.optimized) }, async resolveId(id, importer) { - if (enabledExperimentalBundling(id, importer)) { - const bundled = await bundleWithEsbuild(id, { - cwd: importer ? dirname(importer) : process.cwd(), - loaders, - target, - esbuildPlugins: experimentalBundling?.esbuildPlugins, - rollupPlugins: experimentalBundling?.rollupPlugins, - rollupPluginContext: this, - }) - if (bundled) { - bundleCache.set(bundled.id, bundled) - return bundled.id - } + if (optimizeDepsResult?.optimized.has(id)) { + const m = optimizeDepsResult.optimized.get(id)! + debugOptimizeDeps('resolved %s to %s', id, m.file) + return m.file } if (importer && id[0] === '.') { @@ -157,19 +151,8 @@ export default (options: Options = {}): RollupPlugin => { } }, - load(id) { - if (bundleCache.has(id)) { - const bundled = bundleCache.get(id)! - return { - code: bundled.code, - map: bundled.map, - } - } - }, - async transform(code, id) { - // In bundle mode transformation is handled by esbuild too - if (!filter(id) || bundleCache.has(id)) { + if (!filter(id) || optimizeDepsResult?.optimized.has(id)) { return null } @@ -194,7 +177,7 @@ export default (options: Options = {}): RollupPlugin => { jsxFactory: options.jsxFactory || defaultOptions.jsxFactory, jsxFragment: options.jsxFragment || defaultOptions.jsxFragment, define: options.define, - sourcemap: options.sourceMap !== false, + sourcemap: sourceMap, sourcefile: id, pure: options.pure, legalComments: options.legalComments, @@ -210,6 +193,9 @@ export default (options: Options = {}): RollupPlugin => { ) }, - renderChunk: getRenderChunk(options), + renderChunk: getRenderChunk({ + ...options, + sourceMap, + }), } } diff --git a/src/minify.ts b/src/minify.ts index e1f1092..1d48d73 100644 --- a/src/minify.ts +++ b/src/minify.ts @@ -57,12 +57,19 @@ export const getRenderChunk = (options: Options): RenderChunkHook => } export const minify = (options: Options = {}): Plugin => { + let sourceMap = false return { name: 'esbuild-minify', + outputOptions({ sourcemap }) { + sourceMap = options.sourceMap ?? !!sourcemap + return null + }, + renderChunk: getRenderChunk({ minify: true, ...options, + sourceMap, }), } } diff --git a/src/optimizer/optmize-deps.ts b/src/optimizer/optmize-deps.ts new file mode 100644 index 0000000..dcbef83 --- /dev/null +++ b/src/optimizer/optmize-deps.ts @@ -0,0 +1,92 @@ +import fs from 'fs' +import path from 'path' +import { build, BuildOptions as EsbuildOptions } from 'esbuild' +import esModuleLexer from 'es-module-lexer' + +export type OptimizeDepsOptions = { + include: string[] + cwd: string + esbuildOptions?: EsbuildOptions + sourceMap: boolean +} + +export type Optimized = Map + +export type OptimizeDepsResult = { + optimized: Optimized + cacheDir: string +} + +const slash = (p: string) => p.replace(/\\/g, '/') + +export const optimizeDeps = async ( + options: OptimizeDepsOptions +): Promise => { + const cacheDir = path.join(options.cwd, 'node_modules/.optimize_deps') + await fs.promises.mkdir(cacheDir, { recursive: true }) + await esModuleLexer.init + const result = await build({ + entryPoints: options.include, + absWorkingDir: options.cwd, + bundle: true, + format: 'esm', + ignoreAnnotations: true, + metafile: true, + splitting: true, + outdir: cacheDir, + sourcemap: options.sourceMap, + ...options.esbuildOptions, + plugins: [ + { + name: 'optimize-deps', + async setup(build) { + build.onResolve({ filter: /.*/ }, async (args) => { + if (args.pluginData?.__skip) return + if (options.include.includes(args.path)) { + const resolved = await build.resolve(args.path, { + resolveDir: args.resolveDir, + kind: 'import-statement', + pluginData: { __skip: true }, + }) + return { + path: args.path, + namespace: 'optimize-deps', + pluginData: { + resolveDir: args.resolveDir, + absolute: resolved.path, + }, + } + } + }) + build.onLoad( + { filter: /.*/, namespace: 'optimize-deps' }, + async (args) => { + const { absolute, resolveDir } = args.pluginData + const contents = await fs.promises.readFile(absolute, 'utf-8') + const [, exported] = esModuleLexer.parse(contents) + return { + contents: + exported.length > 0 + ? `export * from '${slash(absolute)}'` + : `module.exports = require('${slash(absolute)}')`, + resolveDir, + } + } + ) + }, + }, + ...(options.esbuildOptions?.plugins || []), + ], + }) + + const optimized: Optimized = new Map() + + for (const id of options.include) { + optimized.set(id, { file: path.join(cacheDir, `${id}.js`) }) + } + + return { + optimized, + cacheDir, + } +} diff --git a/test/index.test.ts b/test/index.test.ts index 751802c..b26dc6c 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -418,84 +418,22 @@ describe('minify plugin', () => { }) }) -describe('bundle', () => { +describe('optimizeDeps', () => { test('simple', async () => { const dir = realFs(getTestName(), { - './fixture/bar.ts': `export const bar = 'bar'`, - './fixture/Foo.jsx': ` - import {bar} from 'bar' - export const Foo =
foo {bar}
- `, - './fixture/entry-a.jsx': ` - import {Foo} from './Foo' - export const A = () => A - `, - './fixture/entry-b.jsx': ` - import {Foo} from './Foo' - export const B = () => B - `, + './index.ts': `import React from 'react';import * as Vue from 'vue';export {React,Vue}`, }) const output = await build({ - input: [ - path.join(dir, './fixture/entry-a.jsx'), - path.join(dir, './fixture/entry-b.jsx'), - ], + input: [path.join(dir, './index.ts')], rollupPlugins: [ esbuild({ - experimentalBundling: { - filter: () => true, - rollupPlugins: [ - { - name: 'alias', - resolveId(source, importer) { - if (source === 'bar' && importer) { - return path.join(path.dirname(importer), 'bar.ts') - } - }, - }, - ], + optimizeDeps: { + include: ['react', 'vue'], }, }), ], }) - expect( - output.map((o) => { - return { - code: o.type === 'chunk' ? o.code : o.source, - path: o.fileName, - } - }) - ).toMatchInlineSnapshot(` - Array [ - Object { - "code": "// test/.temp/esbuild/bundle simple/fixture/bar.ts - var bar = \\"bar\\"; - - // test/.temp/esbuild/bundle simple/fixture/Foo.jsx - var Foo = /* @__PURE__ */ React.createElement(\\"div\\", null, \\"foo \\", bar); - // test/.temp/esbuild/bundle simple/fixture/entry-a.jsx - var A = () => /* @__PURE__ */ React.createElement(Foo, null, \\"A\\"); - - export { A }; - ", - "path": "entry-a.js", - }, - Object { - "code": "// test/.temp/esbuild/bundle simple/fixture/bar.ts - var bar = \\"bar\\"; - - // test/.temp/esbuild/bundle simple/fixture/Foo.jsx - var Foo = /* @__PURE__ */ React.createElement(\\"div\\", null, \\"foo \\", bar); - - // test/.temp/esbuild/bundle simple/fixture/entry-b.jsx - var B = () => /* @__PURE__ */ React.createElement(Foo, null, \\"B\\"); - - export { B }; - ", - "path": "entry-b.js", - }, - ] - `) + expect(output[0].code).not.toContain('import ') }) })