Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible loader chaining problem / possible yarn problem #48515

Closed
izaakschroeder opened this issue Jun 21, 2023 · 5 comments
Closed

Possible loader chaining problem / possible yarn problem #48515

izaakschroeder opened this issue Jun 21, 2023 · 5 comments
Labels
esm Issues and PRs related to the ECMAScript Modules implementation. loaders Issues and PRs related to ES module loaders

Comments

@izaakschroeder
Copy link
Contributor

izaakschroeder commented Jun 21, 2023

Version

v20.3.1

Platform

Darwin Kernel Version 22.5.0: Mon Apr 24 20:52:24 PDT 2023; root:xnu-8796.121.2~5/RELEASE_ARM64_T6000 arm64

Subsystem

esm, loaders

What steps will reproduce the bug?

  • Have Yarn 3+ installed
    • corepack enable
    • yarn set version berry
    • yarn set version 4
  • Write a custom loader that uses the load hook
    • Within that hook use await import(someFile);
    • Within someFile import a package that requires another loader to resolve

Reproducible repo: https://github.com/izaakschroeder/loader-chain-issue

Run the following:

yarn
cd packages/demo
yarn demo

/packages/banana-loader/loader.mjs:

import * as path from 'node:path';
import module from 'node:module';
import { fileURLToPath } from 'node:url'


const DEFAULT_EXTENSIONS = ['.banana'];

const compile = async (code, filepath) => {
  // We are second loader in chain so we have PnP injected yay all this works
  const pnpApi = module.findPnpApi(filepath);
  const packageLocator = pnpApi.findPackageLocator(filepath);
  const packageInformation = pnpApi.getPackageInformation(packageLocator);
  const configFile = path.join(packageInformation.packageLocation, 'banana.config.mjs');

  // This fails complaining that "banana-config" cannot be resolved
  // This confuses me because shouldn't PnP be active at this point? If the previous
  // code works then how can this not? And specifically importing `configFile`
  // itself is OK, only the import WITHIN it fails.
  const configModule = await import(configFile);

  if (configModule.default.magic !== 42) {
    throw new Error('Bad banana');
  }

  return code;
}

export const load = async (url, context, nextLoad) => {
  if (DEFAULT_EXTENSIONS.some((ext) => url.endsWith(ext))) {
    const {source, responseURL, format} = await nextLoad(url, {...context, format: 'module'});    
    const code = await compile(source.toString('utf8'), fileURLToPath(responseURL));
    return {
      format,
      source: code,
      shortCircuit: true,
    };
  }
  return nextLoad(url, context);
}

/packages/demo/banana.config.mjs:

import {createConfig} from "banana-config";

export default createConfig();

/packages/demo/test.banana:

console.log('Hello world');

/packages/banana-config/config.mjs:

export const createConfig = () => {
  return {magic: 42};
};

How often does it reproduce? Is there a required condition?

No response

What is the expected behavior? Why is that the expected behavior?

Using await import(...) should respect the existing loader chain.

What do you see instead?

Module resolution fails inside an import'd module.

Additional information

No response

@aduh95
Copy link
Contributor

aduh95 commented Jun 22, 2023

I think that's a known limitation, static imports will use only the previous loaders, dynamic imports will use whatever loaders are available at the time of the import. Calling import() inside a hook will create infinite recursion and should be avoided.

@VoltrexKeyva VoltrexKeyva added esm Issues and PRs related to the ECMAScript Modules implementation. loaders Issues and PRs related to ES module loaders labels Jun 22, 2023
@izaakschroeder
Copy link
Contributor Author

izaakschroeder commented Jun 22, 2023

Interesting 🤔 I'd love to learn a bit more. Would it be possible to point out the area in the code that is responsible for this behaviour? My mental model is currently something like this:

const loaderStack = [];

