diff --git a/.changeset/thick-pandas-listen.md b/.changeset/thick-pandas-listen.md new file mode 100644 index 000000000..b2386c37e --- /dev/null +++ b/.changeset/thick-pandas-listen.md @@ -0,0 +1,5 @@ +--- +"@farmfe/core": patch +--- + +import.meta.url and require compatible esm and cjs diff --git a/crates/compiler/tests/bundle.rs b/crates/compiler/tests/bundle.rs new file mode 100644 index 000000000..43cf9f648 --- /dev/null +++ b/crates/compiler/tests/bundle.rs @@ -0,0 +1,84 @@ +use std::{collections::HashMap, path::PathBuf}; + +use farmfe_core::config::{bool_or_obj::BoolOrObj, config_regex::ConfigRegex, Mode, TargetEnv}; +mod common; +use crate::common::{ + assert_compiler_result_with_config, create_compiler_with_args, AssertCompilerResultConfig, +}; + +#[allow(dead_code)] +#[cfg(test)] +fn test(file: String, crate_path: String) { + use common::get_config_field; + use farmfe_core::config::partial_bundling::PartialBundlingEnforceResourceConfig; + + use crate::common::try_read_config_from_json; + + let file_path_buf = PathBuf::from(file.clone()); + let create_path_buf = PathBuf::from(crate_path); + let cwd = file_path_buf.parent().unwrap(); + println!("testing test case: {:?}", cwd); + + let entry_name = "index".to_string(); + + let config_entry = cwd.to_path_buf().join("config.json"); + let runtime_entry = cwd.to_path_buf().join("runtime.ts"); + + let config_from_file = try_read_config_from_json(config_entry); + + let compiler = + create_compiler_with_args(cwd.to_path_buf(), create_path_buf, |mut config, plugins| { + config.mode = Mode::Production; + + if runtime_entry.is_file() { + let runtime_entry = runtime_entry.to_string_lossy().to_string(); + config.runtime.path = runtime_entry; + } + + config.input = HashMap::from_iter(vec![(entry_name.clone(), file)]); + + config.minify = Box::new(BoolOrObj::Bool(false)); + config.tree_shaking = Box::new(BoolOrObj::Bool(false)); + + config.external = vec![ConfigRegex::new("(^node:.*)"), ConfigRegex::new("^fs$")]; + config.output.target_env = TargetEnv::Node; + // config.output.format = ModuleFormat::CommonJs; + + // TODO: multiple bundle + config.partial_bundling.enforce_resources = vec![PartialBundlingEnforceResourceConfig { + test: vec![ConfigRegex::new(".+")], + name: "index".to_string(), + }]; + + if let Some(config_from_file) = config_from_file { + if let Some(mode) = get_config_field(&config_from_file, &["mode"]) { + config.mode = mode; + } + + if let Some(format) = get_config_field(&config_from_file, &["output", "format"]) { + config.output.format = format; + } + + if let Some(target_env) = get_config_field(&config_from_file, &["output", "targetEnv"]) { + config.output.target_env = target_env; + } + } + + (config, plugins) + }); + + compiler.compile().unwrap(); + + assert_compiler_result_with_config( + &compiler, + AssertCompilerResultConfig { + entry_name: Some(entry_name), + ignore_emitted_field: false, + ..Default::default() + }, + ); +} + +farmfe_testing::testing! {"tests/fixtures/bundle/library/**/index.ts", test} +// farmfe_testing::testing! {"tests/fixtures/runtime/bundle/cjs/export/entryExportStar/**/index.ts", test} +// farmfe_testing::testing! {"tests/fixtures/runtime/bundle/external/import/namespace/**/index.ts", test} diff --git a/crates/compiler/tests/fixtures/bundle/library/hybrid/noexport/config.json b/crates/compiler/tests/fixtures/bundle/library/hybrid/noexport/config.json new file mode 100644 index 000000000..eb309261d --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/hybrid/noexport/config.json @@ -0,0 +1,6 @@ +{ + "output": { + "targetEnv": "library-node", + "format": "esm" + } +} \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/hybrid/noexport/index.ts b/crates/compiler/tests/fixtures/bundle/library/hybrid/noexport/index.ts new file mode 100644 index 000000000..7979f5b77 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/hybrid/noexport/index.ts @@ -0,0 +1,4 @@ +import fs from 'node:fs'; +const os = require('node:os'); + +console.log(fs.read, os.cpus); diff --git a/crates/compiler/tests/fixtures/bundle/library/hybrid/noexport/output.js b/crates/compiler/tests/fixtures/bundle/library/hybrid/noexport/output.js new file mode 100644 index 000000000..a69269d0f --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/hybrid/noexport/output.js @@ -0,0 +1,69 @@ +//index.js: + import __farmNodeModule from 'module'; +globalThis.nodeRequire = __farmNodeModule.createRequire(import.meta.url);function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +}function _export_star(from, to) { + Object.keys(from).forEach(function(k) { + if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) { + Object.defineProperty(to, k, { + enumerable: true, + get: function() { + return from[k]; + } + }); + } + }); + return from; +}function _interop_require_wildcard(obj, nodeInterop) { + if (!nodeInterop && obj && obj.__esModule) return obj; + if (obj === null || typeof obj !== "object" && typeof obj !== "function") return { + default: obj + }; + var cache = _getRequireWildcardCache(nodeInterop); + if (cache && cache.has(obj)) return cache.get(obj); + var newObj = { + __proto__: null + }; + var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; + for(var key in obj){ + if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { + var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; + if (desc && (desc.get || desc.set)) Object.defineProperty(newObj, key, desc); + else newObj[key] = obj[key]; + } + } + newObj.default = obj; + if (cache) cache.set(obj, newObj); + return newObj; +}function _getRequireWildcardCache(nodeInterop) { + if (typeof WeakMap !== "function") return null; + var cacheBabelInterop = new WeakMap(); + var cacheNodeInterop = new WeakMap(); + return (_getRequireWildcardCache = function(nodeInterop) { + return nodeInterop ? cacheNodeInterop : cacheBabelInterop; + })(nodeInterop); +}function __commonJs(mod) { + var module; + return () => { + if (module) { + return module.exports; + } + module = { + exports: {}, + }; + if(typeof mod === "function") { + mod(module, module.exports); + }else { + mod[Object.keys(mod)[0]](module, module.exports); + } + return module.exports; + }; +}import fs from "node:fs"; +var index_cjs = __commonJs((module, exports)=>{ + "use strict"; + const os = globalThis.nodeRequire('node:os'); + console.log(fs.read, os.cpus); +}); +index_cjs(); diff --git a/crates/compiler/tests/fixtures/bundle/library/hybrid/noexport/runtime.ts b/crates/compiler/tests/fixtures/bundle/library/hybrid/noexport/runtime.ts new file mode 100644 index 000000000..0124c2287 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/hybrid/noexport/runtime.ts @@ -0,0 +1 @@ +console.log('runtime'); \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/hybrid/normal/config.json b/crates/compiler/tests/fixtures/bundle/library/hybrid/normal/config.json new file mode 100644 index 000000000..eb309261d --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/hybrid/normal/config.json @@ -0,0 +1,6 @@ +{ + "output": { + "targetEnv": "library-node", + "format": "esm" + } +} \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/hybrid/normal/index.ts b/crates/compiler/tests/fixtures/bundle/library/hybrid/normal/index.ts new file mode 100644 index 000000000..1119c0b5c --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/hybrid/normal/index.ts @@ -0,0 +1,13 @@ +import fs from 'node:fs'; +const os = require('node:os'); + +console.log(fs.read, os.cpus); + + +export default { + read: fs.read, + c: 1, +}; + +export const foo = 'foo'; +export const bar = 'bar'; \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/hybrid/normal/output.js b/crates/compiler/tests/fixtures/bundle/library/hybrid/normal/output.js new file mode 100644 index 000000000..099beadf4 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/hybrid/normal/output.js @@ -0,0 +1,97 @@ +//index.js: + import __farmNodeModule from 'module'; +globalThis.nodeRequire = __farmNodeModule.createRequire(import.meta.url);function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +}function _export_star(from, to) { + Object.keys(from).forEach(function(k) { + if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) { + Object.defineProperty(to, k, { + enumerable: true, + get: function() { + return from[k]; + } + }); + } + }); + return from; +}function _interop_require_wildcard(obj, nodeInterop) { + if (!nodeInterop && obj && obj.__esModule) return obj; + if (obj === null || typeof obj !== "object" && typeof obj !== "function") return { + default: obj + }; + var cache = _getRequireWildcardCache(nodeInterop); + if (cache && cache.has(obj)) return cache.get(obj); + var newObj = { + __proto__: null + }; + var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; + for(var key in obj){ + if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { + var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; + if (desc && (desc.get || desc.set)) Object.defineProperty(newObj, key, desc); + else newObj[key] = obj[key]; + } + } + newObj.default = obj; + if (cache) cache.set(obj, newObj); + return newObj; +}function _getRequireWildcardCache(nodeInterop) { + if (typeof WeakMap !== "function") return null; + var cacheBabelInterop = new WeakMap(); + var cacheNodeInterop = new WeakMap(); + return (_getRequireWildcardCache = function(nodeInterop) { + return nodeInterop ? cacheNodeInterop : cacheBabelInterop; + })(nodeInterop); +}function __commonJs(mod) { + var module; + return () => { + if (module) { + return module.exports; + } + module = { + exports: {}, + }; + if(typeof mod === "function") { + mod(module, module.exports); + }else { + mod[Object.keys(mod)[0]](module, module.exports); + } + return module.exports; + }; +}import fs from "node:fs"; +var index_cjs = __commonJs((module, exports)=>{ + "use strict"; + Object.defineProperty(exports, "__esModule", { + value: true + }); + function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); + } + _export(exports, { + bar: function() { + return bar; + }, + index_default: function() { + return _default; + }, + foo: function() { + return foo; + } + }); + const os = globalThis.nodeRequire('node:os'); + console.log(fs.read, os.cpus); + var _default = { + read: fs.read, + c: 1 + }; + const foo = 'foo'; + const bar = 'bar'; +}); +var index_default = _interop_require_default(index_cjs()).index_default, bar = index_cjs()["bar"], foo = index_cjs()["foo"]; +export { bar, foo }; +export default index_default; diff --git a/crates/compiler/tests/fixtures/bundle/library/hybrid/normal/runtime.ts b/crates/compiler/tests/fixtures/bundle/library/hybrid/normal/runtime.ts new file mode 100644 index 000000000..0124c2287 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/hybrid/normal/runtime.ts @@ -0,0 +1 @@ +console.log('runtime'); \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/default/config.json b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/default/config.json new file mode 100644 index 000000000..eb309261d --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/default/config.json @@ -0,0 +1,6 @@ +{ + "output": { + "targetEnv": "library-node", + "format": "esm" + } +} \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/default/foo.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/default/foo.ts new file mode 100644 index 000000000..5a549c58c --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/default/foo.ts @@ -0,0 +1 @@ +export default 'foo'; \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/default/index.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/default/index.ts new file mode 100644 index 000000000..1d4a90633 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/default/index.ts @@ -0,0 +1 @@ +export { default } from './foo.ts'; \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/default/output.js b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/default/output.js new file mode 100644 index 000000000..9cf3a7632 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/default/output.js @@ -0,0 +1,48 @@ +//index.js: + function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +}function _export_star(from, to) { + Object.keys(from).forEach(function(k) { + if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) { + Object.defineProperty(to, k, { + enumerable: true, + get: function() { + return from[k]; + } + }); + } + }); + return from; +}function _interop_require_wildcard(obj, nodeInterop) { + if (!nodeInterop && obj && obj.__esModule) return obj; + if (obj === null || typeof obj !== "object" && typeof obj !== "function") return { + default: obj + }; + var cache = _getRequireWildcardCache(nodeInterop); + if (cache && cache.has(obj)) return cache.get(obj); + var newObj = { + __proto__: null + }; + var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; + for(var key in obj){ + if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { + var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; + if (desc && (desc.get || desc.set)) Object.defineProperty(newObj, key, desc); + else newObj[key] = obj[key]; + } + } + newObj.default = obj; + if (cache) cache.set(obj, newObj); + return newObj; +}function _getRequireWildcardCache(nodeInterop) { + if (typeof WeakMap !== "function") return null; + var cacheBabelInterop = new WeakMap(); + var cacheNodeInterop = new WeakMap(); + return (_getRequireWildcardCache = function(nodeInterop) { + return nodeInterop ? cacheNodeInterop : cacheBabelInterop; + })(nodeInterop); +}var foo_default = 'foo'; + +export { foo_default as default }; diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/default/runtime.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/default/runtime.ts new file mode 100644 index 000000000..0124c2287 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/default/runtime.ts @@ -0,0 +1 @@ +console.log('runtime'); \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/named/config.json b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/named/config.json new file mode 100644 index 000000000..eb309261d --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/named/config.json @@ -0,0 +1,6 @@ +{ + "output": { + "targetEnv": "library-node", + "format": "esm" + } +} \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/named/foo.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/named/foo.ts new file mode 100644 index 000000000..be46064a3 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/named/foo.ts @@ -0,0 +1,2 @@ +export const foo = 'foo'; +export const bar = 'bar'; \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/named/index.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/named/index.ts new file mode 100644 index 000000000..c0466d3c5 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/named/index.ts @@ -0,0 +1 @@ +export { foo, bar } from './foo.ts'; \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/named/output.js b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/named/output.js new file mode 100644 index 000000000..c4feebfd5 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/named/output.js @@ -0,0 +1,49 @@ +//index.js: + function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +}function _export_star(from, to) { + Object.keys(from).forEach(function(k) { + if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) { + Object.defineProperty(to, k, { + enumerable: true, + get: function() { + return from[k]; + } + }); + } + }); + return from; +}function _interop_require_wildcard(obj, nodeInterop) { + if (!nodeInterop && obj && obj.__esModule) return obj; + if (obj === null || typeof obj !== "object" && typeof obj !== "function") return { + default: obj + }; + var cache = _getRequireWildcardCache(nodeInterop); + if (cache && cache.has(obj)) return cache.get(obj); + var newObj = { + __proto__: null + }; + var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; + for(var key in obj){ + if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { + var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; + if (desc && (desc.get || desc.set)) Object.defineProperty(newObj, key, desc); + else newObj[key] = obj[key]; + } + } + newObj.default = obj; + if (cache) cache.set(obj, newObj); + return newObj; +}function _getRequireWildcardCache(nodeInterop) { + if (typeof WeakMap !== "function") return null; + var cacheBabelInterop = new WeakMap(); + var cacheNodeInterop = new WeakMap(); + return (_getRequireWildcardCache = function(nodeInterop) { + return nodeInterop ? cacheNodeInterop : cacheBabelInterop; + })(nodeInterop); +}const foo = 'foo'; +const bar = 'bar'; + +export { bar, foo }; diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/named/runtime.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/named/runtime.ts new file mode 100644 index 000000000..0124c2287 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/named/runtime.ts @@ -0,0 +1 @@ +console.log('runtime'); \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/namespace/config.json b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/namespace/config.json new file mode 100644 index 000000000..eb309261d --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/namespace/config.json @@ -0,0 +1,6 @@ +{ + "output": { + "targetEnv": "library-node", + "format": "esm" + } +} \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/namespace/foo.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/namespace/foo.ts new file mode 100644 index 000000000..cb497a023 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/namespace/foo.ts @@ -0,0 +1,5 @@ +export default 'foo'; + +export const foo = 'foo'; + +export const bar = 'bar'; \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/namespace/index.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/namespace/index.ts new file mode 100644 index 000000000..71ea64596 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/namespace/index.ts @@ -0,0 +1 @@ +export * as ns from './foo'; \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/namespace/output.js b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/namespace/output.js new file mode 100644 index 000000000..f6110a6df --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/namespace/output.js @@ -0,0 +1,56 @@ +//index.js: + function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +}function _export_star(from, to) { + Object.keys(from).forEach(function(k) { + if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) { + Object.defineProperty(to, k, { + enumerable: true, + get: function() { + return from[k]; + } + }); + } + }); + return from; +}function _interop_require_wildcard(obj, nodeInterop) { + if (!nodeInterop && obj && obj.__esModule) return obj; + if (obj === null || typeof obj !== "object" && typeof obj !== "function") return { + default: obj + }; + var cache = _getRequireWildcardCache(nodeInterop); + if (cache && cache.has(obj)) return cache.get(obj); + var newObj = { + __proto__: null + }; + var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; + for(var key in obj){ + if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { + var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; + if (desc && (desc.get || desc.set)) Object.defineProperty(newObj, key, desc); + else newObj[key] = obj[key]; + } + } + newObj.default = obj; + if (cache) cache.set(obj, newObj); + return newObj; +}function _getRequireWildcardCache(nodeInterop) { + if (typeof WeakMap !== "function") return null; + var cacheBabelInterop = new WeakMap(); + var cacheNodeInterop = new WeakMap(); + return (_getRequireWildcardCache = function(nodeInterop) { + return nodeInterop ? cacheNodeInterop : cacheBabelInterop; + })(nodeInterop); +}var foo_default = 'foo'; +const foo = 'foo'; +const bar = 'bar'; +var foo_ns = { + bar: bar, + foo: foo, + "default": foo_default, + __esModule: true +}; + +export { foo_ns as ns }; diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/namespace/runtime.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/namespace/runtime.ts new file mode 100644 index 000000000..0124c2287 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/namespace/runtime.ts @@ -0,0 +1 @@ +console.log('runtime'); \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/star/config.json b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/star/config.json new file mode 100644 index 000000000..eb309261d --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/star/config.json @@ -0,0 +1,6 @@ +{ + "output": { + "targetEnv": "library-node", + "format": "esm" + } +} \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/star/foo.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/star/foo.ts new file mode 100644 index 000000000..cb497a023 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/star/foo.ts @@ -0,0 +1,5 @@ +export default 'foo'; + +export const foo = 'foo'; + +export const bar = 'bar'; \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/star/index.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/star/index.ts new file mode 100644 index 000000000..1cc5a0795 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/star/index.ts @@ -0,0 +1 @@ +export * from './foo'; \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/star/output.js b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/star/output.js new file mode 100644 index 000000000..d33ca68f7 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/star/output.js @@ -0,0 +1,57 @@ +//index.js: + function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +}function _export_star(from, to) { + Object.keys(from).forEach(function(k) { + if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) { + Object.defineProperty(to, k, { + enumerable: true, + get: function() { + return from[k]; + } + }); + } + }); + return from; +}function _interop_require_wildcard(obj, nodeInterop) { + if (!nodeInterop && obj && obj.__esModule) return obj; + if (obj === null || typeof obj !== "object" && typeof obj !== "function") return { + default: obj + }; + var cache = _getRequireWildcardCache(nodeInterop); + if (cache && cache.has(obj)) return cache.get(obj); + var newObj = { + __proto__: null + }; + var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; + for(var key in obj){ + if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { + var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; + if (desc && (desc.get || desc.set)) Object.defineProperty(newObj, key, desc); + else newObj[key] = obj[key]; + } + } + newObj.default = obj; + if (cache) cache.set(obj, newObj); + return newObj; +}function _getRequireWildcardCache(nodeInterop) { + if (typeof WeakMap !== "function") return null; + var cacheBabelInterop = new WeakMap(); + var cacheNodeInterop = new WeakMap(); + return (_getRequireWildcardCache = function(nodeInterop) { + return nodeInterop ? cacheNodeInterop : cacheBabelInterop; + })(nodeInterop); +}var foo_default = 'foo'; +const foo = 'foo'; +const bar = 'bar'; +var foo_ns = { + bar: bar, + foo: foo, + "default": foo_default, + __esModule: true +}; + +export { bar, foo }; +export default foo_default; diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/esm/star/runtime.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/star/runtime.ts new file mode 100644 index 000000000..0124c2287 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/esm/star/runtime.ts @@ -0,0 +1 @@ +console.log('runtime'); \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/default/config.json b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/default/config.json new file mode 100644 index 000000000..eb309261d --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/default/config.json @@ -0,0 +1,6 @@ +{ + "output": { + "targetEnv": "library-node", + "format": "esm" + } +} \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/default/foo.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/default/foo.ts new file mode 100644 index 000000000..8af2ad9ac --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/default/foo.ts @@ -0,0 +1,2 @@ +module.exports.cjs = true; +export default 'foo'; \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/default/index.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/default/index.ts new file mode 100644 index 000000000..2f816c828 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/default/index.ts @@ -0,0 +1 @@ +export { default } from './foo.ts'; diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/default/output.js b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/default/output.js new file mode 100644 index 000000000..e29a879d7 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/default/output.js @@ -0,0 +1,78 @@ +//index.js: + function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +}function _export_star(from, to) { + Object.keys(from).forEach(function(k) { + if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) { + Object.defineProperty(to, k, { + enumerable: true, + get: function() { + return from[k]; + } + }); + } + }); + return from; +}function _interop_require_wildcard(obj, nodeInterop) { + if (!nodeInterop && obj && obj.__esModule) return obj; + if (obj === null || typeof obj !== "object" && typeof obj !== "function") return { + default: obj + }; + var cache = _getRequireWildcardCache(nodeInterop); + if (cache && cache.has(obj)) return cache.get(obj); + var newObj = { + __proto__: null + }; + var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; + for(var key in obj){ + if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { + var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; + if (desc && (desc.get || desc.set)) Object.defineProperty(newObj, key, desc); + else newObj[key] = obj[key]; + } + } + newObj.default = obj; + if (cache) cache.set(obj, newObj); + return newObj; +}function _getRequireWildcardCache(nodeInterop) { + if (typeof WeakMap !== "function") return null; + var cacheBabelInterop = new WeakMap(); + var cacheNodeInterop = new WeakMap(); + return (_getRequireWildcardCache = function(nodeInterop) { + return nodeInterop ? cacheNodeInterop : cacheBabelInterop; + })(nodeInterop); +}function __commonJs(mod) { + var module; + return () => { + if (module) { + return module.exports; + } + module = { + exports: {}, + }; + if(typeof mod === "function") { + mod(module, module.exports); + }else { + mod[Object.keys(mod)[0]](module, module.exports); + } + return module.exports; + }; +}var foo_cjs = __commonJs((module, exports)=>{ + "use strict"; + Object.defineProperty(exports, "__esModule", { + value: true + }); + Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return _default; + } + }); + module.exports.cjs = true; + var _default = 'foo'; +}); +var foo_default = foo_cjs()["default"]; + +export { foo_default as default }; diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/default/runtime.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/default/runtime.ts new file mode 100644 index 000000000..0124c2287 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/default/runtime.ts @@ -0,0 +1 @@ +console.log('runtime'); \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/named/config.json b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/named/config.json new file mode 100644 index 000000000..eb309261d --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/named/config.json @@ -0,0 +1,6 @@ +{ + "output": { + "targetEnv": "library-node", + "format": "esm" + } +} \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/named/foo.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/named/foo.ts new file mode 100644 index 000000000..34c6b8f88 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/named/foo.ts @@ -0,0 +1,4 @@ +export const foo = 'foo'; +export const bar = 'bar'; + +module.exports.cjs = true; diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/named/index.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/named/index.ts new file mode 100644 index 000000000..d6be28456 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/named/index.ts @@ -0,0 +1 @@ +export { foo, bar } from './foo.ts'; diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/named/output.js b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/named/output.js new file mode 100644 index 000000000..f1996fe32 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/named/output.js @@ -0,0 +1,87 @@ +//index.js: + function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +}function _export_star(from, to) { + Object.keys(from).forEach(function(k) { + if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) { + Object.defineProperty(to, k, { + enumerable: true, + get: function() { + return from[k]; + } + }); + } + }); + return from; +}function _interop_require_wildcard(obj, nodeInterop) { + if (!nodeInterop && obj && obj.__esModule) return obj; + if (obj === null || typeof obj !== "object" && typeof obj !== "function") return { + default: obj + }; + var cache = _getRequireWildcardCache(nodeInterop); + if (cache && cache.has(obj)) return cache.get(obj); + var newObj = { + __proto__: null + }; + var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; + for(var key in obj){ + if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { + var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; + if (desc && (desc.get || desc.set)) Object.defineProperty(newObj, key, desc); + else newObj[key] = obj[key]; + } + } + newObj.default = obj; + if (cache) cache.set(obj, newObj); + return newObj; +}function _getRequireWildcardCache(nodeInterop) { + if (typeof WeakMap !== "function") return null; + var cacheBabelInterop = new WeakMap(); + var cacheNodeInterop = new WeakMap(); + return (_getRequireWildcardCache = function(nodeInterop) { + return nodeInterop ? cacheNodeInterop : cacheBabelInterop; + })(nodeInterop); +}function __commonJs(mod) { + var module; + return () => { + if (module) { + return module.exports; + } + module = { + exports: {}, + }; + if(typeof mod === "function") { + mod(module, module.exports); + }else { + mod[Object.keys(mod)[0]](module, module.exports); + } + return module.exports; + }; +}var foo_cjs = __commonJs((module, exports)=>{ + "use strict"; + Object.defineProperty(exports, "__esModule", { + value: true + }); + function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); + } + _export(exports, { + bar: function() { + return bar; + }, + foo: function() { + return foo; + } + }); + const foo = 'foo'; + const bar = 'bar'; + module.exports.cjs = true; +}); +var bar = foo_cjs()["bar"], foo = foo_cjs()["foo"]; + +export { bar, foo }; diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/named/runtime.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/named/runtime.ts new file mode 100644 index 000000000..0124c2287 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/named/runtime.ts @@ -0,0 +1 @@ +console.log('runtime'); \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/namespace/config.json b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/namespace/config.json new file mode 100644 index 000000000..eb309261d --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/namespace/config.json @@ -0,0 +1,6 @@ +{ + "output": { + "targetEnv": "library-node", + "format": "esm" + } +} \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/namespace/foo.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/namespace/foo.ts new file mode 100644 index 000000000..aea4653a0 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/namespace/foo.ts @@ -0,0 +1,7 @@ +export default 'foo'; + +export const foo = 'foo'; + +export const bar = 'bar'; + +module.exports.cjs = true; \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/namespace/index.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/namespace/index.ts new file mode 100644 index 000000000..acd381147 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/namespace/index.ts @@ -0,0 +1 @@ +export * as ns from './foo'; diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/namespace/output.js b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/namespace/output.js new file mode 100644 index 000000000..46366be2b --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/namespace/output.js @@ -0,0 +1,91 @@ +//index.js: + function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +}function _export_star(from, to) { + Object.keys(from).forEach(function(k) { + if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) { + Object.defineProperty(to, k, { + enumerable: true, + get: function() { + return from[k]; + } + }); + } + }); + return from; +}function _interop_require_wildcard(obj, nodeInterop) { + if (!nodeInterop && obj && obj.__esModule) return obj; + if (obj === null || typeof obj !== "object" && typeof obj !== "function") return { + default: obj + }; + var cache = _getRequireWildcardCache(nodeInterop); + if (cache && cache.has(obj)) return cache.get(obj); + var newObj = { + __proto__: null + }; + var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; + for(var key in obj){ + if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { + var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; + if (desc && (desc.get || desc.set)) Object.defineProperty(newObj, key, desc); + else newObj[key] = obj[key]; + } + } + newObj.default = obj; + if (cache) cache.set(obj, newObj); + return newObj; +}function _getRequireWildcardCache(nodeInterop) { + if (typeof WeakMap !== "function") return null; + var cacheBabelInterop = new WeakMap(); + var cacheNodeInterop = new WeakMap(); + return (_getRequireWildcardCache = function(nodeInterop) { + return nodeInterop ? cacheNodeInterop : cacheBabelInterop; + })(nodeInterop); +}function __commonJs(mod) { + var module; + return () => { + if (module) { + return module.exports; + } + module = { + exports: {}, + }; + if(typeof mod === "function") { + mod(module, module.exports); + }else { + mod[Object.keys(mod)[0]](module, module.exports); + } + return module.exports; + }; +}var foo_cjs = __commonJs((module, exports)=>{ + "use strict"; + Object.defineProperty(exports, "__esModule", { + value: true + }); + function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); + } + _export(exports, { + bar: function() { + return bar; + }, + default: function() { + return _default; + }, + foo: function() { + return foo; + } + }); + var _default = 'foo'; + const foo = 'foo'; + const bar = 'bar'; + module.exports.cjs = true; +}); +var foo_ns = _interop_require_wildcard(foo_cjs()); + +export { foo_ns as ns }; diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/namespace/runtime.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/namespace/runtime.ts new file mode 100644 index 000000000..0124c2287 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/namespace/runtime.ts @@ -0,0 +1 @@ +console.log('runtime'); \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/star/config.json b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/star/config.json new file mode 100644 index 000000000..eb309261d --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/star/config.json @@ -0,0 +1,6 @@ +{ + "output": { + "targetEnv": "library-node", + "format": "esm" + } +} \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/star/foo.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/star/foo.ts new file mode 100644 index 000000000..4fbeb3711 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/star/foo.ts @@ -0,0 +1,7 @@ +export default 'foo'; + +export const foo = 'foo'; + +export const bar = 'bar'; + +module.exports.cjs = true; diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/star/index.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/star/index.ts new file mode 100644 index 000000000..1cc5a0795 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/star/index.ts @@ -0,0 +1 @@ +export * from './foo'; \ No newline at end of file diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/star/output.js b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/star/output.js new file mode 100644 index 000000000..f2320e3c3 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/star/output.js @@ -0,0 +1,92 @@ +//index.js: + function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +}function _export_star(from, to) { + Object.keys(from).forEach(function(k) { + if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) { + Object.defineProperty(to, k, { + enumerable: true, + get: function() { + return from[k]; + } + }); + } + }); + return from; +}function _interop_require_wildcard(obj, nodeInterop) { + if (!nodeInterop && obj && obj.__esModule) return obj; + if (obj === null || typeof obj !== "object" && typeof obj !== "function") return { + default: obj + }; + var cache = _getRequireWildcardCache(nodeInterop); + if (cache && cache.has(obj)) return cache.get(obj); + var newObj = { + __proto__: null + }; + var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; + for(var key in obj){ + if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { + var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; + if (desc && (desc.get || desc.set)) Object.defineProperty(newObj, key, desc); + else newObj[key] = obj[key]; + } + } + newObj.default = obj; + if (cache) cache.set(obj, newObj); + return newObj; +}function _getRequireWildcardCache(nodeInterop) { + if (typeof WeakMap !== "function") return null; + var cacheBabelInterop = new WeakMap(); + var cacheNodeInterop = new WeakMap(); + return (_getRequireWildcardCache = function(nodeInterop) { + return nodeInterop ? cacheNodeInterop : cacheBabelInterop; + })(nodeInterop); +}function __commonJs(mod) { + var module; + return () => { + if (module) { + return module.exports; + } + module = { + exports: {}, + }; + if(typeof mod === "function") { + mod(module, module.exports); + }else { + mod[Object.keys(mod)[0]](module, module.exports); + } + return module.exports; + }; +}var foo_cjs = __commonJs((module, exports)=>{ + "use strict"; + Object.defineProperty(exports, "__esModule", { + value: true + }); + function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); + } + _export(exports, { + bar: function() { + return bar; + }, + default: function() { + return _default; + }, + foo: function() { + return foo; + } + }); + var _default = 'foo'; + const foo = 'foo'; + const bar = 'bar'; + module.exports.cjs = true; +}); +var foo_default = _interop_require_default(foo_cjs()).default, bar = foo_cjs()["bar"], foo = foo_cjs()["foo"]; + +export { bar, foo }; +export default foo_default; diff --git a/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/star/runtime.ts b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/star/runtime.ts new file mode 100644 index 000000000..0124c2287 --- /dev/null +++ b/crates/compiler/tests/fixtures/bundle/library/reexport/reexport_hybrid_cjs/star/runtime.ts @@ -0,0 +1 @@ +console.log('runtime'); \ No newline at end of file diff --git a/crates/core/src/config/mod.rs b/crates/core/src/config/mod.rs index d659b59d3..41480dd94 100644 --- a/crates/core/src/config/mod.rs +++ b/crates/core/src/config/mod.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use serde::{Deserialize, Serialize}; use swc_css_prefixer::options::Targets; -use swc_ecma_parser::{EsConfig, TsConfig}; +use swc_ecma_parser::{EsSyntax as EsConfig, TsSyntax as TsConfig}; use self::{ bool_or_obj::BoolOrObj, comments::CommentsConfig, config_regex::ConfigRegex, html::HtmlConfig, diff --git a/crates/plugin_bundle/src/lib.rs b/crates/plugin_bundle/src/lib.rs index 7410c9f28..f2247e07a 100644 --- a/crates/plugin_bundle/src/lib.rs +++ b/crates/plugin_bundle/src/lib.rs @@ -48,18 +48,28 @@ impl Plugin for FarmPluginBundle { resource_pots.sort_by_key(|item| item.id.clone()); - let r = resource_pots.iter().map(|item| &**item).collect::>(); + let r = resource_pots + .iter() + .filter(|item| { + context.config.output.target_env.is_library() + || matches!(item.resource_pot_type, ResourcePotType::Runtime) + }) + .map(|item| &**item) + .collect::>(); let mut shared_bundle = SharedBundle::new(r, &module_graph, context)?; - let runtime_resource_pot = resource_pots + let inject_resource_pot_id = resource_pots .iter() - .find(|item| matches!(item.resource_pot_type, ResourcePotType::Runtime)) + .find(|item| { + (context.config.output.target_env.is_library() && item.entry_module.is_some()) + || matches!(item.resource_pot_type, ResourcePotType::Runtime) + }) .map(|i| i.id.clone()); - if let Some(runtime_resource_pot_id) = runtime_resource_pot { + if let Some(resource_pot_id) = inject_resource_pot_id { let polyfill = &mut shared_bundle .bundle_map - .get_mut(&runtime_resource_pot_id) + .get_mut(&resource_pot_id) .unwrap() .polyfill; diff --git a/crates/plugin_bundle/src/resource_pot_to_bundle/bundle/bundle_analyzer.rs b/crates/plugin_bundle/src/resource_pot_to_bundle/bundle/bundle_analyzer.rs index 3226e7872..ee8be9dbf 100644 --- a/crates/plugin_bundle/src/resource_pot_to_bundle/bundle/bundle_analyzer.rs +++ b/crates/plugin_bundle/src/resource_pot_to_bundle/bundle/bundle_analyzer.rs @@ -1,9 +1,13 @@ use std::{ - cell::RefCell, cmp::Ordering, collections::{HashMap, HashSet}, rc::Rc, sync::Arc + cell::RefCell, + cmp::Ordering, + collections::{HashMap, HashSet}, + rc::Rc, + sync::Arc, }; use farmfe_core::{ - config::{Mode, ModuleFormat, TargetEnv}, + config::{external::ExternalConfig, Config, Mode, ModuleFormat, TargetEnv}, context::CompilationContext, enhanced_magic_string::{ bundle::{Bundle, BundleOptions}, @@ -11,7 +15,7 @@ use farmfe_core::{ }, error::{CompilationError, Result}, farm_profile_function, farm_profile_scope, - module::{module_graph::ModuleGraph, ModuleId, ModuleSystem}, + module::{module_graph::ModuleGraph, ModuleId, ModuleSystem, ModuleType}, resource::resource_pot::{ResourcePot, ResourcePotType}, swc_common::{comments::SingleThreadedComments, util::take::Take}, }; @@ -23,8 +27,11 @@ use farmfe_toolkit::{ }; use crate::resource_pot_to_bundle::{ + bundle::bundle_external::ReferenceKind, common::OptionToResult, - modules_analyzer::module_analyzer::{ExportSpecifierInfo, ImportSpecifierInfo, StmtAction}, + modules_analyzer::module_analyzer::{ + ExportSpecifierInfo, ImportSpecifierInfo, StmtAction, Variable, + }, polyfill::SimplePolyfill, targets::generate::{ generate_bundle_import_by_bundle_reference, generate_export_by_reference_export, @@ -73,6 +80,13 @@ impl<'a> BundleAnalyzer<'a> { } } + pub fn set_namespace(&mut self, resource_pot_id: &str) { + self + .bundle_variable + .borrow_mut() + .set_namespace(resource_pot_id.to_string()); + } + // step: 1 toposort fetch modules pub fn build_module_order(&mut self, order_index_map: &HashMap) { farm_profile_function!(); @@ -189,6 +203,7 @@ impl<'a> BundleAnalyzer<'a> { } // 3-3 find module relation and link local variable + // TODO: refactor bundle_reference logic pub fn link_module_relation( &mut self, module_analyzer_manager: &mut ModuleAnalyzerManager, @@ -215,6 +230,7 @@ impl<'a> BundleAnalyzer<'a> { .is_some_and(|i| i.resource_pot_id != resource_pot_id) }) }; + let mut is_contain_export = false; for statement in &module_analyzer.statements { if let Some(import) = &statement.import { @@ -414,7 +430,8 @@ impl<'a> BundleAnalyzer<'a> { } if let Some(export) = &statement.export { - if module_analyzer_manager.is_commonjs(module_id) { + is_contain_export = true; + if module_analyzer_manager.is_commonjs(module_id) && !is_reference_by_another { continue; } @@ -476,13 +493,17 @@ impl<'a> BundleAnalyzer<'a> { source.clone().into(), module_system.clone(), ); - } else if module_analyzer_manager.is_commonjs(source) { + } else if module_analyzer_manager.is_commonjs(source) + && (!module_analyzer.entry + || matches!(module_analyzer.module_type, ModuleType::Runtime)) + { reexport_commonjs(source, &mut self.bundle_reference)?; } else { let export_names = &*module_analyzer_manager.get_export_names(source); let export_type = export_names.export_type.merge(module_system.clone()); let is_hybrid_dynamic = matches!(export_type, ModuleSystem::Hybrid); + let is_commonjs = module_analyzer_manager.is_commonjs(source); { for (from, export_as) in &export_names.export.named { @@ -490,13 +511,57 @@ impl<'a> BundleAnalyzer<'a> { &ExportSpecifierInfo::Named((*from, Some(*export_as)).into()), export_type.clone(), ); + + if is_commonjs { + let is_default_key = + self.bundle_variable.borrow().is_default_key(*from); + + let imported = if is_default_key { + module_analyzer_manager + .module_global_uniq_name + .default_name_result(module_id)? + } else { + *from + }; + + self.bundle_reference.add_declare_commonjs_import( + &ImportSpecifierInfo::Named { + local: *export_as, + imported: Some(imported), + }, + export.source.clone().unwrap().into(), + &self.bundle_variable.borrow(), + )?; + } } if let Some(item) = &export_names.export.default { + let is_default_key = self.bundle_variable.borrow().is_default_key(*item); + self.bundle_reference.add_local_export( - &ExportSpecifierInfo::Default(*item), + &ExportSpecifierInfo::Default(if is_default_key { + module_analyzer_manager + .module_global_uniq_name + .default_name_result(source)? + } else { + *item + }), export_type.clone(), ); + + if is_commonjs { + self.bundle_reference.add_declare_commonjs_import( + &ImportSpecifierInfo::Default(if is_default_key { + module_analyzer_manager + .module_global_uniq_name + .default_name_result(source)? + } else { + *item + }), + source.clone().into(), + &self.bundle_variable.borrow(), + )?; + } } } @@ -552,12 +617,12 @@ impl<'a> BundleAnalyzer<'a> { // export { name as personName } // export { name as personName } from './person'; - ExportSpecifierInfo::Named(variables) => { + ExportSpecifierInfo::Named(variable) => { if let Some(source) = &export.source { let is_find_default = - self.bundle_variable.borrow().name(variables.local()) == "default"; + self.bundle_variable.borrow().name(variable.local()) == "default"; let target = self.bundle_variable.borrow_mut().find_ident_by_index( - variables.local(), + variable.local(), source, module_analyzer_manager, resource_pot_id.clone(), @@ -575,12 +640,30 @@ impl<'a> BundleAnalyzer<'a> { match target { FindModuleExportResult::Local(local, target_source, _) => { is_confirmed_import = true; + let is_default_key = self.bundle_variable.borrow().is_default_key(local); + + let name = if is_default_key { + module_analyzer_manager + .module_global_uniq_name + .default_name_result(&target_source)? + } else { + local + }; + if is_common_js { self.bundle_variable.borrow_mut().set_var_uniq_rename(local); + self.bundle_reference.add_declare_commonjs_import( - &ImportSpecifierInfo::Named { - local, - imported: None, + &if is_default_key { + ImportSpecifierInfo::Named { + local: name, + imported: Some(local), + } + } else { + ImportSpecifierInfo::Named { + local, + imported: None, + } }, target_source.into(), &self.bundle_variable.borrow(), @@ -589,7 +672,10 @@ impl<'a> BundleAnalyzer<'a> { if is_reference_by_another { self.bundle_reference.add_local_export( - &ExportSpecifierInfo::Named((local).into()), + &ExportSpecifierInfo::Named(Variable( + name, + Some(variable.export_as()), + )), module_system, ); } @@ -619,9 +705,31 @@ impl<'a> BundleAnalyzer<'a> { self .bundle_variable .borrow_mut() - .set_var_uniq_rename(variables.local()); + .set_var_uniq_rename(variable.local()); if is_reference_by_another { + if module_analyzer_manager.is_commonjs(module_id) { + let is_default_key = self + .bundle_variable + .borrow() + .is_default_key(variable.local()); + + self.bundle_reference.add_declare_commonjs_import( + &ImportSpecifierInfo::Named { + local: if is_default_key { + module_analyzer_manager + .module_global_uniq_name + .default_name_result(module_id)? + } else { + variable.local() + }, + imported: Some(variable.export_as()), + }, + ReferenceKind::Module((*module_id).clone()), + &self.bundle_variable.borrow(), + )?; + } + self .bundle_reference .add_local_export(specify, module_system.clone()); @@ -632,13 +740,14 @@ impl<'a> BundleAnalyzer<'a> { // export default n, Default(n) // export default 1 + 1, Default("default") ExportSpecifierInfo::Default(var) => { - if self.bundle_variable.borrow().name(*var) == "default" { - let rendered_name = module_analyzer_manager + let default_name = || { + module_analyzer_manager .module_global_uniq_name - .default_name(module_id) - .to_result(format!("not found module {:?} default name", module_id))?; + .default_name_result(module_id) + }; - let rendered_name = self.bundle_variable.borrow().render_name(rendered_name); + if self.bundle_variable.borrow().name(*var) == "default" { + let rendered_name = self.bundle_variable.borrow().render_name(default_name()?); self .bundle_variable @@ -649,6 +758,14 @@ impl<'a> BundleAnalyzer<'a> { } if is_reference_by_another { + if module_analyzer_manager.is_commonjs(module_id) { + self.bundle_reference.add_declare_commonjs_import( + &ImportSpecifierInfo::Default(default_name()?), + ReferenceKind::Module((*module_id).clone()), + &self.bundle_variable.borrow(), + )?; + } + self .bundle_reference .add_local_export(specify, module_system.clone()); @@ -746,6 +863,14 @@ impl<'a> BundleAnalyzer<'a> { } } } + + if !is_contain_export + && module_analyzer_manager.is_commonjs(module_id) + && module_analyzer.entry + { + let reference_kind = ReferenceKind::Module((*module_id).clone()); + self.bundle_reference.execute_module_for_cjs(reference_kind); + } } } } @@ -780,6 +905,8 @@ impl<'a> BundleAnalyzer<'a> { ) -> Result<()> { farm_profile_function!(""); let mut commonjs_import_executed: HashSet = HashSet::new(); + let external_config = ExternalConfig::from(self.context.config.as_ref()); + for module_id in &self.ordered_modules { farm_profile_scope!(format!( "bundle patch ast module: {}", @@ -794,6 +921,7 @@ impl<'a> BundleAnalyzer<'a> { &mut commonjs_import_executed, order_index_map, &mut self.polyfill, + &external_config )?; } @@ -863,7 +991,11 @@ impl<'a> BundleAnalyzer<'a> { } // step: 4 generate bundle code - pub fn codegen(&mut self, module_analyzer_manager: &mut ModuleAnalyzerManager) -> Result { + pub fn codegen( + &mut self, + module_analyzer_manager: &mut ModuleAnalyzerManager, + config: &Config, + ) -> Result { let mut bundle = Bundle::new(BundleOptions { separator: Some('\n'), intro: None, @@ -932,7 +1064,7 @@ impl<'a> BundleAnalyzer<'a> { })?; let map = Arc::new(String::from_utf8(buf).unwrap()); - source_map_chain = module.source_map_chain.clone(); + source_map_chain.clone_from(&module.source_map_chain); source_map_chain.push(map); } @@ -962,9 +1094,16 @@ impl<'a> BundleAnalyzer<'a> { { bundle.prepend("((function(){"); bundle.append("})());", None); - } + }; + + let injectable_resource_pot = (config.output.target_env.is_library() + && self.resource_pot.entry_module.is_some()) + || matches!( + self.resource_pot.resource_pot_type, + ResourcePotType::Runtime + ); - if !self.polyfill.is_empty() { + if !self.polyfill.is_empty() && injectable_resource_pot { for item in self.polyfill.to_str() { bundle.prepend(&item); } diff --git a/crates/plugin_bundle/src/resource_pot_to_bundle/bundle/bundle_external.rs b/crates/plugin_bundle/src/resource_pot_to_bundle/bundle/bundle_external.rs index 6fa03ea3d..a67660299 100644 --- a/crates/plugin_bundle/src/resource_pot_to_bundle/bundle/bundle_external.rs +++ b/crates/plugin_bundle/src/resource_pot_to_bundle/bundle/bundle_external.rs @@ -153,12 +153,15 @@ pub struct BundleReference { /// import { xxx } from './external_bundle_module' | './other_bundle_module' pub import_map: HashMap, + /// + /// ```ts /// export { } from "./cjs_module"; /// export * as ns from "./cjs_module"; /// export { default } ns from "./cjs_module"; - /// import { } from "./cjs_module"; - /// import * as ns from "./cjs_module"; - /// import cjs from "./cjs_module"; + /// // => + /// const cjs_module_cjs = cjs_module()["default"]; + /// ``` + /// pub redeclare_commonjs_import: HashMap, // pub declare_commonjs_export: HashMap, @@ -215,7 +218,7 @@ impl BundleReference { } } - pub fn add_import_helper( + fn add_import_helper( map: &mut HashMap, import: &ImportSpecifierInfo, source: ReferenceKind, diff --git a/crates/plugin_bundle/src/resource_pot_to_bundle/bundle/mod.rs b/crates/plugin_bundle/src/resource_pot_to_bundle/bundle/mod.rs index 8a0667b7c..3dd381e5a 100644 --- a/crates/plugin_bundle/src/resource_pot_to_bundle/bundle/mod.rs +++ b/crates/plugin_bundle/src/resource_pot_to_bundle/bundle/mod.rs @@ -6,6 +6,7 @@ use std::{ use bundle_external::BundleReference; use farmfe_core::{ + config::external::ExternalConfig, context::CompilationContext, error::{CompilationError, MapCompletionError, Result}, farm_profile_function, farm_profile_scope, @@ -15,7 +16,7 @@ use farmfe_core::{ swc_common::{util::take::Take, DUMMY_SP}, swc_ecma_ast::{ self, BindingIdent, CallExpr, ClassDecl, Decl, EmptyStmt, Expr, ExprStmt, FnDecl, Ident, - ModuleDecl, ModuleItem, Stmt, VarDecl, VarDeclarator, + Module, ModuleDecl, ModuleItem, Stmt, VarDecl, VarDeclarator, }, }; use farmfe_toolkit::{script::swc_try_with::try_with, swc_ecma_visit::VisitMutWith}; @@ -31,6 +32,7 @@ use crate::resource_pot_to_bundle::targets::{ use self::reference::ReferenceMap; use super::{ + common::OptionToResult, defined_idents_collector::RenameIdent, modules_analyzer::module_analyzer::{ ExportSpecifierInfo, ImportSpecifierInfo, ModuleAnalyzer, StmtAction, @@ -43,6 +45,9 @@ pub struct ModuleAnalyzerManager<'a> { pub module_map: HashMap, pub namespace_modules: HashSet, + /// + /// + /// TODO: dynamic generate /// /// ```js /// // namespace/moduleA.js @@ -116,6 +121,12 @@ impl ModuleGlobalUniqName { .and_then(|item| item.commonjs) } + pub fn default_name_result(&self, module_id: &ModuleId) -> Result { + self + .default_name(module_id) + .to_result("not found module {:?} default name") + } + fn entry_module(&mut self, module_id: &ModuleId) -> &mut ModuleGlobalName { if !self.module_map.contains_key(module_id) { self @@ -225,6 +236,7 @@ impl<'a> ModuleAnalyzerManager<'a> { Ok(()) } + #[inline] pub fn is_commonjs(&self, module_id: &ModuleId) -> bool { self .module_map @@ -233,6 +245,15 @@ impl<'a> ModuleAnalyzerManager<'a> { .unwrap_or(false) } + #[inline] + pub fn is_entry(&self, module_id: &ModuleId) -> bool { + self + .module_map + .get(module_id) + .map(|item| item.entry) + .unwrap_or(false) + } + pub fn module_system(&self, module_id: &ModuleId) -> ModuleSystem { self .module_map @@ -286,6 +307,16 @@ impl<'a> ModuleAnalyzerManager<'a> { self.module_map.get_mut(module_id).unwrap() } + #[inline] + pub fn set_ast_body(&mut self, module_id: &ModuleId, ast_body: Vec) { + self.module_analyzer_mut_unchecked(module_id).ast.body = ast_body; + } + + #[inline] + pub fn set_ast(&mut self, module_id: &ModuleId, ast_body: Module) { + self.module_analyzer_mut_unchecked(module_id).ast = ast_body; + } + pub fn module_analyzer_by_source( &self, module_id: &ModuleId, @@ -331,8 +362,6 @@ impl<'a> ModuleAnalyzerManager<'a> { module_id: &ModuleId, bundle_variable: &BundleVariable, ) -> Arc { - let mut map = ReferenceMap::new(self.module_system(module_id)); - let exports_stmts = if let Some(module_analyzer) = self.module_analyzer(module_id) { if let Some(export_names) = &module_analyzer.export_names { return export_names.clone(); @@ -347,6 +376,13 @@ impl<'a> ModuleAnalyzerManager<'a> { vec![] }; + let mut map = ReferenceMap::new(self.module_system(module_id)); + + // preventing circular references + if let Some(m) = self.module_analyzer_mut(module_id) { + m.export_names = Some(Arc::new(map.clone())); + } + for export in exports_stmts { for specify in export.specifiers.iter() { if let Some(ref source) = export.source { @@ -397,6 +433,10 @@ impl<'a> ModuleAnalyzerManager<'a> { } } + if self.is_commonjs(module_id) && self.module_analyzer(module_id).is_some_and(|m| m.entry) { + // map + } + if let Some(m) = self.module_analyzer_mut(module_id) { m.export_names = Some(Arc::new(map)); } @@ -414,6 +454,7 @@ impl<'a> ModuleAnalyzerManager<'a> { commonjs_import_executed: &mut HashSet, order_index_map: &HashMap, polyfill: &mut SimplePolyfill, + external_config: &ExternalConfig, ) -> Result<()> { farm_profile_function!(format!( "patch module analyzer ast: {}", @@ -432,6 +473,7 @@ impl<'a> ModuleAnalyzerManager<'a> { commonjs_import_executed, order_index_map, polyfill, + external_config, )?; Ok(()) @@ -611,6 +653,7 @@ impl<'a> ModuleAnalyzerManager<'a> { commonjs_import_executed: &mut HashSet, order_index_map: &HashMap, polyfill: &mut SimplePolyfill, + external_config: &ExternalConfig, ) -> Result<()> { farm_profile_function!(""); @@ -676,6 +719,9 @@ impl<'a> ModuleAnalyzerManager<'a> { module_graph, &self.module_global_uniq_name, bundle_variable, + &context.config, + polyfill, + external_config ) } @@ -695,7 +741,7 @@ impl<'a> ModuleAnalyzerManager<'a> { ast.visit_mut_with(&mut RenameIdent::new(rename_map)); - self.module_analyzer_mut(module_id).unwrap().ast = ast; + self.set_ast(module_id, ast); } }) .unwrap(); @@ -816,7 +862,15 @@ impl<'a> ModuleAnalyzerManager<'a> { .add_namespace(source, |s| bundle_variable.register_used_name_by_module_id(source, s, root)); } } - _ => {} + ExportSpecifierInfo::Named(var) => { + if bundle_variable.name(var.local()) == "default" { + self + .module_global_uniq_name + .add_default(&module_analyzer.module_id, |s| { + bundle_variable.register_used_name_by_module_id(&module_analyzer.module_id, s, root) + }); + } + } } } } diff --git a/crates/plugin_bundle/src/resource_pot_to_bundle/common.rs b/crates/plugin_bundle/src/resource_pot_to_bundle/common.rs index 97f66b0db..6e1f85c2d 100644 --- a/crates/plugin_bundle/src/resource_pot_to_bundle/common.rs +++ b/crates/plugin_bundle/src/resource_pot_to_bundle/common.rs @@ -7,7 +7,7 @@ use farmfe_core::{ module::Module, swc_common::{comments::SingleThreadedComments, Mark}, swc_ecma_ast::{Module as EcmaAstModule, ModuleItem}, - swc_ecma_parser::{lexer::Lexer, EsConfig, Parser, StringInput, Syntax}, + swc_ecma_parser::{lexer::Lexer, EsSyntax as EsConfig, Parser, StringInput, Syntax}, }; use farmfe_toolkit::{ common::{create_swc_source_map, Source}, @@ -56,7 +56,6 @@ pub fn parse_module_item(string: &str) -> Result { pub trait OptionToResult { fn to_result(self, error: S) -> Result; - fn to_result_with_error(self, error: CompilationError) -> Result; } impl OptionToResult for std::option::Option { @@ -66,11 +65,4 @@ impl OptionToResult for std::option::Option { None => Err(CompilationError::GenericError(error.to_string())), } } - - fn to_result_with_error(self, error: CompilationError) -> Result { - match self { - Some(v) => Ok(v), - None => Err(error), - } - } } diff --git a/crates/plugin_bundle/src/resource_pot_to_bundle/mod.rs b/crates/plugin_bundle/src/resource_pot_to_bundle/mod.rs index a92c74a91..040934a26 100644 --- a/crates/plugin_bundle/src/resource_pot_to_bundle/mod.rs +++ b/crates/plugin_bundle/src/resource_pot_to_bundle/mod.rs @@ -242,14 +242,38 @@ impl<'a> SharedBundle<'a> { let bundle_analyzer = self.bundle_map.get_mut(resource_pot_id).unwrap(); - bundle_analyzer - .bundle_variable - .borrow_mut() - .set_namespace(bundle_analyzer.resource_pot.id.clone()); + bundle_analyzer.set_namespace(&bundle_analyzer.resource_pot.id); bundle_analyzer.render(&mut self.module_analyzer_manager, &self.order_index_map)?; } + let mut polyfill = SimplePolyfill::new(vec![]); + + for resource_pot_id in &self.order_resource_pot { + let bundle_analyzer = self.bundle_map.get(resource_pot_id).unwrap(); + + if matches!( + bundle_analyzer.resource_pot.resource_pot_type, + ResourcePotType::Js + ) { + polyfill.extends(&bundle_analyzer.polyfill); + } + } + + let runtime_resource_pot_id = self.order_resource_pot.iter().find(|item| { + self.bundle_map.get_mut(*item).is_some_and(|item| { + matches!( + item.resource_pot.resource_pot_type, + ResourcePotType::Runtime + ) + }) + }); + + if let Some(runtime_resource_pot_id) = runtime_resource_pot_id { + let bundle_analyzer = self.bundle_map.get_mut(runtime_resource_pot_id).unwrap(); + bundle_analyzer.polyfill.extends(&polyfill); + }; + Ok(()) } @@ -272,7 +296,7 @@ impl<'a> SharedBundle<'a> { let bundle = self.bundle_map.get_mut(resource_pot_id).unwrap(); - let bundle = bundle.codegen(&mut self.module_analyzer_manager)?; + let bundle = bundle.codegen(&mut self.module_analyzer_manager, &self.context.config)?; Ok(bundle) } diff --git a/crates/plugin_bundle/src/resource_pot_to_bundle/modules_analyzer/analyze.rs b/crates/plugin_bundle/src/resource_pot_to_bundle/modules_analyzer/analyze.rs index f0138ad67..56bd5616b 100644 --- a/crates/plugin_bundle/src/resource_pot_to_bundle/modules_analyzer/analyze.rs +++ b/crates/plugin_bundle/src/resource_pot_to_bundle/modules_analyzer/analyze.rs @@ -6,7 +6,7 @@ use farmfe_core::{ module::{module_graph::ModuleGraph, ModuleId}, swc_common::Mark, swc_ecma_ast::{ - self, Decl, DefaultDecl, ExportDecl, Expr, Ident, ImportSpecifier, ModuleDecl, + self, DefaultDecl, ExportDecl, Expr, Ident, ImportSpecifier, ModuleDecl, ModuleExportName, ModuleItem, }, }; diff --git a/crates/plugin_bundle/src/resource_pot_to_bundle/modules_analyzer/module_analyzer.rs b/crates/plugin_bundle/src/resource_pot_to_bundle/modules_analyzer/module_analyzer.rs index 5ac0ccc4a..d498362f5 100644 --- a/crates/plugin_bundle/src/resource_pot_to_bundle/modules_analyzer/module_analyzer.rs +++ b/crates/plugin_bundle/src/resource_pot_to_bundle/modules_analyzer/module_analyzer.rs @@ -9,7 +9,7 @@ use farmfe_core::{ context::CompilationContext, error::Result, farm_profile_function, - module::{module_graph::ModuleGraph, Module, ModuleId, ModuleSystem}, + module::{module_graph::ModuleGraph, Module, ModuleId, ModuleSystem, ModuleType}, resource::resource_pot::ResourcePotId, swc_common::{Mark, SourceMap}, swc_ecma_ast::{Id, Module as EcmaAstModule}, @@ -242,6 +242,7 @@ pub struct ModuleAnalyzer { pub cjs_module_analyzer: CjsModuleAnalyzer, pub mark: (Mark, Mark), pub module_system: ModuleSystem, + pub module_type: ModuleType, } impl Debug for ModuleAnalyzer { @@ -302,6 +303,7 @@ impl ModuleAnalyzer { cjs_module_analyzer: CjsModuleAnalyzer::new(), mark: mark.unwrap(), module_system: module.meta.as_script().module_system.clone(), + module_type: module.module_type.clone(), }) } diff --git a/crates/plugin_bundle/src/resource_pot_to_bundle/polyfill/mod.rs b/crates/plugin_bundle/src/resource_pot_to_bundle/polyfill/mod.rs index 2358d730a..76e007b2f 100644 --- a/crates/plugin_bundle/src/resource_pot_to_bundle/polyfill/mod.rs +++ b/crates/plugin_bundle/src/resource_pot_to_bundle/polyfill/mod.rs @@ -55,6 +55,26 @@ pub enum Polyfill { /// const fs = _interop_require_default(node_fs); /// ``` InteropRequireDefault, + /// + /// support use require in esm + /// + /// ```ts + /// // esm pre + /// import __farmNodeModule from 'module'; + /// globalThis.nodeRequire = __farmNodeModule.createRequire(import.meta.url); + /// ``` + /// + NodeEsmGlobalRequireHelper, + + /// + /// browser external load + /// ```ts + /// const events = require("events"); + /// // => + /// loadExternalRequire('events'); + /// ``` + /// + BrowserExternalRequire, } impl Polyfill { @@ -161,6 +181,34 @@ function _interop_require_default(obj) { } "#), ], + Polyfill::NodeEsmGlobalRequireHelper => vec![ + r#" +import __farmNodeModule from 'module'; +globalThis.nodeRequire = __farmNodeModule.createRequire(import.meta.url); +"#, + ], + Polyfill::BrowserExternalRequire => vec![ + r#" +function loadExternalRequire(name) { + var _g = (globalThis || window || {}); + var m = _g[name]; + var assign = function() { + var args = Array.prototype.slice.call(arguments); + var target = args.shift(); + var hasOwnProperty = Object.hasOwnProperty; + for(var i = 0; i < args.length; i ++) { + for(var key in args[i]) { + if(!hasOwnProperty.call(target, key)) { + target[key] = args[i][key]; + } + } + } + return target; + } + return m ? m.default && !m.__esModule ? assign({}, m, {__esModule: true}) : (assign({}, m)) : m; +}; + "#, + ], } .into_iter() .map(|item| item.trim().into()) @@ -188,6 +236,8 @@ function _interop_require_default(obj) { Polyfill::Wildcard => vec!["_getRequireWildcardCache", "_interop_require_wildcard"], Polyfill::ExportStar => vec!["_export_star"], Polyfill::InteropRequireDefault => vec!["_interop_require_default"], + Polyfill::NodeEsmGlobalRequireHelper => vec!["__farmNodeModule"], + Polyfill::BrowserExternalRequire => vec!["loadExternalRequire"], }) .into_iter() .map(|item| item.into()) @@ -266,6 +316,7 @@ impl SimplePolyfill { Polyfill::Wildcard, Polyfill::ExportStar, Polyfill::InteropRequireDefault, + Polyfill::NodeEsmGlobalRequireHelper, ] .into_iter() .flat_map(|polyfill| polyfill.name()) diff --git a/crates/plugin_bundle/src/resource_pot_to_bundle/targets/cjs/mod.rs b/crates/plugin_bundle/src/resource_pot_to_bundle/targets/cjs/mod.rs index 92150c1c8..e4faaefcb 100644 --- a/crates/plugin_bundle/src/resource_pot_to_bundle/targets/cjs/mod.rs +++ b/crates/plugin_bundle/src/resource_pot_to_bundle/targets/cjs/mod.rs @@ -5,8 +5,8 @@ use farmfe_core::{ module::{module_graph::ModuleGraph, ModuleId}, swc_common::{Mark, DUMMY_SP}, swc_ecma_ast::{ - self, BindingIdent, CallExpr, ComputedPropName, Expr, ExprOrSpread, Ident, Lit, MemberExpr, - MemberProp, Module as EcmaAstModule, ModuleItem, Pat, Stmt, VarDecl, VarDeclarator, + self, BindingIdent, CallExpr, ComputedPropName, Expr, ExprOrSpread, ExprStmt, Ident, Lit, + MemberExpr, MemberProp, Module as EcmaAstModule, ModuleItem, Pat, Stmt, VarDecl, VarDeclarator, }, }; use farmfe_toolkit::{ @@ -131,6 +131,14 @@ impl CjsModuleAnalyzer { type_args: None, }; + if reference_import.is_empty() { + result.push(ModuleItem::Stmt(Stmt::Expr(ExprStmt { + span: DUMMY_SP, + expr: Box::new(Expr::Call(cjs_caller)), + }))); + return result; + } + if let Some(default) = reference_import.default { decls.push(VarDeclarator { span: DUMMY_SP, diff --git a/crates/plugin_bundle/src/resource_pot_to_bundle/targets/cjs/patch.rs b/crates/plugin_bundle/src/resource_pot_to_bundle/targets/cjs/patch.rs index 49f152061..ac4f82c4e 100644 --- a/crates/plugin_bundle/src/resource_pot_to_bundle/targets/cjs/patch.rs +++ b/crates/plugin_bundle/src/resource_pot_to_bundle/targets/cjs/patch.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use farmfe_core::{ - config::Mode, + config::{external::ExternalConfig, Config, Mode}, context::CompilationContext, error::Result, module::{module_graph::ModuleGraph, ModuleId, ModuleSystem}, @@ -18,7 +18,7 @@ use farmfe_toolkit::{ modules::{ common_js, import_analysis::import_analyzer, - util::{Config, ImportInterop}, + util::{Config as SwcConfig, ImportInterop}, }, }, swc_ecma_visit::VisitMutWith, @@ -125,7 +125,7 @@ impl CjsPatch { ast.visit_mut_with(&mut common_js::<&SingleThreadedComments>( unresolved_mark, - Config { + SwcConfig { ignore_dynamic: true, preserve_import_meta: true, ..Default::default() @@ -165,20 +165,18 @@ impl CjsPatch { if module_analyzer.is_commonjs() { let ast = module_analyzer.ast.body.take(); - let new_body = CjsPatch::wrap_commonjs( + module_analyzer_manager.set_ast_body( module_id, - bundle_variable, - &module_analyzer_manager.module_global_uniq_name, - ast, - context.config.mode.clone(), - polyfill, - ) - .unwrap(); - - module_analyzer_manager - .module_analyzer_mut_unchecked(module_id) - .ast - .body = new_body; + CjsPatch::wrap_commonjs( + module_id, + bundle_variable, + &module_analyzer_manager.module_global_uniq_name, + ast, + context.config.mode.clone(), + polyfill, + ) + .unwrap(), + ); } if let Some(import) = bundle_reference @@ -202,6 +200,9 @@ impl CjsPatch { module_graph: &ModuleGraph, module_global_uniq_name: &ModuleGlobalUniqName, bundle_variable: &BundleVariable, + config: &Config, + polyfill: &mut SimplePolyfill, + external_config: &ExternalConfig, ) { let mut replacer: CJSReplace = CJSReplace { unresolved_mark: mark.0, @@ -210,6 +211,9 @@ impl CjsPatch { module_id: module_id.clone(), module_global_uniq_name, bundle_variable, + config, + polyfill, + external_config }; ast.visit_mut_with(&mut replacer); diff --git a/crates/plugin_bundle/src/resource_pot_to_bundle/targets/cjs/util.rs b/crates/plugin_bundle/src/resource_pot_to_bundle/targets/cjs/util.rs index 9ccad2ab9..5260f019f 100644 --- a/crates/plugin_bundle/src/resource_pot_to_bundle/targets/cjs/util.rs +++ b/crates/plugin_bundle/src/resource_pot_to_bundle/targets/cjs/util.rs @@ -1,14 +1,17 @@ use farmfe_core::{ + config::{external::ExternalConfig, Config, ModuleFormat}, module::{module_graph::ModuleGraph, ModuleId}, swc_common::{Mark, DUMMY_SP}, - swc_ecma_ast::{CallExpr, Expr, ExprOrSpread, Lit}, + swc_ecma_ast::{CallExpr, Callee, Expr, ExprOrSpread, Lit, MemberExpr, MemberProp}, }; use farmfe_toolkit::{ script::is_commonjs_require, swc_ecma_visit::{VisitMut, VisitMutWith}, }; -use crate::resource_pot_to_bundle::{bundle::ModuleGlobalUniqName, uniq_name::BundleVariable}; +use crate::resource_pot_to_bundle::{ + bundle::ModuleGlobalUniqName, uniq_name::BundleVariable, Polyfill, SimplePolyfill, +}; enum ReplaceType { None, @@ -52,6 +55,9 @@ pub struct CJSReplace<'a> { pub module_id: ModuleId, pub module_global_uniq_name: &'a ModuleGlobalUniqName, pub bundle_variable: &'a BundleVariable, + pub config: &'a Config, + pub polyfill: &'a mut SimplePolyfill, + pub external_config: &'a ExternalConfig, } impl<'a> VisitMut for CJSReplace<'a> { @@ -77,10 +83,42 @@ impl<'a> VisitMut for CJSReplace<'a> { .module_graph .get_dep_by_source_optional(&self.module_id, &source, None) { - if let Some(commonjs_name) = self.module_global_uniq_name.commonjs_name(&id) { + if self.module_graph.module(&id).is_some_and(|m| m.external) { + if self.config.output.target_env.is_library() + && self.config.output.target_env.is_node() + { + // node esm + if matches!(self.config.output.format, ModuleFormat::EsModule) { + self.polyfill.add(Polyfill::NodeEsmGlobalRequireHelper); + call_expr.callee = Callee::Expr(Box::new(Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident("globalThis".into())), + prop: MemberProp::Ident("nodeRequire".into()), + }))); + } + } else { + // browser + self.polyfill.add(Polyfill::BrowserExternalRequire); + + let replace_source = self + .external_config + .find_match(&source) + .map(|v| v.source(&source)) + // it's maybe from plugin + .unwrap_or(source.clone()); + + call_expr.callee = + Callee::Expr(Box::new(Expr::Ident("loadExternalRequire".into()))); + call_expr.args = vec![ExprOrSpread { + spread: None, + expr: Box::new(Expr::Lit(Lit::Str(replace_source.into()))), + }]; + call_expr.span = DUMMY_SP; + } + } else if let Some(commonjs_name) = self.module_global_uniq_name.commonjs_name(&id) { *call_expr = CallExpr { span: DUMMY_SP, - callee: farmfe_core::swc_ecma_ast::Callee::Expr(Box::new(Expr::Ident( + callee: Callee::Expr(Box::new(Expr::Ident( self .bundle_variable .render_name(commonjs_name) @@ -95,7 +133,7 @@ impl<'a> VisitMut for CJSReplace<'a> { replaced = ReplaceType::Ident(ns); } } - // TODO: other bundle | external + // TODO: other bundle } } diff --git a/crates/plugin_bundle/src/resource_pot_to_bundle/uniq_name.rs b/crates/plugin_bundle/src/resource_pot_to_bundle/uniq_name.rs index ac07c359c..aa8bade74 100644 --- a/crates/plugin_bundle/src/resource_pot_to_bundle/uniq_name.rs +++ b/crates/plugin_bundle/src/resource_pot_to_bundle/uniq_name.rs @@ -309,6 +309,11 @@ impl BundleVariable { self.var_by_index(index).var.0.to_string() } + #[inline] + pub fn is_default_key(&self, index: usize) -> bool { + self.name(index) == "default" + } + pub fn render_name(&self, index: usize) -> String { let var = self.var_by_index(index); if let Some(rename) = var.rename.as_ref() { diff --git a/crates/plugin_runtime/src/handle_entry_resources.rs b/crates/plugin_runtime/src/handle_entry_resources.rs index 6cf71d4ec..9d46f2fd6 100644 --- a/crates/plugin_runtime/src/handle_entry_resources.rs +++ b/crates/plugin_runtime/src/handle_entry_resources.rs @@ -292,6 +292,7 @@ pub fn handle_entry_resources( ) { let module_graph = context.module_graph.read(); let module_group_graph = context.module_group_graph.read(); + let is_library = context.config.output.target_env.is_library(); // create a runtime resource let mut runtime_code = None; @@ -385,7 +386,7 @@ pub fn handle_entry_resources( for pre in vec![ dep_resources_require_code, - if should_inject_runtime { + if should_inject_runtime && !is_library { let runtime_resource = if let Some(runtime_resource) = runtime_resource.as_ref() { runtime_resource } else { @@ -404,13 +405,15 @@ pub fn handle_entry_resources( entry_bundle.prepend(&pre); } - for post in vec![ - set_initial_loaded_resources_code, - set_dynamic_resources_map_code, - call_entry_code, - export_info_code, - ] { - entry_bundle.append(&post); + if !is_library { + for post in vec![ + set_initial_loaded_resources_code, + set_dynamic_resources_map_code, + call_entry_code, + export_info_code, + ] { + entry_bundle.append(&post); + } } let entry_bundle_code = entry_bundle.to_string(); @@ -454,7 +457,7 @@ fn create_runtime_code( resources_map: &HashMap, context: &Arc, ) -> String { - let node_specific_code = if context.config.output.target_env == TargetEnv::Node { + let node_specific_code = if context.config.output.target_env.is_node() { match context.config.output.format { ModuleFormat::EsModule => { format!( diff --git a/crates/plugin_runtime/src/lib.rs b/crates/plugin_runtime/src/lib.rs index 91ff7bf4e..139d144a3 100644 --- a/crates/plugin_runtime/src/lib.rs +++ b/crates/plugin_runtime/src/lib.rs @@ -59,11 +59,9 @@ impl Plugin for FarmPluginRuntime { } fn config(&self, config: &mut Config) -> farmfe_core::error::Result> { - // library bundle does not contain runtime if config.output.target_env.is_library() { return Ok(None); } - // runtime package entry file if !config.runtime.path.is_empty() { config.input.insert( diff --git a/crates/plugin_script/src/import_meta_visitor.rs b/crates/plugin_script/src/import_meta_visitor.rs index 2b5a08ef8..0148a2f99 100644 --- a/crates/plugin_script/src/import_meta_visitor.rs +++ b/crates/plugin_script/src/import_meta_visitor.rs @@ -7,7 +7,8 @@ use farmfe_core::{ plugin::{PluginResolveHookParam, ResolveKind}, swc_common::DUMMY_SP, swc_ecma_ast::{ - CallExpr, Callee, Expr, ExprOrSpread, Ident, Lit, MemberExpr, MemberProp, MetaPropKind, Str, + CallExpr, Callee, Expr, ExprOrSpread, Ident, Lit, MemberExpr, MemberProp, MetaPropKind, + NewExpr, Str, }, }; use farmfe_toolkit::swc_ecma_visit::{VisitMut, VisitMutWith}; @@ -155,3 +156,62 @@ impl VisitMut for HmrAcceptedVisitor { } } } + +/// +/// transform when cjs and library +/// ```ts +/// import.meta.url +/// // => +/// new URL(__filename, 'file:').href +/// ``` +/// +struct ImportMetaURLVisitor {} + +impl ImportMetaURLVisitor { + fn replace_import_meta_url(&self, n: &mut Expr) -> bool { + if let Expr::Member(member) = n { + if let box Expr::MetaProp(_) = member.obj { + if let MemberProp::Ident(ident) = &member.prop { + if ident.sym == "url" { + *n = Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::New(NewExpr { + span: DUMMY_SP, + callee: Box::new(Expr::Ident("URL".into())), + args: Some(vec![ + ExprOrSpread { + spread: None, + expr: Box::new(Expr::Ident("__filename".into())), + }, + ExprOrSpread { + spread: None, + expr: Box::new(Expr::Lit(Lit::Str("file:".into()))), + }, + ]), + type_args: None, + })), + prop: MemberProp::Ident("href".into()), + }); + + return true; + } + } + } + } + + false + } +} + +impl VisitMut for ImportMetaURLVisitor { + fn visit_mut_expr(&mut self, n: &mut Expr) { + if !self.replace_import_meta_url(n) { + n.visit_mut_children_with(self); + } + } +} + +pub fn replace_import_meta_url(ast: &mut farmfe_core::swc_ecma_ast::Module) { + let mut visitor = ImportMetaURLVisitor {}; + ast.visit_mut_with(&mut visitor); +} diff --git a/crates/plugin_script/src/lib.rs b/crates/plugin_script/src/lib.rs index 99ea2b11e..70a986376 100644 --- a/crates/plugin_script/src/lib.rs +++ b/crates/plugin_script/src/lib.rs @@ -41,7 +41,7 @@ use farmfe_toolkit::{ swc_ecma_visit::VisitMutWith, }; -use import_meta_visitor::ImportMetaVisitor; +use import_meta_visitor::{replace_import_meta_url, ImportMetaVisitor}; #[cfg(feature = "swc_plugin")] use swc_plugins::{init_plugin_module_cache_once, transform_by_swc_plugins}; @@ -193,7 +193,9 @@ impl Plugin for FarmPluginScript { .to_string_lossy() .to_string() }; + transform_url_with_import_meta_url(ast, &comments); + transform_import_meta_glob( ast, context.config.root.clone(), @@ -249,10 +251,19 @@ impl Plugin for FarmPluginScript { // set param.module.meta.module_system set_module_system_for_module_meta(param, context); + let is_replace_import_meta_url = context.config.output.target_env.is_library() + && matches!(context.config.output.format, ModuleFormat::CommonJs); + + if is_replace_import_meta_url { + let ast = &mut param.module.meta.as_script_mut().ast; + replace_import_meta_url(ast) + }; + // find and replace `import.meta.xxx` to `module.meta.xxx` and detect hmr_accepted // skip transform import.meta when targetEnv is node - if matches!(context.config.output.target_env, TargetEnv::Browser) - || matches!(context.config.output.format, ModuleFormat::CommonJs) + if !context.config.output.target_env.is_library() + && (matches!(context.config.output.target_env, TargetEnv::Browser) + || matches!(context.config.output.format, ModuleFormat::CommonJs)) { // transform `import.meta.xxx` to `module.meta.xxx` let ast = &mut param.module.meta.as_script_mut().ast; diff --git a/crates/plugin_script/src/transform_import_meta_url/mod.rs b/crates/plugin_script/src/transform_import_meta_url/mod.rs index e342ec255..ccb3cdb4a 100644 --- a/crates/plugin_script/src/transform_import_meta_url/mod.rs +++ b/crates/plugin_script/src/transform_import_meta_url/mod.rs @@ -69,7 +69,7 @@ fn normalized_glob_pattern(pattern: String) -> String { return pattern_builder.join("/"); } -// transform `new URL("url", import.meta.url)` to `new URL(import.meta.glob('url', { eager: true, import: 'default', query: 'url' }), import.meta.url71)` +// transform `new URL("url", import.meta.url)` to `new URL(import.meta.glob('url', { eager: true, import: 'default', query: 'url' }), import.meta.url)` struct ImportMetaURLVisitor<'a> { comments: &'a SingleThreadedComments, } diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index f51cc473e..eb751b2ef 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -13,7 +13,7 @@ pub const FARM_IGNORE_ACTION_COMMENT: &str = "$farm-ignore"; pub const FARM_IGNORE_ACTION_COMMENTS: [&str; 2] = [FARM_IGNORE_ACTION_COMMENT, "$vite-ignore"]; pub fn is_skip_action_by_comment(comment: &str) -> bool { - if comment.is_empty() || !comment.contains("$") { + if comment.is_empty() || !comment.contains('$') { return false; } @@ -82,8 +82,8 @@ pub fn file_url_to_path(url: &str) -> String { let url = url.replace("file://", ""); if cfg!(windows) { - if let Some(url) = url.strip_prefix("/") { - url.replace("/", "\\") + if let Some(url) = url.strip_prefix('/') { + url.replace('/', "\\") } else { url.replace("/", "\\") } diff --git a/packages/core/src/utils/share.ts b/packages/core/src/utils/share.ts index a086b26c9..9a12e1e74 100644 --- a/packages/core/src/utils/share.ts +++ b/packages/core/src/utils/share.ts @@ -26,6 +26,12 @@ export const FARM_TARGET_BROWSER_ENVS = [ 'browser-esnext' ]; +export const FARM_TARGET_LIBRARY_ENVS = [ + 'library', + 'library-node', + 'library-browser' +]; + /* eslint-disable @typescript-eslint/no-use-before-define */ export function isObject(value: unknown): value is Record { return Object.prototype.toString.call(value) === '[object Object]'; @@ -158,7 +164,11 @@ export function mapTargetEnvValue(config: Config['config']) { } else if (FARM_TARGET_BROWSER_ENVS.includes(config.output.targetEnv)) { config.output.targetEnv = 'browser'; } else { - config.output.targetEnv = 'library'; + if (FARM_TARGET_LIBRARY_ENVS.includes(config.output.targetEnv)) { + return; + } + + config.output.targetEnv = 'library-browser'; } }