From 54a50d6b45520f93505b4e7c13d5e0e118615bc7 Mon Sep 17 00:00:00 2001 From: Luca Casonato Date: Fri, 15 Mar 2024 14:24:33 +0100 Subject: [PATCH] fix: don't depend on npm:esbuild (#120) `npm:esbuild-wasm` does not actually use WASM when not loaded in a browser. As such, we need to use https://deno.land/x/esbuild@0.20.2/wasm.js when targeting wasm. This commit decouples esbuild_deno_loader from any specific esbuild version, by bundling the required types for the esbuild plugin API itself. --- .github/workflows/ci.yml | 4 -- README.md | 2 +- deno.json | 7 +- mod.ts | 2 +- mod_test.ts | 7 +- src/esbuild_types.ts | 136 ++++++++++++++++++++++++++++++++++++ src/loader_native.ts | 2 +- src/loader_portable.ts | 2 +- src/plugin_deno_loader.ts | 4 +- src/plugin_deno_resolver.ts | 2 +- src/shared.ts | 2 +- 11 files changed, 151 insertions(+), 19 deletions(-) create mode 100644 src/esbuild_types.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af95aee..e63f709 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,10 +42,6 @@ jobs: if: runner.os == 'Linux' run: deno lint - - name: Doc lint - if: runner.os == 'Linux' - run: deno doc --lint mod.ts - - name: Run tests run: deno test -A diff --git a/README.md b/README.md index 4f2f16b..b1d8af9 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This example bundles an entrypoint into a single ESM output. import * as esbuild from "npm:esbuild@0.20.2"; // Import the WASM build on platforms where running subprocesses is not // permitted, such as Deno Deploy, or when running without `--allow-run`. -// import * as esbuild from "npm:esbuild-wasm@0.20"; +// import * as esbuild from "https://deno.land/x/esbuild@0.20.2/wasm.js"; import { denoPlugins } from "jsr:@luca/esbuild-deno-loader@^0.10.2"; diff --git a/deno.json b/deno.json index 60bf630..4ce55e6 100644 --- a/deno.json +++ b/deno.json @@ -1,7 +1,10 @@ { "name": "@luca/esbuild-deno-loader", "version": "0.10.2", - "exports": "./mod.ts", + "exports": { + ".": "./mod.ts", + "./esbuild_types": "./src/esbuild_types.ts" + }, "imports": { "@std/assert": "jsr:@std/assert@0.213", "@std/encoding/base32": "jsr:@std/encoding@0.213/base32", @@ -9,8 +12,6 @@ "@std/fs": "jsr:@std/fs@0.213", "@std/jsonc": "jsr:@std/jsonc@0.213", "@std/path": "jsr:@std/path@0.213", - "esbuild-wasm": "npm:esbuild-wasm@0.20.0", - "esbuild": "npm:esbuild@0.20.0", "x/importmap": "./vendor/x/importmap/mod.ts", "x/importmap/_util.ts": "./vendor/x/importmap/_util.ts" }, diff --git a/mod.ts b/mod.ts index 2e84d88..57ee02f 100644 --- a/mod.ts +++ b/mod.ts @@ -1,4 +1,4 @@ -import type esbuild from "esbuild"; +import type * as esbuild from "./src/esbuild_types.ts"; import { denoResolverPlugin, diff --git a/mod_test.ts b/mod_test.ts index de79501..36eb3fe 100644 --- a/mod_test.ts +++ b/mod_test.ts @@ -1,6 +1,5 @@ -import type esbuild from "esbuild"; -import esbuildNative from "esbuild"; -import esbuildWasm from "esbuild-wasm"; +import * as esbuildNative from "https://deno.land/x/esbuild@v0.20.2/mod.js"; +import * as esbuildWasm from "https://deno.land/x/esbuild@v0.20.2/wasm.js"; import { join } from "@std/path"; import { assert, assertEquals, assertStringIncludes } from "@std/assert"; import { @@ -767,7 +766,7 @@ Deno.test("bundle config inline import map with expansion", async (t) => { }); }); -const COMPUTED_PLUGIN: esbuild.Plugin = { +const COMPUTED_PLUGIN: esbuildNative.Plugin = { name: "computed", setup(build) { build.onResolve({ filter: /.*/, namespace: "computed" }, (args) => { diff --git a/src/esbuild_types.ts b/src/esbuild_types.ts new file mode 100644 index 0000000..66e59d9 --- /dev/null +++ b/src/esbuild_types.ts @@ -0,0 +1,136 @@ +/** + * This is a copy of the esbuild types that `deno_esbuild_loader` uses. This is + * necessary because the `esbuild` package is not available on JSR yet. + * + * @module + */ + +/** the type of import */ +export type ImportKind = + | "entry-point" + // JS + | "import-statement" + | "require-call" + | "dynamic-import" + | "require-resolve" + // CSS + | "import-rule" + | "composes-from" + | "url-token"; + +/** Documentation: https://esbuild.github.io/api/#loader */ +export type Loader = + | "base64" + | "binary" + | "copy" + | "css" + | "dataurl" + | "default" + | "empty" + | "file" + | "js" + | "json" + | "jsx" + | "local-css" + | "text" + | "ts" + | "tsx"; + +/** Documentation: https://esbuild.github.io/plugins */ +export interface Plugin { + name: string; + setup: (build: PluginBuild) => void | Promise; +} + +/** Documentation: https://esbuild.github.io/plugins */ +export interface PluginBuild { + /** Documentation: https://esbuild.github.io/plugins/#build-options */ + initialOptions: BuildOptions; + + /** Documentation: https://esbuild.github.io/plugins/#resolve */ + resolve(path: string, options?: ResolveOptions): Promise; + + /** Documentation: https://esbuild.github.io/plugins/#on-start */ + onStart(callback: () => Promise): void; + + /** Documentation: https://esbuild.github.io/plugins/#on-resolve */ + onResolve( + options: OnResolveOptions, + callback: (args: OnResolveArgs) => Promise, + ): void; + + /** Documentation: https://esbuild.github.io/plugins/#on-load */ + onLoad( + options: OnLoadOptions, + callback: (args: OnLoadArgs) => Promise | undefined, + ): void; +} + +/** Documentation: https://esbuild.github.io/api */ +export interface BuildOptions { + /** Documentation: https://esbuild.github.io/api/#external */ + external?: string[]; + /** Documentation: https://esbuild.github.io/api/#working-directory */ + absWorkingDir?: string; +} + +/** Documentation: https://esbuild.github.io/plugins/#resolve-options */ +export interface ResolveOptions { + importer?: string; + resolveDir?: string; + namespace?: string; + kind?: ImportKind; +} + +/** Documentation: https://esbuild.github.io/plugins/#resolve-results */ +export interface ResolveResult { + path: string; + namespace: string; +} + +/** Documentation: https://esbuild.github.io/plugins/#on-resolve-options */ +export interface OnResolveOptions { + filter: RegExp; + namespace?: string; +} + +/** Documentation: https://esbuild.github.io/plugins/#on-resolve-arguments */ +export interface OnResolveArgs { + path: string; + importer: string; + namespace: string; + resolveDir: string; + kind: ImportKind; +} + +export interface OnResolveResult { + path?: string; + external?: boolean; + namespace?: string; +} + +/** Documentation: https://esbuild.github.io/plugins/#on-load-options */ +export interface OnLoadOptions { + filter: RegExp; + namespace?: string; +} + +/** Documentation: https://esbuild.github.io/plugins/#on-load-arguments */ +export interface OnLoadArgs { + path: string; + namespace: string; +} + +/** Documentation: https://esbuild.github.io/plugins/#on-load-results */ +export interface OnLoadResult { + contents?: string | Uint8Array; + resolveDir?: string; + loader?: Loader; + + watchFiles?: string[]; +} + +/** Documentation: https://esbuild.github.io/plugins/#on-start-results */ +// deno-lint-ignore no-empty-interface +export interface OnStartResult { +} diff --git a/src/loader_native.ts b/src/loader_native.ts index 028c020..a3f46df 100644 --- a/src/loader_native.ts +++ b/src/loader_native.ts @@ -1,4 +1,4 @@ -import esbuild from "esbuild"; +import type * as esbuild from "./esbuild_types.ts"; import { dirname, fromFileUrl, join } from "@std/path"; import { encodeBase32 } from "@std/encoding/base32"; import * as deno from "./deno.ts"; diff --git a/src/loader_portable.ts b/src/loader_portable.ts index f90d472..18b87b1 100644 --- a/src/loader_portable.ts +++ b/src/loader_portable.ts @@ -1,4 +1,4 @@ -import esbuild from "esbuild"; +import type * as esbuild from "./esbuild_types.ts"; import { fromFileUrl } from "@std/path"; import * as deno from "./deno.ts"; import { diff --git a/src/plugin_deno_loader.ts b/src/plugin_deno_loader.ts index d82a00e..54d2f20 100644 --- a/src/plugin_deno_loader.ts +++ b/src/plugin_deno_loader.ts @@ -1,4 +1,4 @@ -import esbuild from "esbuild"; +import type * as esbuild from "./esbuild_types.ts"; import { dirname, join } from "@std/path"; import { NativeLoader } from "./loader_native.ts"; import { PortableLoader } from "./loader_portable.ts"; @@ -231,7 +231,7 @@ export function denoLoaderPlugin( async function onResolve( args: esbuild.OnResolveArgs, - ): Promise { + ): Promise { if (isNodeModulesResolution(args)) { if ( BUILTIN_NODE_MODULES.has(args.path) || diff --git a/src/plugin_deno_resolver.ts b/src/plugin_deno_resolver.ts index 67ca670..d9f0f49 100644 --- a/src/plugin_deno_resolver.ts +++ b/src/plugin_deno_resolver.ts @@ -1,4 +1,4 @@ -import esbuild from "esbuild"; +import type * as esbuild from "./esbuild_types.ts"; import { toFileUrl } from "@std/path"; import { ImportMap, diff --git a/src/shared.ts b/src/shared.ts index 39dfa4a..3f8e183 100644 --- a/src/shared.ts +++ b/src/shared.ts @@ -1,8 +1,8 @@ -import esbuild from "esbuild"; import { extname, fromFileUrl, SEPARATOR, toFileUrl } from "@std/path"; import * as JSONC from "@std/jsonc"; import { ImportMap } from "x/importmap"; import { MediaType } from "./deno.ts"; +import type * as esbuild from "./esbuild_types.ts"; export interface Loader { resolve(specifier: URL): Promise;