const import = async (file) => {
  let resolved = null;
  for (loader of loaderStack) {
    // if this calls import() we have a loop
    // UNLESS `loaderStack` is somehow twiddled with each time
    resolved = await loader.resolve();
    if (resolved.shortCircuit) { break; }
  }
  let result = {source: await fs.loadFile(resolved) };
  for (loader of loaderStack) {
    // if this calls import() we have a loop
    // UNLESS `loaderStack` is somehow twiddled with each time
    result = await loader.load(result);
    if (resolved.shortCircuit) { break; }
  }
  return result;
}

const addLoader = (file) => {
  loaderStack.push(await import(file));
}

@aduh95
Copy link
Contributor

aduh95 commented Jun 22, 2023

for (let i = 0; i < customLoaderURLs.length; i++) {
const customLoaderURL = customLoaderURLs[i];
// Importation must be handled by internal loader to avoid polluting user-land
const keyedExports = await privateModuleLoader.import(
customLoaderURL,
parentURL,
kEmptyObject,
);
hooks.addCustomLoader(customLoaderURL, keyedExports);
}

The mental model you presented does not correspond to the loader API (the next hook is available as an argument, and the order is different), but I'd say it's good enough to understand what's happening: once the loader module is loaded, a dynamic import would be loaded by a loaderStack that has grown since the static imports have been loaded.

@izaakschroeder
Copy link
Contributor Author

Ah excellent thanks @aduh95 😄 I'll have a look in that file!

izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jun 26, 2023
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jun 26, 2023
@izaakschroeder
Copy link
Contributor Author

izaakschroeder commented Jun 26, 2023

@aduh95 thanks for pointing me in the right direction 😄 I'm not sure if this approach is sensible or not but I have a working patch now that solves the problem: #48559 Running it against https://github.com/izaakschroeder/loader-chain-issue now produces correct output!

NODE=/PATH/TO/nodejs/node/out/Release/node

"${NODE}" \
  --require ../../.pnp.cjs \
  --loader ../../.pnp.loader.mjs \
  --loader banana-loader \
  ./demo.banana

Outputs:

Hello world

izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jun 27, 2023
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jun 27, 2023
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jun 27, 2023
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jun 30, 2023
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jun 30, 2023
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jul 4, 2023
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jul 4, 2023
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jul 12, 2023
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jul 12, 2023
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jul 14, 2023
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jul 14, 2023
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jul 14, 2023
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jul 17, 2023
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jul 17, 2023
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jul 17, 2023
Major functional changes:

- Allow `import()` to work within loaders that require other loaders,
- Unflag the use of `Module.register`.

A new interface `Customizations` has been created in order to unify
`ModuleLoader` (previously `DefaultModuleLoader`), `Hooks` and
`CustomizedModuleLoader` all of which now implement it:

```ts
interface LoadResult {
  format: ModuleFormat;
  source: ModuleSource;
}

interface ResolveResult {
  format: string;
  url: URL['href'];
}

interface Customizations {
  allowImportMetaResolve: boolean;
  load(url: string, context: object): Promise<LoadResult>
  resolve(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ): Promise<ResolveResult>
  resolveSync(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ) ResolveResult;
  register(specifier: string, parentUrl: string): any;
}
```

The `ModuleLoader` class now has `setCustomizations` which takes an
object of this shape and delegates its responsibilities to this object
if present.

Note that two properties `allowImportMetaResolve` and `resolveSync`
exist now as a mechanism for `import.meta.resolve` – since `Hooks`
does not implement `resolveSync` other loaders cannot use
`import.meta.resolve`; `allowImportMetaResolve` is a way of checking
for that case instead of invoking `resolveSync` and erroring.

Fixes nodejs#48515
Closes nodejs#48439
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jul 18, 2023
Major functional changes:

- Allow `import()` to work within loaders that require other loaders,
- Unflag the use of `Module.register`.

A new interface `Customizations` has been created in order to unify
`ModuleLoader` (previously `DefaultModuleLoader`), `Hooks` and
`CustomizedModuleLoader` all of which now implement it:

```ts
interface LoadResult {
  format: ModuleFormat;
  source: ModuleSource;
}

interface ResolveResult {
  format: string;
  url: URL['href'];
}

interface Customizations {
  allowImportMetaResolve: boolean;
  load(url: string, context: object): Promise<LoadResult>
  resolve(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ): Promise<ResolveResult>
  resolveSync(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ) ResolveResult;
  register(specifier: string, parentUrl: string): any;
  forceLoadHooks(): void;
}
```

The `ModuleLoader` class now has `setCustomizations` which takes an
object of this shape and delegates its responsibilities to this object
if present.

Note that two properties `allowImportMetaResolve` and `resolveSync`
exist now as a mechanism for `import.meta.resolve` – since `Hooks`
does not implement `resolveSync` other loaders cannot use
`import.meta.resolve`; `allowImportMetaResolve` is a way of checking
for that case instead of invoking `resolveSync` and erroring.

Fixes nodejs#48515
Closes nodejs#48439
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jul 18, 2023
Major functional changes:

- Allow `import()` to work within loaders that require other loaders,
- Unflag the use of `Module.register`.

A new interface `Customizations` has been created in order to unify
`ModuleLoader` (previously `DefaultModuleLoader`), `Hooks` and
`CustomizedModuleLoader` all of which now implement it:

```ts
interface LoadResult {
  format: ModuleFormat;
  source: ModuleSource;
}

interface ResolveResult {
  format: string;
  url: URL['href'];
}

interface Customizations {
  allowImportMetaResolve: boolean;
  load(url: string, context: object): Promise<LoadResult>
  resolve(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ): Promise<ResolveResult>
  resolveSync(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ) ResolveResult;
  register(specifier: string, parentUrl: string): any;
  forceLoadHooks(): void;
}
```

The `ModuleLoader` class now has `setCustomizations` which takes an
object of this shape and delegates its responsibilities to this object
if present.

Note that two properties `allowImportMetaResolve` and `resolveSync`
exist now as a mechanism for `import.meta.resolve` – since `Hooks`
does not implement `resolveSync` other loaders cannot use
`import.meta.resolve`; `allowImportMetaResolve` is a way of checking
for that case instead of invoking `resolveSync` and erroring.

Fixes nodejs#48515
Closes nodejs#48439
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jul 19, 2023
Major functional changes:

- Allow `import()` to work within loaders that require other loaders,
- Unflag the use of `Module.register`.

A new interface `Customizations` has been created in order to unify
`ModuleLoader` (previously `DefaultModuleLoader`), `Hooks` and
`CustomizedModuleLoader` all of which now implement it:

```ts
interface LoadResult {
  format: ModuleFormat;
  source: ModuleSource;
}

interface ResolveResult {
  format: string;
  url: URL['href'];
}

interface Customizations {
  allowImportMetaResolve: boolean;
  load(url: string, context: object): Promise<LoadResult>
  resolve(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ): Promise<ResolveResult>
  resolveSync(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ) ResolveResult;
  register(specifier: string, parentUrl: string): any;
  forceLoadHooks(): void;
  importMetaInitialize(meta, context, loader): void;
}
```

The `ModuleLoader` class now has `setCustomizations` which takes an
object of this shape and delegates its responsibilities to this object
if present.

Note that two properties `allowImportMetaResolve` and `resolveSync`
exist now as a mechanism for `import.meta.resolve` – since `Hooks`
does not implement `resolveSync` other loaders cannot use
`import.meta.resolve`; `allowImportMetaResolve` is a way of checking
for that case instead of invoking `resolveSync` and erroring.

Fixes nodejs#48515
Closes nodejs#48439
izaakschroeder added a commit to izaakschroeder/node that referenced this issue Jul 19, 2023
Major functional changes:

- Allow `import()` to work within loaders that require other loaders,
- Unflag the use of `Module.register`.

A new interface `Customizations` has been created in order to unify
`ModuleLoader` (previously `DefaultModuleLoader`), `Hooks` and
`CustomizedModuleLoader` all of which now implement it:

```ts
interface LoadResult {
  format: ModuleFormat;
  source: ModuleSource;
}

interface ResolveResult {
  format: string;
  url: URL['href'];
}

interface Customizations {
  allowImportMetaResolve: boolean;
  load(url: string, context: object): Promise<LoadResult>
  resolve(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ): Promise<ResolveResult>
  resolveSync(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ) ResolveResult;
  register(specifier: string, parentUrl: string): any;
  forceLoadHooks(): void;
  importMetaInitialize(meta, context, loader): void;
}
```

The `ModuleLoader` class now has `setCustomizations` which takes an
object of this shape and delegates its responsibilities to this object
if present.

Note that two properties `allowImportMetaResolve` and `resolveSync`
exist now as a mechanism for `import.meta.resolve` – since `Hooks`
does not implement `resolveSync` other loaders cannot use
`import.meta.resolve`; `allowImportMetaResolve` is a way of checking
for that case instead of invoking `resolveSync` and erroring.

Fixes nodejs#48515
Closes nodejs#48439
pluris pushed a commit to pluris/node that referenced this issue Aug 6, 2023
Major functional changes:

- Allow `import()` to work within loaders that require other loaders,
- Unflag the use of `Module.register`.

A new interface `Customizations` has been created in order to unify
`ModuleLoader` (previously `DefaultModuleLoader`), `Hooks` and
`CustomizedModuleLoader` all of which now implement it:

```ts
interface LoadResult {
  format: ModuleFormat;
  source: ModuleSource;
}

interface ResolveResult {
  format: string;
  url: URL['href'];
}

interface Customizations {
  allowImportMetaResolve: boolean;
  load(url: string, context: object): Promise<LoadResult>
  resolve(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ): Promise<ResolveResult>
  resolveSync(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ) ResolveResult;
  register(specifier: string, parentUrl: string): any;
  forceLoadHooks(): void;
  importMetaInitialize(meta, context, loader): void;
}
```

The `ModuleLoader` class now has `setCustomizations` which takes an
object of this shape and delegates its responsibilities to this object
if present.

Note that two properties `allowImportMetaResolve` and `resolveSync`
exist now as a mechanism for `import.meta.resolve` – since `Hooks`
does not implement `resolveSync` other loaders cannot use
`import.meta.resolve`; `allowImportMetaResolve` is a way of checking
for that case instead of invoking `resolveSync` and erroring.

Fixes nodejs#48515
Closes nodejs#48439

PR-URL: nodejs#48559
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
pluris pushed a commit to pluris/node that referenced this issue Aug 7, 2023
Major functional changes:

- Allow `import()` to work within loaders that require other loaders,
- Unflag the use of `Module.register`.

A new interface `Customizations` has been created in order to unify
`ModuleLoader` (previously `DefaultModuleLoader`), `Hooks` and
`CustomizedModuleLoader` all of which now implement it:

```ts
interface LoadResult {
  format: ModuleFormat;
  source: ModuleSource;
}

interface ResolveResult {
  format: string;
  url: URL['href'];
}

interface Customizations {
  allowImportMetaResolve: boolean;
  load(url: string, context: object): Promise<LoadResult>
  resolve(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ): Promise<ResolveResult>
  resolveSync(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ) ResolveResult;
  register(specifier: string, parentUrl: string): any;
  forceLoadHooks(): void;
  importMetaInitialize(meta, context, loader): void;
}
```

The `ModuleLoader` class now has `setCustomizations` which takes an
object of this shape and delegates its responsibilities to this object
if present.

Note that two properties `allowImportMetaResolve` and `resolveSync`
exist now as a mechanism for `import.meta.resolve` – since `Hooks`
does not implement `resolveSync` other loaders cannot use
`import.meta.resolve`; `allowImportMetaResolve` is a way of checking
for that case instead of invoking `resolveSync` and erroring.

Fixes nodejs#48515
Closes nodejs#48439

PR-URL: nodejs#48559
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Ceres6 pushed a commit to Ceres6/node that referenced this issue Aug 14, 2023
Major functional changes:

- Allow `import()` to work within loaders that require other loaders,
- Unflag the use of `Module.register`.

A new interface `Customizations` has been created in order to unify
`ModuleLoader` (previously `DefaultModuleLoader`), `Hooks` and
`CustomizedModuleLoader` all of which now implement it:

```ts
interface LoadResult {
  format: ModuleFormat;
  source: ModuleSource;
}

interface ResolveResult {
  format: string;
  url: URL['href'];
}

interface Customizations {
  allowImportMetaResolve: boolean;
  load(url: string, context: object): Promise<LoadResult>
  resolve(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ): Promise<ResolveResult>
  resolveSync(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ) ResolveResult;
  register(specifier: string, parentUrl: string): any;
  forceLoadHooks(): void;
  importMetaInitialize(meta, context, loader): void;
}
```

The `ModuleLoader` class now has `setCustomizations` which takes an
object of this shape and delegates its responsibilities to this object
if present.

Note that two properties `allowImportMetaResolve` and `resolveSync`
exist now as a mechanism for `import.meta.resolve` – since `Hooks`
does not implement `resolveSync` other loaders cannot use
`import.meta.resolve`; `allowImportMetaResolve` is a way of checking
for that case instead of invoking `resolveSync` and erroring.

Fixes nodejs#48515
Closes nodejs#48439

PR-URL: nodejs#48559
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Ceres6 pushed a commit to Ceres6/node that referenced this issue Aug 14, 2023
Major functional changes:

- Allow `import()` to work within loaders that require other loaders,
- Unflag the use of `Module.register`.

A new interface `Customizations` has been created in order to unify
`ModuleLoader` (previously `DefaultModuleLoader`), `Hooks` and
`CustomizedModuleLoader` all of which now implement it:

```ts
interface LoadResult {
  format: ModuleFormat;
  source: ModuleSource;
}

interface ResolveResult {
  format: string;
  url: URL['href'];
}

interface Customizations {
  allowImportMetaResolve: boolean;
  load(url: string, context: object): Promise<LoadResult>
  resolve(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ): Promise<ResolveResult>
  resolveSync(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ) ResolveResult;
  register(specifier: string, parentUrl: string): any;
  forceLoadHooks(): void;
  importMetaInitialize(meta, context, loader): void;
}
```

The `ModuleLoader` class now has `setCustomizations` which takes an
object of this shape and delegates its responsibilities to this object
if present.

Note that two properties `allowImportMetaResolve` and `resolveSync`
exist now as a mechanism for `import.meta.resolve` – since `Hooks`
does not implement `resolveSync` other loaders cannot use
`import.meta.resolve`; `allowImportMetaResolve` is a way of checking
for that case instead of invoking `resolveSync` and erroring.

Fixes nodejs#48515
Closes nodejs#48439

PR-URL: nodejs#48559
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
UlisesGascon pushed a commit to UlisesGascon/node that referenced this issue Aug 14, 2023
Major functional changes:

- Allow `import()` to work within loaders that require other loaders,
- Unflag the use of `Module.register`.

A new interface `Customizations` has been created in order to unify
`ModuleLoader` (previously `DefaultModuleLoader`), `Hooks` and
`CustomizedModuleLoader` all of which now implement it:

```ts
interface LoadResult {
  format: ModuleFormat;
  source: ModuleSource;
}

interface ResolveResult {
  format: string;
  url: URL['href'];
}

interface Customizations {
  allowImportMetaResolve: boolean;
  load(url: string, context: object): Promise<LoadResult>
  resolve(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ): Promise<ResolveResult>
  resolveSync(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ) ResolveResult;
  register(specifier: string, parentUrl: string): any;
  forceLoadHooks(): void;
  importMetaInitialize(meta, context, loader): void;
}
```

The `ModuleLoader` class now has `setCustomizations` which takes an
object of this shape and delegates its responsibilities to this object
if present.

Note that two properties `allowImportMetaResolve` and `resolveSync`
exist now as a mechanism for `import.meta.resolve` – since `Hooks`
does not implement `resolveSync` other loaders cannot use
`import.meta.resolve`; `allowImportMetaResolve` is a way of checking
for that case instead of invoking `resolveSync` and erroring.

Fixes nodejs#48515
Closes nodejs#48439

PR-URL: nodejs#48559
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
RafaelGSS pushed a commit that referenced this issue Aug 15, 2023
Major functional changes:

- Allow `import()` to work within loaders that require other loaders,
- Unflag the use of `Module.register`.

A new interface `Customizations` has been created in order to unify
`ModuleLoader` (previously `DefaultModuleLoader`), `Hooks` and
`CustomizedModuleLoader` all of which now implement it:

```ts
interface LoadResult {
  format: ModuleFormat;
  source: ModuleSource;
}

interface ResolveResult {
  format: string;
  url: URL['href'];
}

interface Customizations {
  allowImportMetaResolve: boolean;
  load(url: string, context: object): Promise<LoadResult>
  resolve(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ): Promise<ResolveResult>
  resolveSync(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ) ResolveResult;
  register(specifier: string, parentUrl: string): any;
  forceLoadHooks(): void;
  importMetaInitialize(meta, context, loader): void;
}
```

The `ModuleLoader` class now has `setCustomizations` which takes an
object of this shape and delegates its responsibilities to this object
if present.

Note that two properties `allowImportMetaResolve` and `resolveSync`
exist now as a mechanism for `import.meta.resolve` – since `Hooks`
does not implement `resolveSync` other loaders cannot use
`import.meta.resolve`; `allowImportMetaResolve` is a way of checking
for that case instead of invoking `resolveSync` and erroring.

Fixes #48515
Closes #48439

PR-URL: #48559
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
targos pushed a commit to targos/node that referenced this issue Nov 11, 2023
Major functional changes:

- Allow `import()` to work within loaders that require other loaders,
- Unflag the use of `Module.register`.

A new interface `Customizations` has been created in order to unify
`ModuleLoader` (previously `DefaultModuleLoader`), `Hooks` and
`CustomizedModuleLoader` all of which now implement it:

```ts
interface LoadResult {
  format: ModuleFormat;
  source: ModuleSource;
}

interface ResolveResult {
  format: string;
  url: URL['href'];
}

interface Customizations {
  allowImportMetaResolve: boolean;
  load(url: string, context: object): Promise<LoadResult>
  resolve(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ): Promise<ResolveResult>
  resolveSync(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ) ResolveResult;
  register(specifier: string, parentUrl: string): any;
  forceLoadHooks(): void;
  importMetaInitialize(meta, context, loader): void;
}
```

The `ModuleLoader` class now has `setCustomizations` which takes an
object of this shape and delegates its responsibilities to this object
if present.

Note that two properties `allowImportMetaResolve` and `resolveSync`
exist now as a mechanism for `import.meta.resolve` – since `Hooks`
does not implement `resolveSync` other loaders cannot use
`import.meta.resolve`; `allowImportMetaResolve` is a way of checking
for that case instead of invoking `resolveSync` and erroring.

Fixes nodejs#48515
Closes nodejs#48439

PR-URL: nodejs#48559
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
targos pushed a commit that referenced this issue Nov 23, 2023
Major functional changes:

- Allow `import()` to work within loaders that require other loaders,
- Unflag the use of `Module.register`.

A new interface `Customizations` has been created in order to unify
`ModuleLoader` (previously `DefaultModuleLoader`), `Hooks` and
`CustomizedModuleLoader` all of which now implement it:

```ts
interface LoadResult {
  format: ModuleFormat;
  source: ModuleSource;
}

interface ResolveResult {
  format: string;
  url: URL['href'];
}

interface Customizations {
  allowImportMetaResolve: boolean;
  load(url: string, context: object): Promise<LoadResult>
  resolve(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ): Promise<ResolveResult>
  resolveSync(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ) ResolveResult;
  register(specifier: string, parentUrl: string): any;
  forceLoadHooks(): void;
  importMetaInitialize(meta, context, loader): void;
}
```

The `ModuleLoader` class now has `setCustomizations` which takes an
object of this shape and delegates its responsibilities to this object
if present.

Note that two properties `allowImportMetaResolve` and `resolveSync`
exist now as a mechanism for `import.meta.resolve` – since `Hooks`
does not implement `resolveSync` other loaders cannot use
`import.meta.resolve`; `allowImportMetaResolve` is a way of checking
for that case instead of invoking `resolveSync` and erroring.

Fixes #48515
Closes #48439

PR-URL: #48559
Backport-PR-URL: #50669
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
sercher added a commit to sercher/graaljs that referenced this issue Apr 25, 2024
Major functional changes:

- Allow `import()` to work within loaders that require other loaders,
- Unflag the use of `Module.register`.

A new interface `Customizations` has been created in order to unify
`ModuleLoader` (previously `DefaultModuleLoader`), `Hooks` and
`CustomizedModuleLoader` all of which now implement it:

```ts
interface LoadResult {
  format: ModuleFormat;
  source: ModuleSource;
}

interface ResolveResult {
  format: string;
  url: URL['href'];
}

interface Customizations {
  allowImportMetaResolve: boolean;
  load(url: string, context: object): Promise<LoadResult>
  resolve(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ): Promise<ResolveResult>
  resolveSync(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ) ResolveResult;
  register(specifier: string, parentUrl: string): any;
  forceLoadHooks(): void;
  importMetaInitialize(meta, context, loader): void;
}
```

The `ModuleLoader` class now has `setCustomizations` which takes an
object of this shape and delegates its responsibilities to this object
if present.

Note that two properties `allowImportMetaResolve` and `resolveSync`
exist now as a mechanism for `import.meta.resolve` – since `Hooks`
does not implement `resolveSync` other loaders cannot use
`import.meta.resolve`; `allowImportMetaResolve` is a way of checking
for that case instead of invoking `resolveSync` and erroring.

Fixes nodejs/node#48515
Closes nodejs/node#48439

PR-URL: nodejs/node#48559
Backport-PR-URL: nodejs/node#50669
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
sercher added a commit to sercher/graaljs that referenced this issue Apr 25, 2024
Major functional changes:

- Allow `import()` to work within loaders that require other loaders,
- Unflag the use of `Module.register`.

A new interface `Customizations` has been created in order to unify
`ModuleLoader` (previously `DefaultModuleLoader`), `Hooks` and
`CustomizedModuleLoader` all of which now implement it:

```ts
interface LoadResult {
  format: ModuleFormat;
  source: ModuleSource;
}

interface ResolveResult {
  format: string;
  url: URL['href'];
}

interface Customizations {
  allowImportMetaResolve: boolean;
  load(url: string, context: object): Promise<LoadResult>
  resolve(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ): Promise<ResolveResult>
  resolveSync(
    originalSpecifier:
    string, parentURL: string,
    importAssertions: Record<string, string>
  ) ResolveResult;
  register(specifier: string, parentUrl: string): any;
  forceLoadHooks(): void;
  importMetaInitialize(meta, context, loader): void;
}
```

The `ModuleLoader` class now has `setCustomizations` which takes an
object of this shape and delegates its responsibilities to this object
if present.

Note that two properties `allowImportMetaResolve` and `resolveSync`
exist now as a mechanism for `import.meta.resolve` – since `Hooks`
does not implement `resolveSync` other loaders cannot use
`import.meta.resolve`; `allowImportMetaResolve` is a way of checking
for that case instead of invoking `resolveSync` and erroring.

Fixes nodejs/node#48515
Closes nodejs/node#48439

PR-URL: nodejs/node#48559
Backport-PR-URL: nodejs/node#50669
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
esm Issues and PRs related to the ECMAScript Modules implementation. loaders Issues and PRs related to ES module loaders
Projects
None yet
Development

No branches or pull requests

3 participants