lucacasonato / esbuild_deno_loader

Deno module resolution for `esbuild`
https://jsr.io/@luca/esbuild-deno-loader
MIT License
176 stars 46 forks source link

cannot resolve module specifier starts with special character #74

Open babie opened 1 year ago

babie commented 1 year ago

I tried to run Tauri with Deno Fresh. So, I used deno_esbuild for compile to deno-fresh entrypoint file. And I used esbuild_deno_loader for module resolution. But, I failed.

{
  "lock": false,
  "tasks": {
    "start": "deno run -A --watch=static/,routes/ dev.ts",
    "build": "deno run -A build.ts",
    "update": "deno run -A -r https://fresh.deno.dev/update .",
    "cache": "deno cache --reload --lock=deno.lock --lock-write main.ts"
  },
  "imports": {
    "$fresh/": "https://deno.land/x/fresh@1.2.0/",
    "preact": "https://esm.sh/preact@10.15.1",
    "preact/": "https://esm.sh/preact@10.15.1/",
    "preact-render-to-string": "https://esm.sh/*preact-render-to-string@6.1.0",
    "@preact/signals": "https://esm.sh/*@preact/signals@1.1.3",
    "@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.2.3",
    "$std/": "https://deno.land/std@0.190.0/",
    "esbuild": "https://deno.land/x/esbuild@v0.18.7/mod.js",
    "esbuild-deno-loader": "https://deno.land/x/esbuild_deno_loader@0.8.1/mod.ts"
  },
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "preact"
  }
}
import * as esbuild from "esbuild";
import { denoPlugins } from "esbuild-deno-loader";
import { posix } from "$std/path/mod.ts";

const options: esbuild.BuildOptions = {
  entryPoints: [posix.resolve("main.ts")],
  bundle: true,
  format: "esm",
  outdir: posix.resolve("build"),
  minify: true,
  sourcemap: "external",
  plugins: [
    ...denoPlugins(),
  ],
};

await esbuild.build(options);

esbuild.stop();

all codes is here: https://github.com/babie/tauri-with-deno-fresh/tree/with-special-character

Expect

No errors.

Actual

$ deno task build
Task build deno run -A build.ts
✘ [ERROR] Module not found "file:///Users/babie/src/github.com/babie/tauri-deno-fresh/$std/dotenv/load.ts". [plugin deno-loader]

    main.ts:7:7:
      7 │ import "$std/dotenv/load.ts";
        ╵        ~~~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Module not found "file:///Users/babie/src/github.com/babie/tauri-deno-fresh/$fresh/server.ts". [plugin deno-loader]

    main.ts:9:22:
      9 │ import { start } from "$fresh/server.ts";
        ╵                       ~~~~~~~~~~~~~~~~~~

✘ [ERROR] Module not found "file:///Users/babie/src/github.com/babie/tauri-deno-fresh/routes/$fresh/runtime.ts". [plugin deno-loader]

    routes/index.tsx:1:21:
      1 │ import { Head } from "$fresh/runtime.ts";
        ╵                      ~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Module not found "file:///Users/babie/src/github.com/babie/tauri-deno-fresh/components/$fresh/runtime.ts". [plugin deno-loader]

    components/Button.tsx:2:27:
      2 │ import { IS_BROWSER } from "$fresh/runtime.ts";
        ╵                            ~~~~~~~~~~~~~~~~~~~

✘ [ERROR] Module not found "file:///Users/babie/src/github.com/babie/tauri-deno-fresh/routes/@preact/signals". [plugin deno-loader]

    routes/index.tsx:2:26:
      2 │ import { useSignal } from "@preact/signals";
        ╵                           ~~~~~~~~~~~~~~~~~

error: Uncaught (in promise) Error: Build failed with 5 errors:
components/Button.tsx:2:27: ERROR: [plugin: deno-loader] Module not found "file:///Users/babie/src/github.com/babie/tauri-deno-fresh/components/$fresh/runtime.ts".
main.ts:7:7: ERROR: [plugin: deno-loader] Module not found "file:///Users/babie/src/github.com/babie/tauri-deno-fresh/$std/dotenv/load.ts".
main.ts:9:22: ERROR: [plugin: deno-loader] Module not found "file:///Users/babie/src/github.com/babie/tauri-deno-fresh/$fresh/server.ts".
routes/index.tsx:1:21: ERROR: [plugin: deno-loader] Module not found "file:///Users/babie/src/github.com/babie/tauri-deno-fresh/routes/$fresh/runtime.ts".
routes/index.tsx:2:26: ERROR: [plugin: deno-loader] Module not found "file:///Users/babie/src/github.com/babie/tauri-deno-fresh/routes/@preact/signals".
  let error = new Error(`${text}${summary}`);
              ^
    at failureErrorWithLog (https://deno.land/x/esbuild@v0.18.7/mod.js:1615:15)
    at https://deno.land/x/esbuild@v0.18.7/mod.js:1027:25
    at runOnEndCallbacks (https://deno.land/x/esbuild@v0.18.7/mod.js:1450:45)
    at buildResponseToResult (https://deno.land/x/esbuild@v0.18.7/mod.js:1025:7)
    at https://deno.land/x/esbuild@v0.18.7/mod.js:1054:16
    at responseCallbacks.<computed> (https://deno.land/x/esbuild@v0.18.7/mod.js:676:9)
    at handleIncomingPacket (https://deno.land/x/esbuild@v0.18.7/mod.js:731:9)
    at readFromStdout (https://deno.land/x/esbuild@v0.18.7/mod.js:652:7)
    at https://deno.land/x/esbuild@v0.18.7/mod.js:1901:11
    at eventLoopTick (ext:core/01_core.js:183:11)

I guess that importmap module cannot resolve specifiers starts with $ or @. I will send an issue to importmap repo and connect here later.

babie commented 1 year ago

I added an importmap test: https://github.com/babie/tauri-with-deno-fresh/blob/add-importmap-test/test-importmap.ts

import {
  ImportMap,
  resolveImportMap,
  resolveModuleSpecifier,
} from "https://deno.land/x/importmap@0.2.1/mod.ts";

const importMap: ImportMap = {
  imports: {
    "./foo/": "./bar/",
    "$fresh/": "https://deno.land/x/fresh@1.2.0/",
    "@preact/signals": "https://esm.sh/*@preact/signals@1.1.3",
    "@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.2.3",
    "$std/": "https://deno.land/std@0.190.0/",
  },
};
const importMapBaseURL = new URL(import.meta.url);
const resolvedImportMap = resolveImportMap(importMap, importMapBaseURL);
console.log("resolved importmap:");
console.dir(resolvedImportMap);

const moduleSpecifiers = [
  "./foo/test.js",
  "$fresh/server.ts",
  "@preact/signals",
  "@preact/signals-core",
  "$std/dotenv/load.ts",
];
const baseURL = new URL(import.meta.url);
console.log("resolved module specifiers:");
for (const moduleSpecifier of moduleSpecifiers) {
  const resolvedModuleSpecifier = resolveModuleSpecifier(
    moduleSpecifier,
    resolvedImportMap,
    baseURL,
  );
  console.log(`${moduleSpecifier} -> ${resolvedModuleSpecifier}`);
}

but importmap module ran as expacted:

$ deno run test-importmap.ts

resolved importmap:
{
  imports: {
    "file:///Users/babie/src/github.com/babie/tauri-deno-fresh/foo/": "file:///Users/babie/src/github.com/babie/tauri-deno-fresh/bar/",
    "@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.2.3",
    "@preact/signals": "https://esm.sh/*@preact/signals@1.1.3",
    "$fresh/": "https://deno.land/x/fresh@1.2.0/",
    "$std/": "https://deno.land/std@0.190.0/"
  },
  scopes: {}
}
resolved module specifiers:
./foo/test.js -> file:///Users/babie/src/github.com/babie/tauri-deno-fresh/bar/test.js
$fresh/server.ts -> https://deno.land/x/fresh@1.2.0/server.ts
@preact/signals -> https://esm.sh/*@preact/signals@1.1.3
@preact/signals-core -> https://esm.sh/*@preact/signals-core@1.2.3
$std/dotenv/load.ts -> https://deno.land/std@0.190.0/dotenv/load.ts

there might be a bug on esbuild_deno_loader.

babie commented 1 year ago

memo:

parhaps because esbuild_deno_loader uses args.namespace(default: file) on build.onLoad() and build.onResolve() as it is.