antfu / esbuild-node-loader

Transpile TypeScript to ESM with Node.js loader.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Help on Windows Support

antfu opened this issue · comments

The current implementation failed on Windows, while unfortunately I don't have a Windows to test out. Would use some help on the fix. Thanks.

Seems using relative paths working, with absolute paths there is no way man (I'll try one last time to see if there's any luck):

F:\work\projects\quini\GitHub\antfu\esbuild-node-loader>pnpm run test

> esbuild-node-loader@0.2.0 test F:\work\projects\quini\GitHub\antfu\esbuild-node-loader
> node --experimental-loader ./loader.mjs test/entry.ts

(node:23624) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
• • • • • •   (6 / 6)

  Total:     6
  Passed:    6
  Skipped:   0
  Duration:  1146.71ms
test/entry.ts changes
@@ -1,12 +1,20 @@
 import assert from 'assert'
 import { test } from 'uvu'
 import execa from 'execa'
+import { relative } from 'path'
+
+const cwd = process.cwd()
+function relativize(path: string) {
+  const url = relative(cwd, path)
+  // console.log(`FROM ${path} => ${url}`)
+  return `./${url}`
+}
 
 test('register', async() => {
   const { stdout } = await execa('node', [
     '--experimental-loader',
-    `${process.cwd()}/loader.mjs`,
-    `${process.cwd()}/test/fixture.ts`,
+    relativize(`${cwd}/loader.mjs`),
+    relativize(`${cwd}/test/fixture.ts`),
   ])
   assert(stdout === 'text')
 })
@@ -14,8 +22,8 @@
 test('register2', async() => {
   const { stdout } = await execa('node', [
     '--experimental-loader',
-    `${process.cwd()}/loader.mjs`,
-    `${process.cwd()}/test/fixture.arrowFunction.ts`,
+    relativize(`${cwd}/loader.mjs`),
+    relativize(`${cwd}/test/fixture.arrowFunction.ts`),
   ])
   assert(stdout === 'hello from ts')
 })
@@ -23,8 +31,8 @@
 test('register3', async() => {
   const { stdout } = await execa('node', [
     '--experimental-loader',
-    `${process.cwd()}/loader.mjs`,
-    `${process.cwd()}/test/fixture.import.ts`,
+    relativize(`${cwd}/loader.mjs`),
+    relativize(`${cwd}/test/fixture.import.ts`),
   ])
   assert(stdout === 'export')
 })
@@ -32,8 +40,8 @@
 test('register cjs', async() => {
   const { stdout } = await execa('node', [
     '--experimental-loader',
-    `${process.cwd()}/loader.mjs`,
-    `${process.cwd()}/test/fixture.cjs.ts`,
+    relativize(`${cwd}/loader.mjs`),
+    relativize(`${cwd}/test/fixture.cjs.ts`),
   ])
   assert(stdout === 'fs imported')
 })
@@ -41,8 +49,8 @@
 test('package type module', async() => {
   const { stdout } = await execa('node', [
     '--experimental-loader',
-    `${process.cwd()}/loader.mjs`,
-    `${process.cwd()}/test/fixture-type-module/index.js`,
+    relativize(`${cwd}/loader.mjs`),
+    relativize(`${cwd}/test/fixture-type-module/index.js`),
   ])
   assert(stdout === 'foo')
 })
@@ -50,8 +58,8 @@
 test('import type module', async() => {
   const { stdout } = await execa('node', [
     '--experimental-loader',
-    `${process.cwd()}/loader.mjs`,
-    `${process.cwd()}/test/import-mjs/index.js`,
+    relativize(`${cwd}/loader.mjs`),
+    relativize(`${cwd}/test/import-mjs/index.js`),
   ])
   assert(stdout === 'foo')
 })
loader.mjs changes
@@ -1,8 +1,16 @@
 import { URL, pathToFileURL, fileURLToPath } from 'url'
 import { transformSync } from 'esbuild'
 import fs from 'fs'
+import { relative } from 'path'
 
-const baseURL = pathToFileURL(`${process.cwd()}/`).href
+const cwd = process.cwd()
+function relativize(path) {
+  const url = relative(cwd, path)
+  //console.log(`FROM ${path} => ${url}`)
+  return `./${url}`
+}
+
+const baseURL = pathToFileURL(relativize(`${cwd}/`)).href
 const isWindows = process.platform === "win32"
 
 const extensionsRegex = /\.ts$/
@@ -46,12 +54,12 @@
   const { url, format } = context
 
   if (extensionsRegex.test(url)) {
-    let filename = fileURLToPath(url)
-    if (isWindows)
-      filename = filename.slice(1)
+    // let filename = fileURLToPath(url)
+    // if (isWindows)
+    //   filename = filename.slice(1)
 
     const { code: js, warnings, map: jsSourceMap } = transformSync(source.toString(), {
-      sourcefile: filename,
+      sourcefile: url,
       sourcemap: 'both',
       loader: 'ts',
       target: 'esnext',

@antfu Working, just modify transformSource from loader.mjs:

Adjust filename assigment:

    let filename = url
    if (!isWindows)
      filename = fileURLToPath(url)

To make the tests working you need to use relativize from previous comment.

transformSource code:

export function transformSource(source, context, defaultTransformSource) {
  const { url, format } = context

  if (extensionsRegex.test(url)) {
    let filename = url
    if (!isWindows)
      filename = fileURLToPath(url)

    const { code: js, warnings, map: jsSourceMap } = transformSync(source.toString(), {
      sourcefile: filename,
      sourcemap: 'both',
      loader: 'ts',
      target: 'esnext',
      format: format === 'module' ? 'esm' : 'cjs',
    })

    if (warnings && warnings.length > 0) {
      for (const warning of warnings) {
        console.log(warning.location)
        console.log(warning.text)
      }
    }

    return {
      source: js,
    }
  }

  // Let Node.js handle all other sources.
  return defaultTransformSource(source, context, defaultTransformSource)
}

Maybe you need to check if script is provided with absolute path and then relativize from cwd: using esno I've never seen provide scripts with absolute paths, always with relative paths, I think if also working previous fix on linux/macosx, just include a warning/hint for windows users to use always relative paths to root directory.

Ideally I think we would like to have absolute path working as well

Found these 2 issues, I have tried with no luck: