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
  • Loading branch information
hyf0 committed Nov 10, 2023
1 parent 734ea9b commit 51da74c
Show file tree
Hide file tree
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
Expand Up @@ -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"),
}
Expand Down
1 change: 1 addition & 0 deletions crates/rolldown/src/bundler/utils/resolve_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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())),
),
}
}
Expand Down
2 changes: 1 addition & 1 deletion web/wasm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@
"sideEffects": [
"./snippets/*"
]
}
}

0 comments on commit 51da74c

Please sign in to comment.