Skip to content

Commit

Permalink
feat(swc): Add import resolvers (#1834)
Browse files Browse the repository at this point in the history
swc_ecma_loader:
 - Add `Resolve`. 
 - Add `TsConfigResolver`. 

swc_ecma_transforms_module:
 - Use `Resolve` for remapping import paths.
 - Add `ImportResolver`.
 - Add `NodeImprortResolver`.

swc:
 - Add `paths` to `.swcrc`.
 - Use `paths`. (#379, #702)
 - Canonicalize file names.
  • Loading branch information
kdy1 committed Jun 24, 2021
1 parent a31ca40 commit 4cd4337
Show file tree
Hide file tree
Showing 46 changed files with 899 additions and 149 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
tool: "cargo"
# Where the output from the benchmark tool is stored
output-file-path: output.txt
external-data-json-path: ./raw-data/benchmark-data.json
external-data-json-path: ./raw-data/$GITHUB_SHA/benchmark-data.json
# Workflow will fail when an alert happens
fail-on-alert: true
# GitHub API token to make a commit comment
Expand All @@ -67,8 +67,7 @@ jobs:
token: ${{ secrets.GH_TOKEN }}
branch: gh-pages
folder: raw-data
clean: true
git-config-email: kdy1997.dev@gmail.com
git-config-email: github-bot@swc.rs
repository-name: swc-project/raw-data
commit-message: "Update"
single-commit: true
2 changes: 1 addition & 1 deletion .github/workflows/cargo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ jobs:
branch: gh-pages
folder: target/doc
clean: true
git-config-email: kdy1997.dev@gmail.com
git-config-email: github-bot@swc.rs
repository-name: swc-project/rustdoc
commit-message: "Update"
single-commit: true
2 changes: 1 addition & 1 deletion .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ jobs:
npm i -g qunit failonlyreporter
# Download
git clone --depth 1 https://github.com/reduxjs/redux.git integration-tests/redux/repo
git clone --depth 1 https://github.com/reduxjs/redux.git -b v4.1.0 integration-tests/redux/repo
swc --sync integration-tests/redux/repo/src/ -d integration-tests/redux/repo/lib/
echo "module.exports=require('./index')" > integration-tests/redux/repo/lib/redux.js
swc --sync integration-tests/redux/repo/src/ -d integration-tests/redux/repo/test/
Expand Down
9 changes: 6 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc"
repository = "https://github.com/swc-project/swc.git"
version = "0.24.1"
version = "0.25.0"

[lib]
name = "swc"
Expand All @@ -23,19 +23,22 @@ base64 = "0.12.0"
dashmap = "4.0.2"
either = "1"
log = {version = "0.4", features = ["release_max_level_info"]}
lru = "0.6.1"
once_cell = "1"
regex = "1"
serde = {version = "1", features = ["derive"]}
serde_json = "1"
sourcemap = "6"
swc_atoms = {version = "0.2", path = "./atoms"}
swc_bundler = {version = "0.42.0", path = "./bundler"}
swc_common = {version = "0.10.16", path = "./common", features = ["sourcemap", "concurrent"]}
swc_ecma_ast = {version = "0.46.0", path = "./ecmascript/ast"}
swc_ecma_codegen = {version = "0.59.1", path = "./ecmascript/codegen"}
swc_ecma_ext_transforms = {version = "0.18.1", path = "./ecmascript/ext-transforms"}
swc_ecma_loader = {version = "0.8.0", path = "./ecmascript/loader", features = ["lru", "node", "tsc"]}
swc_ecma_parser = {version = "0.60.2", path = "./ecmascript/parser"}
swc_ecma_preset_env = {version = "0.24.1", path = "./ecmascript/preset-env"}
swc_ecma_transforms = {version = "0.54.1", path = "./ecmascript/transforms", features = [
swc_ecma_preset_env = {version = "0.25.0", path = "./ecmascript/preset-env"}
swc_ecma_transforms = {version = "0.55.0", path = "./ecmascript/transforms", features = [
"compat",
"module",
"optimization",
Expand Down
7 changes: 4 additions & 3 deletions bundler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ include = ["Cargo.toml", "build.rs", "src/**/*.rs", "src/**/*.js"]
license = "Apache-2.0/MIT"
name = "swc_bundler"
repository = "https://github.com/swc-project/swc.git"
version = "0.41.1"
version = "0.42.0"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
Expand All @@ -35,8 +35,9 @@ swc_atoms = {version = "0.2.4", path = "../atoms"}
swc_common = {version = "0.10.16", path = "../common"}
swc_ecma_ast = {version = "0.46.0", path = "../ecmascript/ast"}
swc_ecma_codegen = {version = "0.59.1", path = "../ecmascript/codegen"}
swc_ecma_loader = {version = "0.8.0", path = "../ecmascript/loader"}
swc_ecma_parser = {version = "0.60.2", path = "../ecmascript/parser"}
swc_ecma_transforms = {version = "0.54.1", path = "../ecmascript/transforms", features = ["optimization"]}
swc_ecma_transforms = {version = "0.55.0", path = "../ecmascript/transforms", features = ["optimization"]}
swc_ecma_utils = {version = "0.37.2", path = "../ecmascript/utils"}
swc_ecma_visit = {version = "0.32.1", path = "../ecmascript/visit"}

Expand All @@ -45,7 +46,7 @@ hex = "0.4"
ntest = "0.7.2"
reqwest = {version = "0.10.8", features = ["blocking"]}
sha-1 = "0.9"
swc_ecma_transforms = {version = "0.54.1", path = "../ecmascript/transforms", features = ["react", "typescript"]}
swc_ecma_transforms = {version = "0.55.0", path = "../ecmascript/transforms", features = ["react", "typescript"]}
tempfile = "3.1.0"
testing = {version = "0.10.5", path = "../testing"}
url = "2.1.1"
Expand Down
19 changes: 1 addition & 18 deletions bundler/src/resolve.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1 @@
use anyhow::Error;
use swc_common::FileName;

pub trait Resolve: swc_common::sync::Send + swc_common::sync::Sync {
fn resolve(&self, base: &FileName, module_specifier: &str) -> Result<FileName, Error>;
}

impl<T: ?Sized + Resolve> Resolve for Box<T> {
fn resolve(&self, base: &FileName, module_specifier: &str) -> Result<FileName, Error> {
(**self).resolve(base, module_specifier)
}
}

impl<'a, T: ?Sized + Resolve> Resolve for &'a T {
fn resolve(&self, base: &FileName, module_specifier: &str) -> Result<FileName, Error> {
(**self).resolve(base, module_specifier)
}
}
pub use swc_ecma_loader::resolve::Resolve;
6 changes: 3 additions & 3 deletions ecmascript/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecmascript"
repository = "https://github.com/swc-project/swc.git"
version = "0.40.2"
version = "0.41.0"

[package.metadata.docs.rs]
all-features = true
Expand All @@ -31,9 +31,9 @@ typescript = ["swc_ecma_transforms/typescript"]
swc_ecma_ast = {version = "0.46.0", path = "./ast"}
swc_ecma_codegen = {version = "0.59.1", path = "./codegen", optional = true}
swc_ecma_dep_graph = {version = "0.28.1", path = "./dep-graph", optional = true}
swc_ecma_minifier = {version = "0.6.1", path = "./minifier", optional = true}
swc_ecma_minifier = {version = "0.7.0", path = "./minifier", optional = true}
swc_ecma_parser = {version = "0.60.2", path = "./parser", optional = true}
swc_ecma_transforms = {version = "0.54.1", path = "./transforms", optional = true}
swc_ecma_transforms = {version = "0.55.0", path = "./transforms", optional = true}
swc_ecma_utils = {version = "0.37.2", path = "./utils", optional = true}
swc_ecma_visit = {version = "0.32.1", path = "./visit", optional = true}

Expand Down
23 changes: 21 additions & 2 deletions ecmascript/loader/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,34 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecma_loader"
repository = "https://github.com/swc-project/swc.git"
version = "0.7.1"
version = "0.8.0"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[package.metadata.docs.rs]
all-features = true

[features]
default = []

# Enable node js resolver
node = ["normpath", "serde", "serde_json"]
# Enable support for `paths` of tsconfig.json
tsc = ["dashmap", "once_cell", "regex"]

[dependencies]
anyhow = "1.0.41"
dashmap = {version = "4.0.2", optional = true}
lru = {version = "0.6.5", optional = true}
once_cell = {version = "1.8.0", optional = true}
regex = {version = "1", optional = true}
serde = {version = "1.0.126", optional = true}
serde_json = {version = "1.0.64", optional = true}
swc_atoms = {version = "0.2.3", path = "../../atoms"}
swc_common = {version = "0.10.16", path = "../../common"}
swc_ecma_ast = {version = "0.46.0", path = "../ast"}
swc_ecma_visit = {version = "0.32.1", path = "../visit"}

[dev-dependencies]
testing = {version = "0.10.5", path = "../../testing"}

[target.'cfg(windows)'.dependencies]
normpath = {version = "0.2", optional = true}
9 changes: 2 additions & 7 deletions ecmascript/loader/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,2 @@
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
pub mod resolve;
pub mod resolvers;
25 changes: 25 additions & 0 deletions ecmascript/loader/src/resolve.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use anyhow::Error;
use std::sync::Arc;
use swc_common::sync::{Send, Sync};
use swc_common::FileName;

pub trait Resolve: Send + Sync {
fn resolve(&self, base: &FileName, module_specifier: &str) -> Result<FileName, Error>;
}

macro_rules! impl_ref {
($R:ident, $T:ty) => {
impl<$R> Resolve for $T
where
R: ?Sized + Resolve,
{
fn resolve(&self, base: &FileName, src: &str) -> Result<FileName, Error> {
(**self).resolve(base, src)
}
}
};
}

impl_ref!(R, &'_ R);
impl_ref!(R, Box<R>);
impl_ref!(R, Arc<R>);
68 changes: 68 additions & 0 deletions ecmascript/loader/src/resolvers/lru.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use crate::resolve::Resolve;
use anyhow::Error;
use lru::LruCache;
use std::sync::Mutex;
use swc_common::FileName;

#[derive(Debug)]
pub struct CachingResolver<R>
where
R: Resolve,
{
cache: Mutex<LruCache<(FileName, String), FileName>>,
inner: R,
}

impl<R> Default for CachingResolver<R>
where
R: Resolve + Default,
{
fn default() -> Self {
Self::new(40, Default::default())
}
}

impl<R> CachingResolver<R>
where
R: Resolve,
{
pub fn new(cap: usize, inner: R) -> Self {
Self {
cache: Mutex::new(LruCache::new(cap)),
inner,
}
}
}

impl<R> Resolve for CachingResolver<R>
where
R: Resolve,
{
fn resolve(&self, base: &FileName, src: &str) -> Result<FileName, Error> {
{
let lock = self.cache.lock();
match lock {
Ok(mut lock) => {
//
if let Some(v) = lock.get(&(base.clone(), src.to_string())) {
return Ok(v.clone());
}
}
Err(_) => {}
}
}

let resolved = self.inner.resolve(base, src)?;
{
let lock = self.cache.lock();
match lock {
Ok(mut lock) => {
lock.put((base.clone(), src.to_string()), resolved.clone());
}
Err(_) => {}
}
}

Ok(resolved)
}
}
6 changes: 6 additions & 0 deletions ecmascript/loader/src/resolvers/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#[cfg(feature = "lru")]
pub mod lru;
#[cfg(feature = "node")]
pub mod node;
#[cfg(feature = "tsc")]
pub mod tsc;
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,16 @@
//!
//! See: https://github.com/goto-bus-stop/node-resolve

use crate::resolve::Resolve;
use anyhow::{bail, Context, Error};
use lru::LruCache;
#[cfg(windows)]
use normpath::BasePath;
// use path_slash::{PathBufExt, PathExt};
use serde::Deserialize;
use std::{
fs::File,
io::BufReader,
path::{Component, Path, PathBuf},
sync::Mutex,
};

use swc_bundler::Resolve;
use swc_common::FileName;

// Run `node -p "require('module').builtinModules"`
Expand Down Expand Up @@ -99,22 +95,16 @@ struct PackageJson {
main: Option<String>,
}

#[derive(Debug, Default)]
pub struct NodeResolver {
cache: Mutex<LruCache<(PathBuf, String), PathBuf>>,
_private: (),
}

static EXTENSIONS: &[&str] = &["ts", "tsx", "js", "jsx", "json", "node"];

impl NodeResolver {
pub fn new() -> Self {
Self {
cache: Mutex::new(LruCache::new(40)),
}
}

fn wrap(&self, base: &PathBuf, target: &str, path: PathBuf) -> Result<FileName, Error> {
fn wrap(&self, path: PathBuf) -> Result<FileName, Error> {
let path = path.canonicalize().context("failed to canonicalize")?;
self.store(base, target, path.clone());
Ok(FileName::Real(path))
}

Expand Down Expand Up @@ -209,16 +199,6 @@ impl NodeResolver {
None => bail!("not found"),
}
}

fn store(&self, base: &PathBuf, target: &str, result: PathBuf) {
let lock = self.cache.lock();
match lock {
Ok(mut lock) => {
lock.put((base.clone(), target.to_string()), result.to_path_buf());
}
Err(_) => {}
}
}
}

impl Resolve for NodeResolver {
Expand All @@ -232,26 +212,14 @@ impl Resolve for NodeResolver {
_ => bail!("node-resolver supports only files"),
};

{
let lock = self.cache.lock();
match lock {
Ok(mut lock) => {
//
if let Some(v) = lock.get(&(base.clone(), target.to_string())) {
return Ok(FileName::Real(v.clone()));
}
}
Err(_) => {}
}
}
let target_path = Path::new(target);

if target_path.is_absolute() {
let path = PathBuf::from(target_path);
return self
.resolve_as_file(&path)
.or_else(|_| self.resolve_as_directory(&path))
.and_then(|p| self.wrap(base, target, p));
.and_then(|p| self.wrap(p));
}

let cwd = &Path::new(".");
Expand All @@ -273,10 +241,10 @@ impl Resolve for NodeResolver {
return self
.resolve_as_file(&path)
.or_else(|_| self.resolve_as_directory(&path))
.and_then(|p| self.wrap(base, target, p));
.and_then(|p| self.wrap(p));
}

self.resolve_node_modules(base_dir, target)
.and_then(|p| self.wrap(base, target, p))
.and_then(|p| self.wrap(p))
}
}

0 comments on commit 4cd4337

Please sign in to comment.