Skip to content

Commit

Permalink
wip: amd dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
nilptr committed Aug 18, 2024
1 parent 0e809ea commit d1d0be1
Show file tree
Hide file tree
Showing 11 changed files with 912 additions and 0 deletions.
12 changes: 12 additions & 0 deletions crates/rspack_core/src/runtime_globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,15 @@ bitflags! {
const RSPACK_UNIQUE_ID = 1 << 64;

const HAS_FETCH_PRIORITY = 1 << 65;

// amd module support
const AMD_DEFINE = 1 << 66;
const AMD_OPTIONS = 1 << 67;

/**
* the uncaught error handler for the webpack runtime
*/
const UNCAUGHT_ERROR_HANDLER = 1 << 68;
}
}

Expand Down Expand Up @@ -293,11 +302,14 @@ impl RuntimeGlobals {
R::GET_CHUNK_UPDATE_CSS_FILENAME => "__webpack_require__.hk",
R::HMR_MODULE_DATA => "__webpack_require__.hmrD",
R::HMR_RUNTIME_STATE_PREFIX => "__webpack_require__.hmrS",
R::AMD_DEFINE => "__webpack_require__.amdD",
R::AMD_OPTIONS => "__webpack_require__.amdO",
R::EXTERNAL_INSTALL_CHUNK => "__webpack_require__.C",
R::GET_FULL_HASH => "__webpack_require__.h",
R::GLOBAL => "__webpack_require__.g",
R::RETURN_EXPORTS_FROM_RUNTIME => "return-exports-from-runtime",
R::INSTANTIATE_WASM => "__webpack_require__.v",
R::UNCAUGHT_ERROR_HANDLER => "__webpack_require__.oe",
R::ASYNC_MODULE => "__webpack_require__.a",
R::BASE_URI => "__webpack_require__.b",
R::STARTUP_ENTRYPOINT => "__webpack_require__.X",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
use bitflags::bitflags;
use rspack_core::{
AsContextDependency, AsModuleDependency, Dependency, DependencyCategory, DependencyId,
DependencyTemplate, DependencyType, RuntimeGlobals, TemplateContext, TemplateReplaceSource,
};
use rspack_util::atom::Atom;

use super::local_module::LocalModule;

bitflags! {
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
struct Branch: u8 {
const L = 1 << 0;
const A = 1 << 1;
const O = 1 << 2;
const F = 1 << 3;
}
}

impl Branch {
pub fn get_requests(&self) -> RuntimeGlobals {
match *self {
f if f == Branch::F => {
RuntimeGlobals::REQUIRE | RuntimeGlobals::EXPORTS | RuntimeGlobals::MODULE
}
o if o == Branch::O => RuntimeGlobals::MODULE,
of if of == (Branch::O | Branch::F) => {
RuntimeGlobals::REQUIRE | RuntimeGlobals::EXPORTS | RuntimeGlobals::MODULE
}
af if af == (Branch::A | Branch::F) => RuntimeGlobals::EXPORTS | RuntimeGlobals::MODULE,
ao if ao == (Branch::A | Branch::O) => RuntimeGlobals::MODULE,
aof if aof == (Branch::A | Branch::O | Branch::F) => {
RuntimeGlobals::EXPORTS | RuntimeGlobals::MODULE
}
lf if lf == (Branch::L | Branch::F) => RuntimeGlobals::REQUIRE | RuntimeGlobals::MODULE,
lo if lo == (Branch::L | Branch::O) => RuntimeGlobals::empty(),
lof if lof == (Branch::L | Branch::O | Branch::F) => {
RuntimeGlobals::REQUIRE | RuntimeGlobals::MODULE
}
laf if laf == (Branch::L | Branch::A | Branch::F) => RuntimeGlobals::empty(),

Check warning on line 40 in crates/rspack_plugin_javascript/src/dependency/amd/amd_define_dependency.rs

View workflow job for this annotation

GitHub Actions / Spell check

"laf" should be "kaf" or "kaph" or "lac" or "lad" or "lag" or "laugh" or "leaf" or "loaf".

Check warning on line 40 in crates/rspack_plugin_javascript/src/dependency/amd/amd_define_dependency.rs

View workflow job for this annotation

GitHub Actions / Spell check

"laf" should be "kaf" or "kaph" or "lac" or "lad" or "lag" or "laugh" or "leaf" or "loaf".
lao if lao == (Branch::L | Branch::A | Branch::O) => RuntimeGlobals::empty(),
laof if laof == (Branch::L | Branch::A | Branch::O | Branch::F) => RuntimeGlobals::empty(),
_ => RuntimeGlobals::empty(),
}
}

pub fn get_definition(&self, local_module_var: &Option<String>) -> String {
let name = match local_module_var {
Some(name) => &name,
None => "XXX",
};
match *self {
f if f == Branch::F => "var __WEBPACK_AMD_DEFINE_RESULT__;".to_string(),
o if o == Branch::O => "".to_string(),
of if of == (Branch::O | Branch::F) => {
"var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;".to_string()
}
af if af == (Branch::A | Branch::F) => {
"var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;".to_string()
}
ao if ao == (Branch::A | Branch::O) => "".to_string(),
aof if aof == (Branch::A | Branch::O | Branch::F) => "var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;".to_string(),
lf if lf == (Branch::L | Branch::F) => {
format!("var {}, {}module;", name, name)
},
lo if lo == (Branch::L | Branch::O) => {
format!("var {};", name)
},
lof if lof == (Branch::L | Branch::O | Branch::F) => {
format!("var {}, {}factory, {}module;", name, name, name)
},
laf if laf == (Branch::L | Branch::A | Branch::F) => {

Check warning on line 72 in crates/rspack_plugin_javascript/src/dependency/amd/amd_define_dependency.rs

View workflow job for this annotation

GitHub Actions / Spell check

"laf" should be "kaf" or "kaph" or "lac" or "lad" or "lag" or "laugh" or "leaf" or "loaf".

Check warning on line 72 in crates/rspack_plugin_javascript/src/dependency/amd/amd_define_dependency.rs

View workflow job for this annotation

GitHub Actions / Spell check

"laf" should be "kaf" or "kaph" or "lac" or "lad" or "lag" or "laugh" or "leaf" or "loaf".
format!("var __WEBPACK_AMD_DEFINE_ARRAY__, {}, {}exports;", name, name)
},
lao if lao == (Branch::L | Branch::A | Branch::O)=> {
format!("var {};", name)
},
laof if laof == (Branch::L | Branch::A | Branch::O | Branch::F) => {
format!("var {}array, {}factory, {}exports, {};", name, name, name, name)
},
_ => "".to_string(),
}
}

pub fn get_content(
&self,
local_module_var: &Option<String>,
named_module: &Option<Atom>,
) -> String {
let local_module_var = match local_module_var {
Some(name) => &name,
None => "XXX",
};
let named_module = match named_module {
Some(name) => &name,
None => "YYY",
};
match *self {
f if f == Branch::F => {
format!(
"!(__WEBPACK_AMD_DEFINE_RESULT__ = (#).call(exports, {}, exports, module),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))",
RuntimeGlobals::REQUIRE.name()
)
}
o if o == Branch::O => "!(module.exports = #)".to_string(),
of if of == (Branch::O | Branch::F) => {
format!(
"!(__WEBPACK_AMD_DEFINE_FACTORY__ = (#),
__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
(__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, {}, exports, module)) :
__WEBPACK_AMD_DEFINE_FACTORY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))",
RuntimeGlobals::REQUIRE.name()
)
}
af if af == (Branch::A | Branch::F) => "!(__WEBPACK_AMD_DEFINE_ARRAY__ = #, __WEBPACK_AMD_DEFINE_RESULT__ = (#).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))".to_string(),
ao if ao == (Branch::A | Branch::O) => "!(#, module.exports = #)".to_string(),
aof if aof == (Branch::A | Branch::O | Branch::F) => {
"!(__WEBPACK_AMD_DEFINE_ARRAY__ = #, __WEBPACK_AMD_DEFINE_FACTORY__ = (#),
__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))".to_string()
}
lf if lf == (Branch::L | Branch::F) => {
format!(
"!({}module = {{ id: {}, exports: {{}}, loaded: false }}, {} = (#).call({}module.exports, {}, {}module.exports, {}module), {}module.loaded = true, {} === undefined && ({} = {}module.exports))",
local_module_var,
named_module,
local_module_var,
local_module_var,
RuntimeGlobals::REQUIRE.name(),
local_module_var,
local_module_var,
local_module_var,
local_module_var,
local_module_var,
local_module_var
)
}
lo if lo == (Branch::L | Branch::O) => format!("!({} = #)", local_module_var),
lof if lof == (Branch::L | Branch::O | Branch::F) => {
format!(
"!({}factory = (#), (typeof {}factory === 'function' ? (({}module = {{ id: {}, exports: {{}}, loaded: false }}), ({} = {}factory.call({}module.exports, {}, {}module.exports, {}module)), ({}module.loaded = true), {} === undefined && ({} = {}module.exports)) : {} = {}factory))",
local_module_var,
local_module_var,
local_module_var,
named_module,
local_module_var,
local_module_var,
local_module_var,
RuntimeGlobals::REQUIRE.name(),
local_module_var,
local_module_var,
local_module_var,
local_module_var,
local_module_var,
local_module_var,
local_module_var,
local_module_var,
)
}
laf if laf == (Branch::L | Branch::A | Branch::F) => format!("!(__WEBPACK_AMD_DEFINE_ARRAY__ = #, {} = (#).apply({}exports = {{}}, __WEBPACK_AMD_DEFINE_ARRAY__), {} === undefined && ({} = {}exports))", local_module_var, local_module_var, local_module_var, local_module_var, local_module_var),

Check warning on line 164 in crates/rspack_plugin_javascript/src/dependency/amd/amd_define_dependency.rs

View workflow job for this annotation

GitHub Actions / Spell check

"laf" should be "kaf" or "kaph" or "lac" or "lad" or "lag" or "laugh" or "leaf" or "loaf".

Check warning on line 164 in crates/rspack_plugin_javascript/src/dependency/amd/amd_define_dependency.rs

View workflow job for this annotation

GitHub Actions / Spell check

"laf" should be "kaf" or "kaph" or "lac" or "lad" or "lag" or "laugh" or "leaf" or "loaf".
lao if lao == (Branch::L | Branch::A | Branch::O) => format!("!(#, {} = #)", local_module_var),
laof if laof == (Branch::L | Branch::A | Branch::O | Branch::F) => format!(
"!({}array = #, {}factory = (#),
(typeof {}factory === 'function' ?
(({} = {}factory.apply({}exports = {{}}, {}array)), {} === undefined && ({} = {}exports)) :
({} = {}factory)
))",
local_module_var,
local_module_var,
local_module_var,
local_module_var,
local_module_var,
local_module_var,
local_module_var,
local_module_var,
local_module_var,
local_module_var,
local_module_var,
local_module_var,
),
_ => "".to_string(),
}
}
}

#[derive(Debug, Clone)]
pub struct AmdDefineDependency {
id: DependencyId,
range: (u32, u32),
array_range: Option<(u32, u32)>,
function_range: Option<(u32, u32)>,
object_range: Option<(u32, u32)>,
named_module: Option<Atom>,
local_module: Option<LocalModule>,
}

impl AmdDefineDependency {
pub fn new(
range: (u32, u32),
array_range: Option<(u32, u32)>,
function_range: Option<(u32, u32)>,
object_range: Option<(u32, u32)>,
named_module: Option<Atom>,
) -> Self {
Self {
id: DependencyId::new(),
range,
array_range,
function_range,
object_range,
named_module,
local_module: None,
}
}
}

impl Dependency for AmdDefineDependency {
fn id(&self) -> &DependencyId {
&self.id
}

fn category(&self) -> &DependencyCategory {
&DependencyCategory::Amd
}

fn dependency_type(&self) -> &DependencyType {
&DependencyType::AmdDefine
}
}

impl AmdDefineDependency {
fn local_module_var(&self) -> Option<String> {
self.local_module.as_ref().and_then(|m| {
if m.is_used() {
Some(m.variable_name())
} else {
None
}
})
}

fn branch(&self) -> Branch {
let mut ret = Branch::empty();
if self.local_module.as_ref().is_some_and(|m| m.is_used()) {
ret |= Branch::L;
}
if self.array_range.is_some() {
ret |= Branch::A;
}
if self.object_range.is_some() {
ret |= Branch::O;
}
if self.function_range.is_some() {
ret |= Branch::F;
}
ret
}
}

impl DependencyTemplate for AmdDefineDependency {
fn apply(
&self,
source: &mut TemplateReplaceSource,
code_generatable_context: &mut TemplateContext,
) {
let branch = self.branch();
code_generatable_context
.runtime_requirements
.insert(branch.get_requests());

// TODO: localModuleVar.replace(/\$/g, "$$$$")
let local_module_var = self.local_module_var();

let text = branch.get_content(&local_module_var, &self.named_module);
let definition = branch.get_definition(&local_module_var);

let mut texts = text.split('#');

if definition.len() > 0 {
source.insert(0, &definition, None);
}

let mut current = self.range.0;
if let Some(array_range) = self.array_range {
source.replace(current, array_range.0 - 1, texts.next().unwrap_or(""), None);
current = array_range.1;
}

if let Some(object_range) = self.object_range {
source.replace(
current,
object_range.0 - 1,
texts.next().unwrap_or(""),
None,
);
current = object_range.1;
} else if let Some(function_range) = self.function_range {
source.replace(
current,
function_range.0 - 1,
texts.next().unwrap_or(""),
None,
);
current = function_range.1;
}

source.replace(current, self.range.1 - 1, texts.next().unwrap_or(""), None);

if texts.next().is_some() {
panic!("Implementation error");
}
}

fn dependency_id(&self) -> Option<DependencyId> {
Some(self.id)
}
}

impl AsModuleDependency for AmdDefineDependency {}

impl AsContextDependency for AmdDefineDependency {}
Loading

0 comments on commit d1d0be1

Please sign in to comment.