From 3e31e45272291e1828444b8dd163d5a1c5dce10c Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 14 Jan 2024 16:51:17 +0000 Subject: [PATCH 1/5] feat: add support for node-like module resolution --- fixtures/import-wasm-example/README.md | 1 + fixtures/import-wasm-example/src/index.js | 11 +- .../import-wasm-example/tests/index.test.ts | 2 +- fixtures/import-wasm-static/README.md | 2 + .../import-wasm-static/wasm/not-exported.wasm | Bin 0 -> 46 bytes .../import-wasm-static/wasm/not-exported.wat | 7 ++ packages/wrangler/package.json | 2 + .../deployment-bundle/module-collection.ts | 14 +++ pnpm-lock.yaml | 101 +++++++----------- 9 files changed, 75 insertions(+), 65 deletions(-) create mode 100644 fixtures/import-wasm-static/wasm/not-exported.wasm create mode 100644 fixtures/import-wasm-static/wasm/not-exported.wat diff --git a/fixtures/import-wasm-example/README.md b/fixtures/import-wasm-example/README.md index a8a57e937250..565bd3c375e1 100644 --- a/fixtures/import-wasm-example/README.md +++ b/fixtures/import-wasm-example/README.md @@ -1,3 +1,4 @@ # import-wasm-example `import-wasm-example` is a test fixture that imports a `wasm` file from `import-wasm-static`, testing npm module resolution with wrangler imports. +It also imports a file that isn't technically exported from `import-wasm-static`, testing more traditional node module resolution. diff --git a/fixtures/import-wasm-example/src/index.js b/fixtures/import-wasm-example/src/index.js index 300683601a95..bf0f6d049d0d 100644 --- a/fixtures/import-wasm-example/src/index.js +++ b/fixtures/import-wasm-example/src/index.js @@ -1,12 +1,19 @@ // this is from the `import-wasm-static` fixture defined above // and setup inside package.json to mimic an npm package import multiply from "import-wasm-static/multiply.wasm"; +import otherMultiple from "import-wasm-static/wasm/not-exported.wasm"; export default { async fetch(request) { // just instantiate and return something - // we're really just testing the import at the top of this file + // we're really just testing the imports at the top of this file const multiplyModule = await WebAssembly.instantiate(multiply); - return new Response(`${multiplyModule.exports.multiply(7, 3)}`); + const otherModule = await WebAssembly.instantiate(otherMultiple); + + const results = [ + multiplyModule.exports.multiply(7, 3), + otherModule.exports.multiply(7, 3), + ]; + return new Response(results.join(", ")); }, }; diff --git a/fixtures/import-wasm-example/tests/index.test.ts b/fixtures/import-wasm-example/tests/index.test.ts index d81425387861..6e5da94d4647 100644 --- a/fixtures/import-wasm-example/tests/index.test.ts +++ b/fixtures/import-wasm-example/tests/index.test.ts @@ -21,6 +21,6 @@ describe("wrangler correctly imports wasm files with npm resolution", () => { it("responds", async ({ expect }) => { const response = await fetch(`http://${ip}:${port}/`); const text = await response.text(); - expect(text).toBe("21"); + expect(text).toBe("21, 21"); }); }); diff --git a/fixtures/import-wasm-static/README.md b/fixtures/import-wasm-static/README.md index 2ac75f70c4a6..71f461e8169b 100644 --- a/fixtures/import-wasm-static/README.md +++ b/fixtures/import-wasm-static/README.md @@ -1,3 +1,5 @@ # import-wasm-static `import-wasm-static` is a fixture that simply exports a `wasm` file via `package.json` exports to be used and imported in other fixtures, to test npm module resolution. + +It also provides a `not-exported.wasm` file that is not exported via `package.json` exports, to test node module resolution. diff --git a/fixtures/import-wasm-static/wasm/not-exported.wasm b/fixtures/import-wasm-static/wasm/not-exported.wasm new file mode 100644 index 0000000000000000000000000000000000000000..0fbf9272721fa9c854cd555878d6f6b10e474195 GIT binary patch literal 46 zcmZQbEY4+QU|?WmXG~zKuV<`hW@2Pu=V9c?EzK#(EXb*3VBq3pWM@!dP+-jA1^~GP B2cZA} literal 0 HcmV?d00001 diff --git a/fixtures/import-wasm-static/wasm/not-exported.wat b/fixtures/import-wasm-static/wasm/not-exported.wat new file mode 100644 index 000000000000..064fbe7eda08 --- /dev/null +++ b/fixtures/import-wasm-static/wasm/not-exported.wat @@ -0,0 +1,7 @@ +(module + (func $multiply (param $p1 i32) (param $p2 i32) (result i32) + local.get $p1 + local.get $p2 + i32.mul) + (export "multiply" (func $multiply)) +) diff --git a/packages/wrangler/package.json b/packages/wrangler/package.json index 67d3a403a6e3..578585741d24 100644 --- a/packages/wrangler/package.json +++ b/packages/wrangler/package.json @@ -110,6 +110,7 @@ "miniflare": "workspace:*", "nanoid": "^3.3.3", "path-to-regexp": "^6.2.0", + "resolve": "^1.22.8", "resolve.exports": "^2.0.2", "selfsigned": "^2.0.1", "source-map": "0.6.1", @@ -141,6 +142,7 @@ "@types/minimatch": "^5.1.2", "@types/prompts": "^2.0.14", "@types/react": "^17.0.37", + "@types/resolve": "^1.20.6", "@types/serve-static": "^1.13.10", "@types/shell-quote": "^1.7.2", "@types/signal-exit": "^3.0.1", diff --git a/packages/wrangler/src/deployment-bundle/module-collection.ts b/packages/wrangler/src/deployment-bundle/module-collection.ts index dc3bce1916ee..c8ee2905b8f2 100644 --- a/packages/wrangler/src/deployment-bundle/module-collection.ts +++ b/packages/wrangler/src/deployment-bundle/module-collection.ts @@ -3,6 +3,7 @@ import { readdirSync } from "node:fs"; import { readFile } from "node:fs/promises"; import path from "node:path"; import globToRegExp from "glob-to-regexp"; +import { sync as resolveSync } from "resolve"; import { exports as resolveExports } from "resolve.exports"; import { UserError } from "../errors"; import { logger } from "../logger"; @@ -316,6 +317,19 @@ export function createModuleCollector(props: { } } + // Next try to resolve using the node module resolution algorithm + try { + const resolved = resolveSync(args.path, { + basedir: args.resolveDir, + }); + filePath = resolved; + } catch (e) { + // We tried, now it'll just fall-through to the previous behaviour + // and ENOENT if the absolute file path doesn't exist. + } + + // Finally, load the file and hash it + // If we didn't do any smart resolution above, this will attempt to load as an absolute path const fileContent = await readFile(filePath); const fileHash = crypto .createHash("sha1") diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 37a06fb3f8ad..f920ec1bbb18 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1300,6 +1300,9 @@ importers: path-to-regexp: specifier: ^6.2.0 version: 6.2.0 + resolve: + specifier: ^1.22.8 + version: 1.22.8 resolve.exports: specifier: ^2.0.2 version: 2.0.2 @@ -1392,6 +1395,9 @@ importers: '@types/react': specifier: ^17.0.37 version: 17.0.52 + '@types/resolve': + specifier: ^1.20.6 + version: 1.20.6 '@types/serve-static': specifier: ^1.13.10 version: 1.13.10 @@ -1499,7 +1505,7 @@ importers: version: 2.5.7 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.1.7)(supports-color@9.2.2) + version: 29.7.0(supports-color@9.2.2) jest-fetch-mock: specifier: ^3.0.3 version: 3.0.3 @@ -1514,7 +1520,7 @@ importers: version: 5.1.0 msw: specifier: ^0.49.1 - version: 0.49.1(supports-color@9.2.2)(typescript@4.9.5) + version: 0.49.1(supports-color@9.2.2) open: specifier: ^8.4.0 version: 8.4.0 @@ -1640,7 +1646,7 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/core@7.22.20(supports-color@9.2.2): + /@babel/core@7.22.20: resolution: {integrity: sha512-Y6jd1ahLubuYweD/zJH+vvOY141v4f9igNQAQ+MBgq9JlHS2iTsZKn1aMsb3vGccZsXI16VzTBw52Xx0DWmtnA==} engines: {node: '>=6.9.0'} dependencies: @@ -1649,10 +1655,10 @@ packages: '@babel/generator': 7.22.15 '@babel/helper-compilation-targets': 7.22.15 '@babel/helper-module-transforms': 7.22.20(@babel/core@7.22.20) - '@babel/helpers': 7.22.15(supports-color@9.2.2) + '@babel/helpers': 7.22.15 '@babel/parser': 7.22.16 '@babel/template': 7.22.15 - '@babel/traverse': 7.22.20(supports-color@9.2.2) + '@babel/traverse': 7.22.20 '@babel/types': 7.22.19 convert-source-map: 1.8.0 debug: 4.3.4(supports-color@9.2.2) @@ -1856,7 +1862,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.22.20(supports-color@9.2.2) + '@babel/core': 7.22.20 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-module-imports': 7.22.15 '@babel/helper-simple-access': 7.22.5 @@ -1976,12 +1982,12 @@ packages: - supports-color dev: true - /@babel/helpers@7.22.15(supports-color@9.2.2): + /@babel/helpers@7.22.15: resolution: {integrity: sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw==} engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.22.15 - '@babel/traverse': 7.22.20(supports-color@9.2.2) + '@babel/traverse': 7.22.20 '@babel/types': 7.22.19 transitivePeerDependencies: - supports-color @@ -2728,7 +2734,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.20(supports-color@9.2.2) + '@babel/core': 7.22.20 '@babel/helper-plugin-utils': 7.22.5 dev: true @@ -2738,7 +2744,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.20(supports-color@9.2.2) + '@babel/core': 7.22.20 '@babel/helper-plugin-utils': 7.22.5 dev: true @@ -3066,7 +3072,7 @@ packages: '@babel/types': 7.22.5 dev: true - /@babel/traverse@7.22.20(supports-color@9.2.2): + /@babel/traverse@7.22.20: resolution: {integrity: sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw==} engines: {node: '>=6.9.0'} dependencies: @@ -6529,6 +6535,10 @@ packages: '@types/scheduler': 0.16.2 csstype: 3.1.2 + /@types/resolve@1.20.6: + resolution: {integrity: sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==} + dev: true + /@types/responselike@1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: @@ -7483,7 +7493,7 @@ packages: peerDependencies: vite: ^4.2.0 dependencies: - '@babel/core': 7.22.20(supports-color@9.2.2) + '@babel/core': 7.22.20 '@babel/plugin-transform-react-jsx-self': 7.22.5(@babel/core@7.22.20) '@babel/plugin-transform-react-jsx-source': 7.22.5(@babel/core@7.22.20) react-refresh: 0.14.0 @@ -9061,7 +9071,7 @@ packages: /core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - /create-jest@29.7.0(@types/node@20.1.7)(supports-color@9.2.2): + /create-jest@29.7.0(supports-color@9.2.2): resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -9070,7 +9080,7 @@ packages: chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.9 - jest-config: 29.7.0(@types/node@20.1.7)(supports-color@9.2.2) + jest-config: 29.7.0(@types/node@18.16.10)(supports-color@9.2.2) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -12856,7 +12866,7 @@ packages: - supports-color dev: true - /jest-cli@29.7.0(@types/node@20.1.7)(supports-color@9.2.2): + /jest-cli@29.7.0(supports-color@9.2.2): resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -12870,10 +12880,10 @@ packages: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.1.7)(supports-color@9.2.2) + create-jest: 29.7.0(supports-color@9.2.2) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.1.7)(supports-color@9.2.2) + jest-config: 29.7.0(@types/node@18.16.10)(supports-color@9.2.2) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -12924,46 +12934,6 @@ packages: - supports-color dev: true - /jest-config@29.7.0(@types/node@20.1.7)(supports-color@9.2.2): - resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true - dependencies: - '@babel/core': 7.22.5(supports-color@9.2.2) - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 20.1.7 - babel-jest: 29.7.0(@babel/core@7.22.5)(supports-color@9.2.2) - chalk: 4.1.2 - ci-info: 3.3.0 - deepmerge: 4.2.2 - glob: 7.2.0 - graceful-fs: 4.2.9 - jest-circus: 29.7.0(supports-color@9.2.2) - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0(supports-color@9.2.2) - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.5 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - dev: true - /jest-diff@29.7.0: resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -13144,7 +13114,7 @@ packages: jest-pnp-resolver: 1.2.2(jest-resolve@29.7.0) jest-util: 29.7.0 jest-validate: 29.7.0 - resolve: 1.22.2 + resolve: 1.22.8 resolve.exports: 2.0.2 slash: 3.0.0 dev: true @@ -13320,7 +13290,7 @@ packages: supports-color: 8.1.1 dev: true - /jest@29.7.0(@types/node@20.1.7)(supports-color@9.2.2): + /jest@29.7.0(supports-color@9.2.2): resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -13333,7 +13303,7 @@ packages: '@jest/core': 29.7.0(supports-color@9.2.2) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@20.1.7)(supports-color@9.2.2) + jest-cli: 29.7.0(supports-color@9.2.2) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -14593,7 +14563,7 @@ packages: /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - /msw@0.49.1(supports-color@9.2.2)(typescript@4.9.5): + /msw@0.49.1(supports-color@9.2.2): resolution: {integrity: sha512-JpIIq4P65ofj0HVmDMkJuRwgP9s5kcdutpZ15evMTb2k91/USB7IKWRLV9J1Mzc3OqTdwNj4RwtOWJ5y/FulQQ==} engines: {node: '>=14'} hasBin: true @@ -14622,7 +14592,6 @@ packages: path-to-regexp: 6.2.0 strict-event-emitter: 0.2.8 type-fest: 2.19.0 - typescript: 4.9.5 yargs: 17.7.2 transitivePeerDependencies: - encoding @@ -16544,6 +16513,14 @@ packages: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + /resolve@2.0.0-next.4: resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} hasBin: true From 81935080d9ce392e8c651e50fb1be2879184b41e Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 14 Jan 2024 16:59:32 +0000 Subject: [PATCH 2/5] chore: add changeset --- .changeset/sour-plums-pull.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .changeset/sour-plums-pull.md diff --git a/.changeset/sour-plums-pull.md b/.changeset/sour-plums-pull.md new file mode 100644 index 000000000000..6a0db4da79fa --- /dev/null +++ b/.changeset/sour-plums-pull.md @@ -0,0 +1,13 @@ +--- +"wrangler": patch +--- + +feat: resolve imports in a more node-like fashion, greatly increasing developer experience. + +Previously, trying to import a file that wasn't explicitly exported from a module would result in an error, but now, better attempts are made to resolve the import using node's module resolution algorithm. It's now possible to do things like this: + +```js +import JPEG_DEC_WASM from "@jsquash/jpeg/codec/dec/mozjpeg_dec.wasm"; +``` + +This works even if the `mozjpeg_dec.wasm` file isn't explicitly exported from the `@jsquash/jpeg` module. From 6f5a039f8bd1bad7a038ae6908540d808db845a9 Mon Sep 17 00:00:00 2001 From: James Ross Date: Mon, 15 Jan 2024 15:06:58 +0000 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Pete Bacon Darwin --- .changeset/sour-plums-pull.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.changeset/sour-plums-pull.md b/.changeset/sour-plums-pull.md index 6a0db4da79fa..237b7e30cd01 100644 --- a/.changeset/sour-plums-pull.md +++ b/.changeset/sour-plums-pull.md @@ -2,7 +2,7 @@ "wrangler": patch --- -feat: resolve imports in a more node-like fashion, greatly increasing developer experience. +feat: resolve imports in a more node-like fashion for package that do not declare exports Previously, trying to import a file that wasn't explicitly exported from a module would result in an error, but now, better attempts are made to resolve the import using node's module resolution algorithm. It's now possible to do things like this: @@ -11,3 +11,5 @@ import JPEG_DEC_WASM from "@jsquash/jpeg/codec/dec/mozjpeg_dec.wasm"; ``` This works even if the `mozjpeg_dec.wasm` file isn't explicitly exported from the `@jsquash/jpeg` module. + +Fixes #4726 From c0a930d1bca2f39da455fd63c270ada8b5b8523c Mon Sep 17 00:00:00 2001 From: James Ross Date: Mon, 15 Jan 2024 15:07:38 +0000 Subject: [PATCH 4/5] chore: changeset typo --- .changeset/sour-plums-pull.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/sour-plums-pull.md b/.changeset/sour-plums-pull.md index 237b7e30cd01..855e3e41e158 100644 --- a/.changeset/sour-plums-pull.md +++ b/.changeset/sour-plums-pull.md @@ -2,7 +2,7 @@ "wrangler": patch --- -feat: resolve imports in a more node-like fashion for package that do not declare exports +feat: resolve imports in a more node-like fashion for packages that do not declare exports Previously, trying to import a file that wasn't explicitly exported from a module would result in an error, but now, better attempts are made to resolve the import using node's module resolution algorithm. It's now possible to do things like this: @@ -12,4 +12,4 @@ import JPEG_DEC_WASM from "@jsquash/jpeg/codec/dec/mozjpeg_dec.wasm"; This works even if the `mozjpeg_dec.wasm` file isn't explicitly exported from the `@jsquash/jpeg` module. -Fixes #4726 +Fixes #4726 From 36a833b47fc3393ca4d7155b4a569e33c9c5ab80 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Mon, 15 Jan 2024 20:09:56 +0000 Subject: [PATCH 5/5] Update .changeset/sour-plums-pull.md --- .changeset/sour-plums-pull.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/sour-plums-pull.md b/.changeset/sour-plums-pull.md index 855e3e41e158..1b1508b5b79d 100644 --- a/.changeset/sour-plums-pull.md +++ b/.changeset/sour-plums-pull.md @@ -2,7 +2,7 @@ "wrangler": patch --- -feat: resolve imports in a more node-like fashion for packages that do not declare exports +fix: resolve imports in a more node-like fashion for packages that do not declare exports Previously, trying to import a file that wasn't explicitly exported from a module would result in an error, but now, better attempts are made to resolve the import using node's module resolution algorithm. It's now possible to do things like this: