Skip to content

npmResolve plugin#3

Open
bartlomieju wants to merge 7 commits into
itsdouges:mainfrom
bartlomieju:npm_loader
Open

npmResolve plugin#3
bartlomieju wants to merge 7 commits into
itsdouges:mainfrom
bartlomieju:npm_loader

Conversation

@bartlomieju
Copy link
Copy Markdown

@bartlomieju bartlomieju commented Dec 23, 2022

This PR adds basic support for loading npm: specifiers. It's a quick and dirty way to do that and it doesn't work completely - eg. React is distributed as CommonJS module, while Vite expect that we'll return an ESM module. @itsdouges do you happen to know which plugin can take care of transforming CJS to ESM? It would prefer to avoid having to write that myself as the details are gnarly.

@itsdouges
Copy link
Copy Markdown
Owner

Thanks mate! I'm running it locally and getting this error:

Uncaught SyntaxError: ambiguous indirect export: default

Is this because it's resolving to cjs instead of esm?

@bartlomieju
Copy link
Copy Markdown
Author

Thanks mate! I'm running it locally and getting this error:

Uncaught SyntaxError: ambiguous indirect export: default

Is this because it's resolving to cjs instead of esm?

Correct - react distributes as CJS, not ESM. AFAIK by default Vite will prebundle those (https://vitejs.dev/guide/dep-pre-bundling.html), so we should find a way to do the same behavior (or ideally to tell Vite to do that for us instead). I think we might have to implement similar loader for esbuild to teach it where to obtain the sources for various packages when bundling.

@itsdouges
Copy link
Copy Markdown
Owner

Right so since we aren't using node modules the whole automatic prebundling step won't work I suppose.

@itsdouges
Copy link
Copy Markdown
Owner

This is almost where I got to with my testing locally. The only difference is id finish by passing the specifier to this.resolve() so it gets the directory resolved by the rollup node resolve plugin. Mostly worked well until you get to the nested entry point case... which without reimplementing everything we'd need Deno info support to give the cache location 🤔

@itsdouges
Copy link
Copy Markdown
Owner

I've made a post on the Vite discord, hopefully someone chimes in https://discord.com/channels/804011606160703521/1056012573713117193/1056012573713117193

Comment thread src/npm-resolve.ts

export default function npmResolve({}: PluginConfig) {
export default function npmResolve(config: PluginConfig) {
// TODO(bartlomieju): both plugins should use the same instance, or maybe
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine to create two separate ones. The cache instances are passed in from the plugin config in mod.ts.

Comment thread src/deno.ts Outdated

const status = await p.status();
if (!status.success) {
throw new Error(`invariant: could not get info on ${name}`);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

${name} doesn't exist here

Comment thread src/deno.ts
return moduleInfo;
}

async function cacheInfo(): Promise<CacheInfo> {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we call this cacheDirs?

Comment thread src/npm-resolve.ts
),
);

let file = packageJson.main || 'index.js';
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to pass the package dir here to this.resolve() so the node resolve plugin picks it up and does the work, no?

(Is that what Deno would do internally, basically? Does Deno internally handle exports/main/module/files/folders for entrypoints, etc?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try, if this.resolve() would work then it would be great. Yes, Deno handles this internally

Comment thread src/npm-resolve.ts
let file = packageJson.main || 'index.js';
if (ref.subPath) {
// TODO(bartlomieju): handle other extensions
file = `${ref.subPath}.js`;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only one facet of multiple ways a package entrypoint can be defined. If Deno does this internally (I assume it would have to?) perhaps we just focus on getting the Deno side fixed? Else it's a lot of rework here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, but it will be slow - calling a subprocess to resolve each specifier seems worse than porting some code/using a package that can do that.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point 😄

Comment thread src/npm-resolve.ts
versionReq: string | null;
subPath: string | null;
}
function npmPackageReference(specifier: string): NpmPackageReference {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great function

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a direct port from Deno's code, that's how it's handled internally by Deno

@itsdouges
Copy link
Copy Markdown
Owner

itsdouges commented Dec 24, 2022

Types not loading for the NPM module, what do we need to do to get that working? We want something that works transparently (either through Deno config, or not needing anything at all). A type comment would be a deal breaker IMO.

image

image

@bartlomieju
Copy link
Copy Markdown
Author

bartlomieju commented Dec 26, 2022

Types not loading for the NPM module, what do we need to do to get that working? We want something that works transparently (either through Deno config, or not needing anything at all). A type comment would be a deal breaker IMO.

image image

If it works outside Vite project with npm: specifier then that's unexpected, I need to double check with my colleague. That said - comments are needed in some cases now (if a package doesn't provide types configuration in its package.json, automatic acquisition from DefinitelyTyped is not yet implemented).

EDIT: Just checked and it seems react doesn't have types entry right now. So this should be handled as part of denoland/deno#15960

@itsdouges
Copy link
Copy Markdown
Owner

Sweet! So the distinction is if the module doesn't ship with types it's a little more complicated and will result in maybe needing the type comment. That's fair enough

@bartlomieju
Copy link
Copy Markdown
Author

Sweet! So the distinction is if the module doesn't ship with types it's a little more complicated and will result in maybe needing the type comment. That's fair enough

Correct, but we'll fix it in the future to automatically try to acquire types from @types/<package_name>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants