Skip to content

Commit

Permalink
feat: allow to use node module specifier as the bundle input (#211)
Browse files Browse the repository at this point in the history
* feat: allow to use node module specifier as the bundle input

* Tweak

* Update yarn.lock
hyf0 authored Nov 10, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 734ea9b commit 51da74c
Showing 16 changed files with 231 additions and 32 deletions.
10 changes: 5 additions & 5 deletions crates/rolldown/src/bundler/renderer/mod.rs
Original file line number Diff line number Diff line change
@@ -165,22 +165,22 @@ impl<'r> AstRenderer<'r> {

fn strip_export_keyword(
&mut self,
decl: &oxc::ast::ast::ExportDefaultDeclaration,
default_decl: &oxc::ast::ast::ExportDefaultDeclaration,
) -> RenderControl {
match &decl.declaration {
match &default_decl.declaration {
oxc::ast::ast::ExportDefaultDeclarationKind::Expression(exp) => {
let default_ref_name = self.ctx.default_ref_name.expect("Should generated a name");
self.ctx.source.overwrite(
decl.span.start,
default_decl.span.start,
exp.span().start,
format!("var {default_ref_name} = "),
);
}
oxc::ast::ast::ExportDefaultDeclarationKind::FunctionDeclaration(decl) => {
self.ctx.remove_node(Span::new(decl.span.start, decl.span.start));
self.ctx.remove_node(Span::new(default_decl.span.start, decl.span.start));
}
oxc::ast::ast::ExportDefaultDeclarationKind::ClassDeclaration(decl) => {
self.ctx.remove_node(Span::new(decl.span.start, decl.span.start));
self.ctx.remove_node(Span::new(default_decl.span.start, decl.span.start));
}
_ => unreachable!("TypeScript code should be preprocessed"),
}
1 change: 1 addition & 0 deletions crates/rolldown/src/bundler/utils/resolve_id.rs
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ use rolldown_resolver::Resolver;

use crate::{bundler::plugin_driver::SharedPluginDriver, HookResolveIdArgs};

#[derive(Debug)]
pub struct ResolvedRequestInfo {
pub path: RawPath,
pub module_type: ModuleType,
Original file line number Diff line number Diff line change
@@ -8,6 +8,6 @@ input_file: crates/rolldown/tests/fixtures/errors/unresolved_entry
## UNRESOLVED_ENTRY

```text
[UNRESOLVED_ENTRY] Error: Cannot resolve entry module "tests/fixtures/errors/unresolved_entry/main.js"
[UNRESOLVED_ENTRY] Error: Cannot resolve entry module "./main.js"
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
!node_modules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import assert from 'assert'
import isPlainObject from './dist/is-plain-obj.mjs'

assert(isPlainObject({}))
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
source: crates/rolldown/tests/common/case.rs
expression: content
input_file: crates/rolldown/tests/fixtures/resolve/node_modules_as_entries
---
# Assets

## is-plain-obj.mjs

```js
// node_modules/is-plain-obj/index.js
function isPlainObject(value) {
if (typeof value !== 'object' || value === null) {
return false;
}
const prototype = Object.getPrototypeOf(value);
return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value);
}
export { isPlainObject as default };
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import * as pkg from 'is-plain-obj'
export default pkg

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "pre_bundle_react_react_dom",
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"input": {
"input": [
{
"name": "is-plain-obj",
"import": "is-plain-obj"
}
]
}
}
51 changes: 26 additions & 25 deletions crates/rolldown_resolver/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
use rolldown_common::{ModuleType, RawPath, ResourceId};
use rolldown_error::BuildError;
use rolldown_fs::FileSystemExt;
use std::{
borrow::Cow,
path::{Path, PathBuf},
sync::Arc,
};
use sugar_path::SugarPathBuf;
use std::{path::PathBuf, sync::Arc};
use sugar_path::{AsPath, SugarPathBuf};

use oxc_resolver::{Resolution, ResolveOptions, ResolverGeneric};

@@ -46,40 +42,45 @@ pub struct ResolveRet {
}

impl<F: FileSystemExt + Default> Resolver<F> {
#[allow(clippy::missing_errors_doc)]
// clippy::option_if_let_else: I think the current code is more readable.
#[allow(clippy::missing_errors_doc, clippy::option_if_let_else)]
pub fn resolve(
&self,
importer: Option<&ResourceId>,
specifier: &str,
) -> Result<ResolveRet, BuildError> {
// If the importer is `None`, it means that the specifier is the entry file.
// In this case, we couldn't simply use the CWD as the importer.
// Instead, we should concat the CWD with the specifier. This aligns with https://github.com/rollup/rollup/blob/680912e2ceb42c8d5e571e01c6ece0e4889aecbb/src/utils/resolveId.ts#L56.
let specifier = if importer.is_none() {
Cow::Owned(self.cwd.join(specifier).into_normalize())
let resolved = if let Some(importer) = importer {
let context = importer.as_path().parent().expect("Should have a parent dir");
self.inner.resolve(context, specifier)
} else {
Cow::Borrowed(Path::new(specifier))
};
// If the importer is `None`, it means that the specifier is provided by the user in `input`. In this case, we can't call `resolver.resolve` with
// `{ context: cwd, specifier: specifier }` due to rollup's default resolve behavior. For specifier `main`, rollup will try to resolve it as
// `{ context: cwd, specifier: cwd.join(main) }`, which will resolve to `<cwd>/main.{js,mjs}`. To align with this behavior, we should also
// concat the CWD with the specifier.
// Related rollup code: https://github.com/rollup/rollup/blob/680912e2ceb42c8d5e571e01c6ece0e4889aecbb/src/utils/resolveId.ts#L56.
let joined_specifier = self.cwd.join(specifier).into_normalize();

let context = importer.map_or(self.cwd.as_path(), |s| {
Path::new(s.as_ref()).parent().expect("Should have a parent dir")
});
let is_path_like = specifier.starts_with('.') || specifier.starts_with('/');

let resolved = self.inner.resolve(context, &specifier.to_string_lossy());
let resolved = self.inner.resolve(&self.cwd, joined_specifier.to_str().unwrap());
if resolved.is_ok() {
resolved
} else if !is_path_like {
// If the specifier is not path-like, we should try to resolve it as a bare specifier. This allows us to resolve modules from node_modules.
self.inner.resolve(&self.cwd, specifier)
} else {
resolved
}
};

match resolved {
Ok(info) => Ok(ResolveRet {
resolved: info.path().to_string_lossy().to_string().into(),
module_type: calc_module_type(&info),
}),
Err(_err) => importer.map_or_else(
|| Err(BuildError::unresolved_entry(specifier.to_str().unwrap())),
|importer| {
Err(BuildError::unresolved_import(
specifier.to_string_lossy().to_string(),
importer.prettify(),
))
},
|| Err(BuildError::unresolved_entry(specifier)),
|importer| Err(BuildError::unresolved_import(specifier.to_string(), importer.prettify())),
),
}
}
2 changes: 1 addition & 1 deletion web/wasm/package.json
Original file line number Diff line number Diff line change
@@ -17,4 +17,4 @@
"sideEffects": [
"./snippets/*"
]
}
}

0 comments on commit 51da74c

Please sign in to comment.