rolldown icon indicating copy to clipboard operation
rolldown copied to clipboard

[Bug]: external-directory-import: handles using ../ as external import (#4349) test fails on wasi target

Open Brooooooklyn opened this issue 9 months ago • 2 comments

Reproduction link or steps

  • just build wasi release
  • NAPI_RS_FORCE_WASI=1 pnpm --filter rollup-tests test -- -g external-directory-import

What is expected?

Pass like native targets

What is actually happening?

❯ NAPI_RS_FORCE_WASI=1 pnpm --filter rollup-tests test -- -g external-directory-import
packages/rolldown/npm/darwin-x64         |  WARN  Unsupported platform: wanted: {"cpu":["x64"],"os":["darwin"],"libc":["any"]} (current: {"os":"darwin","cpu":"arm64","libc":"unknown"})
packages/rolldown/npm/freebsd-x64        |  WARN  Unsupported platform: wanted: {"cpu":["x64"],"os":["freebsd"],"libc":["any"]} (current: {"os":"darwin","cpu":"arm64","libc":"unknown"})
.../rolldown/npm/linux-arm-gnueabihf     |  WARN  Unsupported platform: wanted: {"cpu":["arm"],"os":["linux"],"libc":["any"]} (current: {"os":"darwin","cpu":"arm64","libc":"unknown"})
packages/rolldown/npm/linux-arm64-gnu    |  WARN  Unsupported platform: wanted: {"cpu":["arm64"],"os":["linux"],"libc":["glibc"]} (current: {"os":"darwin","cpu":"arm64","libc":"unknown"})
packages/rolldown/npm/linux-arm64-musl   |  WARN  Unsupported platform: wanted: {"cpu":["arm64"],"os":["linux"],"libc":["musl"]} (current: {"os":"darwin","cpu":"arm64","libc":"unknown"})
 WARN  6 other warnings

> rollup-tests@ test /Users/brooklyn/workspace/github/rolldown/packages/rollup-tests
> cross-env ROLLDOWN_OPTIONS_VALIDATION=loose mocha --file ./src/intercept/check.js test/test.js "-g" "external-directory-import"

(node:65270) ExperimentalWarning: WASI is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)


(node:65270) ExperimentalWarning: WASI is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
  rollup
    function
