Skip to content

Commit

Permalink
feat: add ViteScannerPlugin (#261)
Browse files Browse the repository at this point in the history
  • Loading branch information
underfin committed Nov 15, 2023
1 parent 629fd35 commit 3d8aff7
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 0 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ thiserror = "1.0.50"
smallvec = "1.11.1"
ariadne = "0.3.0"
async-scoped = { version = "0.7.1" }
regex = "1.10.2"
once_cell = "1.18.0"
16 changes: 16 additions & 0 deletions crates/rolldown_plugin_vite_scanner/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "rolldown_plugin_vite_scanner"
version = "0.1.0"
edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rolldown = { path = "../rolldown" }
rolldown_error = { path = "../rolldown_error" }
async-trait = { workspace = true }
regex = { workspace = true }
once_cell = { workspace = true }
103 changes: 103 additions & 0 deletions crates/rolldown_plugin_vite_scanner/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use once_cell::sync::Lazy;
use regex::Regex;
use rolldown::{
HookLoadArgs, HookLoadReturn, HookResolveIdArgs, HookResolveIdOutput, HookResolveIdReturn,
Plugin, PluginContext,
};
use std::borrow::Cow;

static HTTP_URL_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^(https?:)?\/\/").expect("Init HTTP_URL_REGEX failed"));
static DATA_URL_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^\s*data:").expect("Init DATA_URL_REGEX failed"));
static VIRTUAL_MODULE_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r#"^virtual-module:.*"#).expect("Init VIRTUAL_MODULE_REGEX failed"));
static VITE_SPECIAL_QUERY_REGEX: Lazy<Regex> = Lazy::new(|| {
Regex::new(r"[?&](?:worker|sharedworker|raw|url)\b")
.expect("Init VITE_SPECIAL_QUERY_REGEX failed")
});
static CSS_REGEX: Lazy<Regex> = Lazy::new(|| {
Regex::new(r"\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)")
.expect("Init CSS_REGEX failed")
});
static JSON_AND_WASM_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r"\.(json|json5|wasm)$").expect("Init JSON_AND_WASM_REGEX failed"));
static KNOWN_ASSET_REGEX: Lazy<Regex> = Lazy::new(|| {
Regex::new(r"\.(apng|png|jpe?g|jfif|pjpeg|pjp|gif|svg|ico|webp|avif|mp4|webm|ogg|mp3|wav|flac|aac|opus|woff2?|eot|ttf|otf|webmanifest|pdf|txt)$").expect("Init KNOWN_ASSET_REGEX failed")
});
static HTML_TYPE_REGEX: Lazy<Regex> = Lazy::new(|| {
Regex::new(r"\.(html|vue|svelte|astro|imba)$").expect("Init HTML_TYPE_REGEX failed")
});

#[derive(Debug)]
pub struct ViteScannerPlugin {
pub entries: Vec<String>,
}

impl ViteScannerPlugin {}

#[async_trait::async_trait]
impl Plugin for ViteScannerPlugin {
fn name(&self) -> Cow<'static, str> {
"rolldown_plugin_vite_scanner".into()
}

async fn resolve_id(
&self,
_ctx: &mut PluginContext,
args: &HookResolveIdArgs,
) -> HookResolveIdReturn {
let HookResolveIdArgs { source, .. } = args;

// External http url or data url
if HTTP_URL_REGEX.is_match(source) || DATA_URL_REGEX.is_match(source) {
return Ok(Some(HookResolveIdOutput { id: (*source).to_string(), external: Some(true) }));
}

// local scripts (`<script>` in Svelte and `<script setup>` in Vue)
if VIRTUAL_MODULE_REGEX.is_match(source) {
return Ok(Some(HookResolveIdOutput {
// strip prefix to get valid filesystem path so bundler can resolve imports in the file
id: source.replace("virtual-module:", ""),
external: None,
}));
}

// TODO bare imports: record and externalize

// Externalized file types
// they are done after the bare import resolve because a package name
// may end with these extensions

// css
if CSS_REGEX.is_match(source)
// json & wasm
|| JSON_AND_WASM_REGEX.is_match(source)
// known asset types
|| KNOWN_ASSET_REGEX.is_match(source)
{
return Ok(Some(HookResolveIdOutput {
id: (*source).to_string(),
external: Some(self.entries.contains(&(*source).to_string())),
}));
}

// known vite query types: ?worker, ?raw
if VITE_SPECIAL_QUERY_REGEX.is_match(source) {
return Ok(Some(HookResolveIdOutput { id: (*source).to_string(), external: Some(true) }));
}

Ok(None)
}

async fn load(&self, _ctx: &mut PluginContext, args: &HookLoadArgs) -> HookLoadReturn {
let HookLoadArgs { id } = args;

// extract scripts inside HTML-like files and treat it as a js module
if HTML_TYPE_REGEX.is_match(id) {
// TODO
}

Ok(None)
}
}

0 comments on commit 3d8aff7

Please sign in to comment.