Skip to content

Commit

Permalink
feat: support single library bundle (#1640)
Browse files Browse the repository at this point in the history
* feat: support single bundle

* remove runtime code

* chore: support single bundle library

* fix: import/export minify object pat

---------

Co-authored-by: shulandmimi <sshuang141@163.com>
  • Loading branch information
wre232114 and shulandmimi authored Jul 19, 2024
1 parent 7b4f23c commit b258c41
Show file tree
Hide file tree
Showing 14 changed files with 132 additions and 44 deletions.
5 changes: 5 additions & 0 deletions .changeset/polite-waves-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@farmfe/core": patch
---

Support single bundle library
63 changes: 48 additions & 15 deletions crates/plugin_bundle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
use std::{collections::HashMap, sync::Arc};

use farmfe_core::{
config::TargetEnv,
enhanced_magic_string::bundle::Bundle,
parking_lot::Mutex,
plugin::Plugin,
resource::resource_pot::{ResourcePotMetaData, ResourcePotType},
Expand All @@ -20,6 +22,7 @@ const MODULE_NEED_POLYFILLS: [Polyfill; 3] = [
#[derive(Default)]
pub struct FarmPluginBundle {
runtime_code: Mutex<Arc<String>>,
bundle_map: Mutex<HashMap<String, Bundle>>,
}

impl FarmPluginBundle {
Expand All @@ -45,29 +48,51 @@ impl Plugin for FarmPluginBundle {

resource_pots.sort_by_key(|item| item.id.clone());

for resource_pot in resource_pots {
if matches!(resource_pot.resource_pot_type, ResourcePotType::Runtime) {
let mut shared_bundle = SharedBundle::new(vec![&resource_pot], &module_graph, context)?;
let r = resource_pots.iter().map(|item| &**item).collect::<Vec<_>>();
let mut shared_bundle = SharedBundle::new(r, &module_graph, context)?;

let runtime_resource_pot = resource_pots
.iter()
.find(|item| matches!(item.resource_pot_type, ResourcePotType::Runtime))
.map(|i| i.id.clone());

let polyfill = &mut shared_bundle
.bundle_map
.get_mut(&resource_pot.id)
.unwrap()
.polyfill;
if let Some(runtime_resource_pot_id) = runtime_resource_pot {
let polyfill = &mut shared_bundle
.bundle_map
.get_mut(&runtime_resource_pot_id)
.unwrap()
.polyfill;

MODULE_NEED_POLYFILLS
.iter()
.for_each(|item| polyfill.add(item.clone()));
}

MODULE_NEED_POLYFILLS
.iter()
.for_each(|item| polyfill.add(item.clone()));
shared_bundle.render()?;
shared_bundle.render()?;

let mut defer_minify = vec![];
for resource_pot in resource_pots.iter() {
if matches!(resource_pot.resource_pot_type, ResourcePotType::Runtime)
|| (context.config.output.target_env == TargetEnv::Library
&& resource_pot.resource_pot_type == ResourcePotType::Js)
{
let resource_pot_id = resource_pot.id.clone();

let bundle = shared_bundle.codegen(&resource_pot_id)?;

resource_pot.defer_minify_as_resource_pot();
defer_minify.push(resource_pot_id.clone());

*self.runtime_code.lock() = Arc::new(bundle.to_string());
break;
if matches!(resource_pot.resource_pot_type, ResourcePotType::Runtime) {
*self.runtime_code.lock() = Arc::new(bundle.to_string());
} else {
self.bundle_map.lock().insert(resource_pot_id, bundle);
}
}
}

for resource_pot in resource_pots {
if defer_minify.contains(&resource_pot.id) {
resource_pot.defer_minify_as_resource_pot();
}
}

Expand All @@ -88,6 +113,14 @@ impl Plugin for FarmPluginBundle {
rendered_map_chain: vec![],
custom_data: resource_pot.meta.custom_data.clone(),
}));
} else if let Some(bundle) = self.bundle_map.lock().get(&resource_pot.id) {
return Ok(Some(ResourcePotMetaData {
// TODO
rendered_modules: HashMap::new(),
rendered_content: Arc::new(bundle.to_string()),
rendered_map_chain: vec![],
custom_data: resource_pot.meta.custom_data.clone(),
}));
}

Ok(None)
Expand Down
33 changes: 30 additions & 3 deletions crates/plugin_minify/src/imports_minifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ use farmfe_core::{
plugin::ResolveKind,
swc_common::{Mark, DUMMY_SP},
swc_ecma_ast::{
CallExpr, Callee, ExportNamedSpecifier, ExportSpecifier, Expr, ExprOrSpread, ExprStmt, Id,
Ident, KeyValueProp, Lit, MemberExpr, MemberProp, ModuleDecl, ModuleExportName, ModuleItem,
NamedExport, ObjectLit, Prop, PropName, PropOrSpread, Stmt, Str,
BindingIdent, CallExpr, Callee, ExportNamedSpecifier, ExportSpecifier, Expr, ExprOrSpread,
ExprStmt, Id, Ident, KeyValuePatProp, KeyValueProp, Lit, MemberExpr, MemberProp, ModuleDecl,
ModuleExportName, ModuleItem, NamedExport, ObjectLit, Pat, Prop, PropName, PropOrSpread, Stmt,
Str,
},
};
use farmfe_toolkit::swc_ecma_visit::{VisitMut, VisitMutWith};
Expand Down Expand Up @@ -510,6 +511,32 @@ impl<'a> VisitMut for IdentReplacer {
}
}
}

fn visit_mut_object_pat(&mut self, pat: &mut farmfe_core::swc_ecma_ast::ObjectPat) {
for n in &mut pat.props {
match n {
farmfe_core::swc_ecma_ast::ObjectPatProp::KeyValue(key) => key.value.visit_mut_with(self),
farmfe_core::swc_ecma_ast::ObjectPatProp::Assign(a) => {
if let Some(value) = &mut a.value {
value.visit_mut_with(self);
} else if let Some(replaced) = self.id_to_replace.get(&a.key.id.to_id()) {
*n = farmfe_core::swc_ecma_ast::ObjectPatProp::KeyValue(KeyValuePatProp {
key: PropName::Ident(a.key.id.clone()),
value: Box::new(Pat::Ident(BindingIdent {
id: Ident::new(
replaced.as_str().into(),
DUMMY_SP.apply_mark(a.key.id.span.ctxt().outer()),
),
type_ann: None,
})),
})
}
}
farmfe_core::swc_ecma_ast::ObjectPatProp::Rest(r) => r.visit_mut_with(self),
}
}
}

fn visit_mut_ident(&mut self, n: &mut farmfe_core::swc_ecma_ast::Ident) {
if let Some(replaced) = self.id_to_replace.get(&n.to_id()) {
n.sym = replaced.as_str().into();
Expand Down
15 changes: 11 additions & 4 deletions crates/plugin_minify/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,17 @@ impl Plugin for FarmPluginMinify {
let meta = module.meta.as_script_mut();
let ast = &mut meta.ast;

if let Some(id_to_replace) = id_to_replace.lock().remove(&module.id) {
let mut ident_replacer = IdentReplacer::new(id_to_replace);
ast.visit_mut_with(&mut ident_replacer);
}
let (cm, _) = create_swc_source_map(Source {
path: PathBuf::from(module.id.to_string()),
content: module.content.clone(),
});
try_with(cm, &context.meta.script.globals, || {
if let Some(id_to_replace) = id_to_replace.lock().remove(&module.id) {
let mut ident_replacer = IdentReplacer::new(id_to_replace);
ast.visit_mut_with(&mut ident_replacer);
}
})
.unwrap();
});

// update used exports of the module
Expand Down
11 changes: 6 additions & 5 deletions crates/plugin_runtime/src/handle_entry_resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,11 +351,12 @@ pub fn handle_entry_resources(
r#"{farm_global_this}.{FARM_MODULE_SYSTEM}.setDynamicModuleResourcesMap({dynamic_resources_code});"#,
);

let top_level_await_entry = if context.config.script.native_top_level_await && async_modules.contains(entry) {
"await "
} else {
""
};
let top_level_await_entry =
if context.config.script.native_top_level_await && async_modules.contains(entry) {
"await "
} else {
""
};

// 5. append call entry
let call_entry_code = format!(
Expand Down
12 changes: 11 additions & 1 deletion crates/plugin_runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ impl Plugin for FarmPluginRuntime {
}

fn config(&self, config: &mut Config) -> farmfe_core::error::Result<Option<()>> {
if config.output.target_env == TargetEnv::Library {
return Ok(None);
}

// runtime package entry file
if !config.runtime.path.is_empty() {
config.input.insert(
Expand Down Expand Up @@ -265,7 +269,9 @@ impl Plugin for FarmPluginRuntime {
context: &Arc<CompilationContext>,
_hook_context: &PluginHookContext,
) -> farmfe_core::error::Result<Option<ResourcePotMetaData>> {
if matches!(resource_pot.resource_pot_type, ResourcePotType::Js) {
if context.config.output.target_env != TargetEnv::Library
&& matches!(resource_pot.resource_pot_type, ResourcePotType::Js)
{
let async_modules = self.get_async_modules(context);
let async_modules = async_modules.downcast_ref::<HashSet<ModuleId>>().unwrap();
let module_graph = context.module_graph.read();
Expand Down Expand Up @@ -439,6 +445,10 @@ impl Plugin for FarmPluginRuntime {
param: &mut PluginFinalizeResourcesHookParams,
context: &Arc<CompilationContext>,
) -> farmfe_core::error::Result<Option<()>> {
if context.config.output.target_env == TargetEnv::Library {
return Ok(None);
}

let async_modules = self.get_async_modules(context);
let async_modules = async_modules.downcast_ref::<HashSet<ModuleId>>().unwrap();
handle_entry_resources::handle_entry_resources(param.resources_map, context, async_modules);
Expand Down
2 changes: 1 addition & 1 deletion examples/react-antd/farm.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default defineConfig({
},
presetEnv: false,
sourcemap: true,
persistentCache: true
persistentCache: false,
},
server: {
writeToDisk: false,
Expand Down
2 changes: 1 addition & 1 deletion examples/script-entry/farm.config.cjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const config: UserConfig = {
output: {
path: 'dist/cjs',
entryFilename: '[entryName].cjs',
targetEnv: 'node-legacy',
targetEnv: 'library',
format: 'cjs'
},
lazyCompilation: false,
Expand Down
15 changes: 10 additions & 5 deletions examples/script-entry/farm.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default defineConfig({
output: {
path: 'dist/esm',
entryFilename: '[entryName].mjs',
targetEnv: 'node',
targetEnv: 'library',
format: 'esm'
},
presetEnv: false,
Expand All @@ -24,10 +24,15 @@ export default defineConfig({
runtime: {
isolate: true
},
minify: {
mangle: {
toplevel: true
}
minify: false,
mode: 'development',
partialBundling: {
enforceResources: [
{
name: 'xxx',
test: ['.+']
}
]
},
persistentCache: false,
lazyCompilation: false
Expand Down
2 changes: 1 addition & 1 deletion js-plugins/dts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
"type": "module",
"exports": {
".": {
"default": "./build/index.cjs",
"require": "./build/index.cjs",
"import": "./dist/index.js",
"default": "./build/index.cjs",
"types": "./dist/index.d.ts"
}
},
Expand Down
8 changes: 2 additions & 6 deletions packages/core/src/config/normalize-config/normalize-output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,8 @@ const targetsMap: TargetsMap = {
cssTargets: es2017Browsers,
scriptGenTarget: 'es2017'
},
'browser-esnext': null
};

export const targetEnvMapPlatform: Record<string, string> = {
'lib-node': 'node',
'lib-browser': 'browser'
'browser-esnext': null,
library: null
};

/**
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/config/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ const compilationConfigSchema = z
'browser-legacy',
'browser-esnext',
'browser-es2015',
'browser-es2017'
'browser-es2017',
'library'
])
.optional(),
format: z.enum(['cjs', 'esm']).optional()
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/types/binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ export interface OutputConfig {
| 'browser-legacy'
| 'browser-es2015'
| 'browser-es2017'
| 'browser-esnext';
| 'browser-esnext'
| 'library';
/**
* output module format
*/
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/utils/share.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ export function mapTargetEnvValue(config: Config['config']) {
config.output.targetEnv = 'node';
} else if (FARM_TARGET_BROWSER_ENVS.includes(config.output.targetEnv)) {
config.output.targetEnv = 'browser';
} else {
config.output.targetEnv = 'library';
}
}

Expand Down

0 comments on commit b258c41

Please sign in to comment.