main.js
  "use strict";
  //#region rolldown:runtime
  var __create = Object.create;
  var __defProp = Object.defineProperty;
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  var __getOwnPropNames = Object.getOwnPropertyNames;
  var __getProtoOf = Object.getPrototypeOf;
  var __hasOwnProp = Object.prototype.hasOwnProperty;
  var __copyProps = (to, from, except, desc) => {
        if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
                key = keys[i];
                if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
                        get: ((k) => from[k]).bind(null, key),
                        enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
                });
        }
        return to;
  };
  var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
        value: mod,
        enumerable: true
  }) : target, mod));
  
  //#endregion
  const __ = __toESM(require("."));
  const ___ = __toESM(require("."));
  const __$1 = __toESM(require("."));
  const ___$1 = __toESM(require(".."));
  const index_js = __toESM(require("./index.js"));
  const ____index_js = __toESM(require("../index.js"));
  
  //#region main.js
  assert.strictEqual(__.default, ".");
  assert.strictEqual(___.default, "..");
  assert.strictEqual(__$1.default, ".");
  assert.strictEqual(___$1.default, "..");
  assert.strictEqual(index_js.default, "./index.js");
  assert.strictEqual(____index_js.default, "../index.js");
  
  //#endregion

      1) external-directory-import: handles using ../ as external import (#4349)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:

'.' !== '..'

    at Object.eval (eval at requireWithContext (test/function/index.js:21:21), <anonymous>:36:8)
    at requireWithContext (test/function/index.js:22:13)
    at /Users/brooklyn/workspace/github/rolldown/packages/rollup-tests/test/function/index.js:45:30
    at runCodeSplitTest (test/function/index.js:63:42)
    at /Users/brooklyn/workspace/github/rolldown/packages/rollup-tests/test/function/index.js:161:36 {
  generatedMessage: true,
  code: 'ERR_ASSERTION',
  actual: '.',
  expected: '..',
  operator: 'strictEqual',
  exports: {}
}

failures [
  "rollup@function@external-directory-import: handles using ../ as external import (#4349)"
]

System Info

System:
    OS: macOS 15.3.2
    CPU: (16) arm64 Apple M3 Max
    Memory: 21.16 GB / 128.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 22.14.0 - /opt/homebrew/bin/node
    npm: 10.9.2 - /opt/homebrew/bin/npm
    pnpm: 9.15.4 - /opt/homebrew/bin/pnpm
    bun: 1.2.5 - /opt/homebrew/bin/bun
  Browsers:
    Chrome: 134.0.6998.89
    Chrome Canary: 136.0.7075.1
    Safari: 18.3.1
  npmPackages:
    rolldown: workspace:* => 1.0.0-beta.6

Any additional comments?

No response

Brooooooklyn avatar Mar 18 '25 14:03 Brooooooklyn

I digged a little while and here are my conclusions:

The issue is related to the function ExternalModule#get_import_path.

https://github.com/rolldown/rolldown/blob/8f5f8f11eb06c497eb50d907d7fd5258ad8fe4de/crates/rolldown_common/src/module/external_module.rs#L52

  • When running wasi rolldown, env::get_current_dir would return \ instead of the actual cwd.
  • This causes ExternalModule#get_import_path returns . instead of ..
  • ExternalModule#get_import_path is ported from https://github.com/rollup/rollup/blob/ab7bfa8fe9c25e41cc62058fa2dcde6b321fd51d/src/utils/relativeId.ts#L23.

Code here

https://github.com/rolldown/rolldown/blob/8f5f8f11eb06c497eb50d907d7fd5258ad8fe4de/crates/rolldown_common/src/module/external_module.rs#L66

,for native rolldown, relative_path is ' '..'

,for wasi rolldown, relative_path is ''

these different result each cause a correct result '..' and a wrong result '.'.

The function/porting code is mainly to generate correct import path for chunk main.js who imported external module ...

Based on the test, the correct generated path should be ...

But even for https://github.com/rollup/rollup/blob/ab7bfa8fe9c25e41cc62058fa2dcde6b321fd51d/src/utils/relativeId.ts#L23 rollup itself, with forcefully settting cwd to /, it generates output ././.

Debugging PR: https://github.com/rolldown/rolldown/pull/3903.

Test Code
import { dirname, normalize, relative, basename } from 'path'
process.cwd = () => '/'
const UPPER_DIR_REGEX = /^(\.\.\/)*\.\.$/

export function getImportPath(
  importerId,
  targetPath,
  stripJsExtension,
  ensureFileName,
) {
  while (targetPath.startsWith('../')) {
    targetPath = targetPath.slice(3)
    importerId = '_/' + importerId
  }
  let relativePath = normalize(relative(dirname(importerId), targetPath))
  if (stripJsExtension && relativePath.endsWith('.js')) {
    relativePath = relativePath.slice(0, -3)
  }
  if (ensureFileName) {
    if (relativePath === '') return '../' + basename(targetPath)
    if (UPPER_DIR_REGEX.test(relativePath)) {
      return [...relativePath.split('/'), '..', basename(targetPath)].join('/')
    }
  }
  return relativePath
    ? relativePath.startsWith('..')
      ? relativePath
      : './' + relativePath
    : '.'
}

console.log(getImportPath('main.js', '..', false, true))

So the thing becomes tricky now. Possible reasons:

  • rolldown or rollup can't work under path /
  • Porting code ExternalModule#get_import_path is wrong
  • Original code of ExternalModule#get_import_path is wrong

And my idea of how to solve this issue would be:

  1. Comprehend the logic of computing import path of external modules completely
  2. Find out if this is a problem of working under / or a problem of the algorithm that's computing import path
  3. Give the fix.

However, this issue might not be solved quickly, @IWANABETHATGUY might need to decide whether we should enable full tests on wasi rolldown with ignoring this test. @underfin cc

hyf0 avatar Mar 19 '25 21:03 hyf0

conclusion: try to fix this issue in wasi target, if it is hard to fix we just ignore this test case in wasi target, since this only affects wasi target which is relatively rarely used.

IWANABETHATGUY avatar Mar 24 '25 06:03 IWANABETHATGUY