diff options
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.cpp | 13 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.h | 2 | ||||
-rw-r--r-- | src/bun.js/builtins/BunBuiltinNames.h | 2 | ||||
-rw-r--r-- | src/bun.js/builtins/cpp/JSZigGlobalObjectBuiltins.cpp | 183 | ||||
-rw-r--r-- | src/bun.js/builtins/cpp/WebCoreJSBuiltinInternals.h | 1 | ||||
-rw-r--r-- | src/bun.js/builtins/js/JSZigGlobalObject.js | 24 | ||||
-rw-r--r-- | src/bundler/entry_points.zig | 6 | ||||
-rw-r--r-- | src/bundler/generate_node_modules_bundle.zig | 2 | ||||
-rw-r--r-- | src/import_record.zig | 4 | ||||
-rw-r--r-- | src/js_ast.zig | 16 | ||||
-rw-r--r-- | src/js_printer.zig | 152 | ||||
-rw-r--r-- | src/linker.zig | 34 |
12 files changed, 272 insertions, 167 deletions
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index a51bc433b..6f04d2d1f 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -1754,6 +1754,12 @@ void GlobalObject::finishCreation(VM& vm) init.set(map); }); + m_requireMap.initLater( + [](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSMap>::Initializer& init) { + auto* map = JSC::JSMap::create(init.owner, init.vm, init.owner->mapStructure()); + init.set(map); + }); + m_JSArrayBufferSinkClassStructure.initLater( [](LazyClassStructure::Initializer& init) { auto* prototype = createJSSinkPrototype(init.vm, init.global, WebCore::SinkID::ArrayBufferSink); @@ -1784,7 +1790,7 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) auto& builtinNames = WebCore::builtinNames(vm); WTF::Vector<GlobalPropertyInfo> extraStaticGlobals; - extraStaticGlobals.reserveCapacity(30); + extraStaticGlobals.reserveCapacity(31); JSC::Identifier queueMicrotaskIdentifier = JSC::Identifier::fromString(vm, "queueMicrotask"_s); extraStaticGlobals.uncheckedAppend( @@ -1848,6 +1854,7 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); static NeverDestroyed<const String> BunLazyString(MAKE_STATIC_STRING_IMPL("Bun.lazy")); + static NeverDestroyed<const String> CommonJSSymbolKey(MAKE_STATIC_STRING_IMPL("CommonJS")); JSC::Identifier BunLazyIdentifier = JSC::Identifier::fromUid(vm.symbolRegistry().symbolForKey(BunLazyString)); JSC::JSFunction* lazyLoadFunction = JSC::JSFunction::create(vm, JSC::jsCast<JSC::JSGlobalObject*>(globalObject()), 0, BunLazyString, functionLazyLoad); @@ -1878,6 +1885,9 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.getInternalWritableStreamPrivateName(), JSFunction::create(vm, this, 1, String(), getInternalWritableStream), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly)); extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.createWritableStreamFromInternalPrivateName(), JSFunction::create(vm, this, 1, String(), createWritableStreamFromInternal), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly)); extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.fulfillModuleSyncPrivateName(), JSFunction::create(vm, this, 1, String(), functionFulfillModuleSync), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::Function)); + + extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.commonJSSymbolPrivateName(), JSC::Symbol::create(vm, vm.symbolRegistry().symbolForKey(CommonJSSymbolKey)), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly)); + this->addStaticGlobals(extraStaticGlobals.data(), extraStaticGlobals.size()); extraStaticGlobals.releaseBuffer(); @@ -2134,6 +2144,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) thisObject->m_JSArrayBufferControllerPrototype.visit(visitor); thisObject->m_importMetaObjectStructure.visit(visitor); thisObject->m_lazyReadableStreamPrototypeMap.visit(visitor); + thisObject->m_requireMap.visit(visitor); visitor.append(thisObject->m_readableStreamToArrayBufferResolve); visitor.append(thisObject->m_readableStreamToText); diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index cabaf57a9..b5a2f99da 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -159,6 +159,7 @@ public: JSC::JSValue ArrayBufferSinkPrototype() { return m_JSArrayBufferSinkClassStructure.prototypeInitializedOnMainThread(this); } JSC::JSValue JSReadableArrayBufferSinkControllerPrototype() { return m_JSArrayBufferControllerPrototype.getInitializedOnMainThread(this); } JSC::JSMap* readableStreamNativeMap() { return m_lazyReadableStreamPrototypeMap.getInitializedOnMainThread(this); } + JSC::JSMap* requireMap() { return m_requireMap.getInitializedOnMainThread(this); } void* bunVM() { return m_bunVM; } bool isThreadLocalDefaultGlobalObject = false; @@ -186,6 +187,7 @@ private: LazyProperty<JSGlobalObject, JSObject> m_JSArrayBufferControllerPrototype; LazyProperty<JSGlobalObject, JSObject> m_importMetaObjectStructure; LazyProperty<JSGlobalObject, JSMap> m_lazyReadableStreamPrototypeMap; + LazyProperty<JSGlobalObject, JSMap> m_requireMap; DOMGuardedObjectSet m_guardedObjects WTF_GUARDED_BY_LOCK(m_gcLock); void* m_bunVM; diff --git a/src/bun.js/builtins/BunBuiltinNames.h b/src/bun.js/builtins/BunBuiltinNames.h index 6acd30a8b..c41d368b4 100644 --- a/src/bun.js/builtins/BunBuiltinNames.h +++ b/src/bun.js/builtins/BunBuiltinNames.h @@ -62,6 +62,7 @@ using namespace JSC; macro(closedPromise) \ macro(closedPromiseCapability) \ macro(code) \ + macro(commonJSSymbol) \ macro(connect) \ macro(consumeReadableStream) \ macro(controlledReadableStream) \ @@ -177,6 +178,7 @@ using namespace JSC; macro(releaseLock) \ macro(removeEventListener) \ macro(require) \ + macro(requireMap) \ macro(requireModule) \ macro(resolve) \ macro(resolveSync) \ diff --git a/src/bun.js/builtins/cpp/JSZigGlobalObjectBuiltins.cpp b/src/bun.js/builtins/cpp/JSZigGlobalObjectBuiltins.cpp index 421ba1181..583a035d8 100644 --- a/src/bun.js/builtins/cpp/JSZigGlobalObjectBuiltins.cpp +++ b/src/bun.js/builtins/cpp/JSZigGlobalObjectBuiltins.cpp @@ -49,7 +49,7 @@ namespace WebCore { const JSC::ConstructAbility s_jsZigGlobalObjectRequireCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_jsZigGlobalObjectRequireCodeConstructorKind = JSC::ConstructorKind::None; -const int s_jsZigGlobalObjectRequireCodeLength = 1221; +const int s_jsZigGlobalObjectRequireCodeLength = 1162; static const JSC::Intrinsic s_jsZigGlobalObjectRequireCodeIntrinsic = JSC::NoIntrinsic; const char* const s_jsZigGlobalObjectRequireCode = "(function (name) {\n" \ @@ -59,36 +59,36 @@ const char* const s_jsZigGlobalObjectRequireCode = " }\n" \ " \n" \ " const resolved = this.resolveSync(name, this.path);\n" \ - " var requireCache = (globalThis[Symbol.for(\"_requireCache\")] ||= new @Map);\n" \ - " var cached = requireCache.@get(resolved);\n" \ + " var cached = @requireMap.@get(resolved);\n" \ + " const last5 = resolved.substring(resolved.length - 5);\n" \ " if (cached) {\n" \ - " if (resolved.endsWith(\".node\")) {\n" \ + " if (last5 === \".node\") {\n" \ " return cached.exports;\n" \ " }\n" \ "\n" \ " return cached;\n" \ " }\n" \ "\n" \ - "\n" \ + " \n" \ " //\n" \ - " if (resolved.endsWith(\".json\")) {\n" \ + " if (last5 === \".json\") {\n" \ " var fs = (globalThis[Symbol.for(\"_fs\")] ||= Bun.fs());\n" \ " var exports = JSON.parse(fs.readFileSync(resolved, \"utf8\"));\n" \ - " requireCache.@set(resolved, exports);\n" \ + " @requireMap.@set(resolved, exports);\n" \ " return exports;\n" \ - " } else if (resolved.endsWith(\".node\")) {\n" \ + " } else if (last5 === \".node\") {\n" \ " var module = { exports: {} };\n" \ " globalThis.process.dlopen(module, resolved);\n" \ - " requireCache.@set(resolved, module);\n" \ + " @requireMap.@set(resolved, module);\n" \ " return module.exports;\n" \ - " } else if (resolved.endsWith(\".toml\")) {\n" \ + " } else if (last5 === \".toml\") {\n" \ " var fs = (globalThis[Symbol.for(\"_fs\")] ||= Bun.fs());\n" \ " var exports = Bun.TOML.parse(fs.readFileSync(resolved, \"utf8\"));\n" \ - " requireCache.@set(resolved, exports);\n" \ + " @requireMap.@set(resolved, exports);\n" \ " return exports;\n" \ " } else {\n" \ " var exports = this.requireModule(this, resolved);\n" \ - " requireCache.@set(resolved, exports);\n" \ + " @requireMap.@set(resolved, exports);\n" \ " return exports;\n" \ " }\n" \ "})\n" \ @@ -96,94 +96,117 @@ const char* const s_jsZigGlobalObjectRequireCode = const JSC::ConstructAbility s_jsZigGlobalObjectLoadModuleCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_jsZigGlobalObjectLoadModuleCodeConstructorKind = JSC::ConstructorKind::None; -const int s_jsZigGlobalObjectLoadModuleCodeLength = 2783; +const int s_jsZigGlobalObjectLoadModuleCodeLength = 2750; static const JSC::Intrinsic s_jsZigGlobalObjectLoadModuleCodeIntrinsic = JSC::NoIntrinsic; const char* const s_jsZigGlobalObjectLoadModuleCode = "(function (meta, resolvedSpecifier) {\n" \ " \"use strict\";\n" \ - " var queue = @createFIFO();\n" \ - " var key = resolvedSpecifier;\n" \ - " \n" \ - " var Loader = globalThis.Loader;\n" \ - " var registry = Loader.registry;\n" \ - " while (key) {\n" \ - " @fulfillModuleSync(key);\n" \ - " var entry = registry.@get(key);\n" \ + " var Loader = globalThis.Loader;\n" \ "\n" \ - " //\n" \ - " //\n" \ - " //\n" \ - " //\n" \ - " var sourceCodeObject = @getPromiseInternalField(entry.fetch, @promiseFieldReactionsOrResult);\n" \ - " \n" \ + " var queue = @createFIFO();\n" \ + " var key = resolvedSpecifier;\n" \ + " var registry = Loader.registry;\n" \ + " while (key) {\n" \ + " @fulfillModuleSync(key);\n" \ + " var entry = registry.@get(key);\n" \ + "\n" \ + " //\n" \ + " //\n" \ + " //\n" \ + " //\n" \ + " var sourceCodeObject = @getPromiseInternalField(\n" \ + " entry.fetch,\n" \ + " @promiseFieldReactionsOrResult\n" \ + " );\n" \ + "\n" \ + " //\n" \ + " //\n" \ + " //\n" \ + " var moduleRecordPromise = Loader.parseModule(key, sourceCodeObject);\n" \ + " var module = entry.module;\n" \ + " if (!module && moduleRecordPromise && @isPromise(moduleRecordPromise)) {\n" \ + " var reactionsOrResult = @getPromiseInternalField(\n" \ + " moduleRecordPromise,\n" \ + " @promiseFieldReactionsOrResult\n" \ + " );\n" \ + " var flags = @getPromiseInternalField(\n" \ + " moduleRecordPromise,\n" \ + " @promiseFieldFlags\n" \ + " );\n" \ + " var state = flags & @promiseStateMask;\n" \ "\n" \ " //\n" \ + " if (\n" \ + " state === @promiseStatePending ||\n" \ + " (reactionsOrResult && @isPromise(reactionsOrResult))\n" \ + " ) {\n" \ + " @throwTypeError(`require() async module \\\"${key}\\\" is unsupported`);\n" \ + " } else if (state === @promiseStateRejected) {\n" \ + " //\n" \ + " //\n" \ + " @throwTypeError(\n" \ + " `${\n" \ + " reactionsOrResult?.message ?? \"An error occurred\"\n" \ + " } while parsing module \\\"${key}\\\"`\n" \ + " );\n" \ + " }\n" \ + " entry.module = module = reactionsOrResult;\n" \ + " } else if (moduleRecordPromise && !module) {\n" \ + " entry.module = module = moduleRecordPromise;\n" \ + " }\n" \ + "\n" \ + " //\n" \ + " @setStateToMax(entry, @ModuleLink);\n" \ + " var dependenciesMap = module.dependenciesMap;\n" \ + " var requestedModules = Loader.requestedModules(module);\n" \ + " var dependencies = @newArrayWithSize(requestedModules.length);\n" \ + "\n" \ + " for (var i = 0, length = requestedModules.length; i < length; ++i) {\n" \ + " var depName = requestedModules[i];\n" \ + "\n" \ " //\n" \ " //\n" \ - " var moduleRecordPromise = Loader.parseModule(key, sourceCodeObject);\n" \ - " var module = entry.module;\n" \ - " if (!module && moduleRecordPromise && @isPromise(moduleRecordPromise)) {\n" \ - " var reactionsOrResult = @getPromiseInternalField(moduleRecordPromise, @promiseFieldReactionsOrResult);\n" \ - " var flags = @getPromiseInternalField(moduleRecordPromise, @promiseFieldFlags);\n" \ - " var state = flags & @promiseStateMask;\n" \ + " var depKey =\n" \ + " depName[0] === \"/\"\n" \ + " ? depName\n" \ + " : Loader.resolveSync(depName, key, @undefined);\n" \ + " var depEntry = Loader.ensureRegistered(depKey);\n" \ "\n" \ - " //\n" \ - " if (state === @promiseStatePending || (reactionsOrResult && @isPromise(reactionsOrResult))) {\n" \ - " @throwTypeError(`require() async module \\\"${key}\\\" is unsupported`);\n" \ - " \n" \ - " } else if (state === @promiseStateRejected) {\n" \ - " //\n" \ - " //\n" \ - " @throwTypeError(`${reactionsOrResult?.message ?? \"An error occurred\"} while parsing module \\\"${key}\\\"`);\n" \ - " }\n" \ - " entry.module = module = reactionsOrResult;\n" \ - " } else if (moduleRecordPromise && !module) {\n" \ - " entry.module = module = moduleRecordPromise;\n" \ + " if (depEntry.state < @ModuleLink) {\n" \ + " queue.push(depKey);\n" \ " }\n" \ "\n" \ - " //\n" \ - " @setStateToMax(entry, @ModuleLink);\n" \ - " var dependenciesMap = module.dependenciesMap;\n" \ - " var requestedModules = Loader.requestedModules(module);\n" \ - " var dependencies = @newArrayWithSize(requestedModules.length);\n" \ - " \n" \ - " for (var i = 0, length = requestedModules.length; i < length; ++i) {\n" \ - " var depName = requestedModules[i];\n" \ - "\n" \ - " //\n" \ - " //\n" \ - " var depKey = depName[0] === '/' ? depName : Loader.resolveSync(depName, key, @undefined);\n" \ - " var depEntry = Loader.ensureRegistered(depKey);\n" \ - "\n" \ - " if (depEntry.state < @ModuleLink) {\n" \ - " queue.push(depKey);\n" \ - " }\n" \ - "\n" \ - " @putByValDirect(dependencies, i, depEntry);\n" \ - " dependenciesMap.@set(depName, depEntry);\n" \ - " }\n" \ - "\n" \ - " entry.dependencies = dependencies;\n" \ - " key = queue.shift();\n" \ - " while (key && ((registry.@get(key)?.state ?? @ModuleFetch) >= @ModuleLink)) {\n" \ - " key = queue.shift();\n" \ - " }\n" \ + " @putByValDirect(dependencies, i, depEntry);\n" \ + " dependenciesMap.@set(depName, depEntry);\n" \ " }\n" \ "\n" \ - " var linkAndEvaluateResult = Loader.linkAndEvaluateModule(resolvedSpecifier, @undefined);\n" \ - " if (linkAndEvaluateResult && @isPromise(linkAndEvaluateResult)) {\n" \ - " //\n" \ - " //\n" \ - " @throwTypeError(`require() async module \\\"${resolvedSpecifier}\\\" is unsupported`);\n" \ + " entry.dependencies = dependencies;\n" \ + " key = queue.shift();\n" \ + " while (key && (registry.@get(key)?.state ?? @ModuleFetch) >= @ModuleLink) {\n" \ + " key = queue.shift();\n" \ " }\n" \ + " }\n" \ + "\n" \ + " var linkAndEvaluateResult = Loader.linkAndEvaluateModule(\n" \ + " resolvedSpecifier,\n" \ + " @undefined\n" \ + " );\n" \ + " if (linkAndEvaluateResult && @isPromise(linkAndEvaluateResult)) {\n" \ + " //\n" \ + " //\n" \ + " @throwTypeError(\n" \ + " `require() async module \\\"${resolvedSpecifier}\\\" is unsupported`\n" \ + " );\n" \ + " }\n" \ + "\n" \ + " return Loader.registry.@get(resolvedSpecifier);\n" \ "\n" \ - " return Loader.registry.@get(resolvedSpecifier);\n" \ "})\n" \ ; const JSC::ConstructAbility s_jsZigGlobalObjectRequireModuleCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_jsZigGlobalObjectRequireModuleCodeConstructorKind = JSC::ConstructorKind::None; -const int s_jsZigGlobalObjectRequireModuleCodeLength = 613; +const int s_jsZigGlobalObjectRequireModuleCodeLength = 606; static const JSC::Intrinsic s_jsZigGlobalObjectRequireModuleCodeIntrinsic = JSC::NoIntrinsic; const char* const s_jsZigGlobalObjectRequireModuleCode = "(function (meta, resolved) {\n" \ @@ -200,7 +223,7 @@ const char* const s_jsZigGlobalObjectRequireModuleCode = " }\n" \ " var exports = Loader.getModuleNamespaceObject(entry.module);\n" \ " var commonJS = exports.default;\n" \ - " if (commonJS && @isObject(commonJS) && Symbol.for(\"CommonJS\") in commonJS) {\n" \ + " if (commonJS && @isObject(commonJS) && @commonJSSymbol in commonJS) {\n" \ " return commonJS();\n" \ " }\n" \ " return exports;\n" \ diff --git a/src/bun.js/builtins/cpp/WebCoreJSBuiltinInternals.h b/src/bun.js/builtins/cpp/WebCoreJSBuiltinInternals.h index fc5e2406a..cefa5fd8c 100644 --- a/src/bun.js/builtins/cpp/WebCoreJSBuiltinInternals.h +++ b/src/bun.js/builtins/cpp/WebCoreJSBuiltinInternals.h @@ -82,6 +82,7 @@ namespace Zig { class GlobalObject; } namespace Zig { class GlobalObject; } namespace Zig { class GlobalObject; } namespace Zig { class GlobalObject; } +namespace Zig { class GlobalObject; } /* * Copyright (c) 2015 Igalia * Copyright (c) 2015 Igalia S.L. diff --git a/src/bun.js/builtins/js/JSZigGlobalObject.js b/src/bun.js/builtins/js/JSZigGlobalObject.js index 7b82067ec..bb08bb107 100644 --- a/src/bun.js/builtins/js/JSZigGlobalObject.js +++ b/src/bun.js/builtins/js/JSZigGlobalObject.js @@ -30,36 +30,36 @@ function require(name) { } const resolved = this.resolveSync(name, this.path); - var requireCache = (globalThis[Symbol.for("_requireCache")] ||= new @Map); - var cached = requireCache.@get(resolved); + var cached = @requireMap.@get(resolved); + const last5 = resolved.substring(resolved.length - 5); if (cached) { - if (resolved.endsWith(".node")) { + if (last5 === ".node") { return cached.exports; } return cached; } - + // TODO: remove this hardcoding - if (resolved.endsWith(".json")) { + if (last5 === ".json") { var fs = (globalThis[Symbol.for("_fs")] ||= Bun.fs()); var exports = JSON.parse(fs.readFileSync(resolved, "utf8")); - requireCache.@set(resolved, exports); + @requireMap.@set(resolved, exports); return exports; - } else if (resolved.endsWith(".node")) { + } else if (last5 === ".node") { var module = { exports: {} }; globalThis.process.dlopen(module, resolved); - requireCache.@set(resolved, module); + @requireMap.@set(resolved, module); return module.exports; - } else if (resolved.endsWith(".toml")) { + } else if (last5 === ".toml") { var fs = (globalThis[Symbol.for("_fs")] ||= Bun.fs()); var exports = Bun.TOML.parse(fs.readFileSync(resolved, "utf8")); - requireCache.@set(resolved, exports); + @requireMap.@set(resolved, exports); return exports; } else { var exports = this.requireModule(this, resolved); - requireCache.@set(resolved, exports); + @requireMap.@set(resolved, exports); return exports; } } @@ -182,7 +182,7 @@ function requireModule(meta, resolved) { } var exports = Loader.getModuleNamespaceObject(entry.module); var commonJS = exports.default; - if (commonJS && @isObject(commonJS) && Symbol.for("CommonJS") in commonJS) { + if (commonJS && @isObject(commonJS) && @commonJSSymbol in commonJS) { return commonJS(); } return exports; diff --git a/src/bundler/entry_points.zig b/src/bundler/entry_points.zig index d2ffc4794..fec040bd2 100644 --- a/src/bundler/entry_points.zig +++ b/src/bundler/entry_points.zig @@ -183,11 +183,13 @@ pub const ServerEntryPoint = struct { const code = try std.fmt.bufPrint( &entry.code_buffer, \\//Auto-generated file + \\var cjsSymbol = Symbol.for("CommonJS"); \\import * as start from '{s}{s}'; \\export * from '{s}{s}'; \\var entryNamespace = start; - \\if ('default' in start && "__internalIsCommonJSNamespace" in globalThis && __internalIsCommonJSNamespace(start)) {{ - \\ entryNamespace = start.default(); + \\var cjs = start?.default; + \\if (cjs && typeof cjs === 'function' && cjsSymbol in cjs) {{ + \\ entryNamespace = cjs(); \\}} \\if (typeof entryNamespace?.then === 'function') {{ \\ entryNamespace = entryNamespace.then((entryNamespace) => {{ diff --git a/src/bundler/generate_node_modules_bundle.zig b/src/bundler/generate_node_modules_bundle.zig index a269944af..f48dcf217 100644 --- a/src/bundler/generate_node_modules_bundle.zig +++ b/src/bundler/generate_node_modules_bundle.zig @@ -1323,7 +1323,7 @@ pub fn processFile(this: *GenerateNodeModuleBundle, worker: *ThreadPool.Worker, if (bundler.options.platform.isBun()) { if (JSC.DisabledModule.has(import_record.path.text)) { import_record.path.is_disabled = true; - import_record.wrap_with_to_module = true; + import_record.do_commonjs_transform_in_printer = true; import_record.is_bundled = true; continue; } diff --git a/src/import_record.zig b/src/import_record.zig index a16e5a8ad..a933df2fb 100644 --- a/src/import_record.zig +++ b/src/import_record.zig @@ -125,8 +125,8 @@ pub const ImportRecord = struct { /// calling the "__reExport()" helper function calls_run_time_re_export_fn: bool = false, - /// Tell the printer to wrap this call to "require()" in "__toModule(...)" - wrap_with_to_module: bool = false, + /// Tell the printer to use runtime code to resolve this import/export + do_commonjs_transform_in_printer: bool = false, /// True for require calls like this: "try { require() } catch {}". In this /// case we shouldn't generate an error if the path could not be resolved. diff --git a/src/js_ast.zig b/src/js_ast.zig index 54b3bbbeb..bacf0cd6d 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -494,14 +494,14 @@ pub const ClauseItem = struct { alias_loc: logger.Loc, name: LocRef, - // This is the original name of the symbol stored in "Name". It's needed for - // "SExportClause" statements such as this: - // - // export {foo as bar} from 'path' - // - // In this case both "foo" and "bar" are aliases because it's a re-export. - // We need to preserve both aliases in case the symbol is renamed. In this - // example, "foo" is "OriginalName" and "bar" is "Alias". + /// This is the original name of the symbol stored in "Name". It's needed for + /// "SExportClause" statements such as this: + /// + /// export {foo as bar} from 'path' + /// + /// In this case both "foo" and "bar" are aliases because it's a re-export. + /// We need to preserve both aliases in case the symbol is renamed. In this + /// example, "foo" is "OriginalName" and "bar" is "Alias". original_name: string, pub const default_alias: string = "default"; diff --git a/src/js_printer.zig b/src/js_printer.zig index 8f5f47e20..5f0e99ded 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -379,7 +379,6 @@ pub const Options = struct { rewrite_require_resolve: bool = true, allocator: std.mem.Allocator = default_allocator, source_map_handler: ?SourceMapHandler = null, - css_import_behavior: Api.CssInJsBehavior = Api.CssInJsBehavior.facade, // TODO: remove this @@ -542,6 +541,8 @@ pub fn NewPrinter( prev_stmt_tag: Stmt.Tag = .s_empty, source_map_builder: SourceMap.Chunk.Builder = undefined, + symbol_counter: u32 = 0, + const Printer = @This(); pub fn writeAll(p: *Printer, bytes: anytype) anyerror!void { @@ -585,16 +586,17 @@ pub fn NewPrinter( } pub fn print(p: *Printer, str: anytype) void { - switch (@TypeOf(str)) { + const StringType = @TypeOf(str); + switch (comptime StringType) { comptime_int, u16, u8 => { - p.writer.print(@TypeOf(str), str); + p.writer.print(StringType, str); }, [6]u8 => { const span = std.mem.span(&str); p.writer.print(@TypeOf(span), span); }, else => { - p.writer.print(@TypeOf(str), str); + p.writer.print(StringType, str); }, } } @@ -670,12 +672,20 @@ pub fn NewPrinter( if (import.items.len > 0) { p.print("var "); p.print("{ "); + if (!import.is_single_line) { p.print("\n"); p.options.indent += 1; p.printIndent(); } + if (import.default_name) |default_name| { + p.print("default:"); + p.printSpaceBeforeIdentifier(); + p.printSymbol(default_name.ref.?); + p.print(", "); + } + for (import.items) |item, i| { if (i > 0) { p.print(","); @@ -687,14 +697,7 @@ pub fn NewPrinter( } } - const name = p.renamer.nameForSymbol(item.name.ref.?); - p.printIdentifier(name); - - if (!strings.eql(name, item.alias)) { - p.print(" : "); - p.printSpace(); - p.printClauseAlias(item.alias); - } + p.printClauseItemAs(item, true); } if (!import.is_single_line) { @@ -1440,6 +1443,32 @@ pub fn NewPrinter( p.print(quote); } + fn printClauseItem(p: *Printer, item: js_ast.ClauseItem) void { + return printClauseItemAs(p, item, false); + } + + fn printClauseItemAs(p: *Printer, item: js_ast.ClauseItem, comptime as_variable: bool) void { + const name = p.renamer.nameForSymbol(item.name.ref.?); + + if (comptime !as_variable) { + p.printIdentifier(name); + + if (!strings.eql(name, item.alias)) { + p.print(" as"); + p.printSpace(); + p.printClauseAlias(item.alias); + } + } else { + p.printClauseAlias(item.alias); + + if (!strings.eql(name, item.alias)) { + p.print(":"); + p.printSpace(); + p.printIdentifier(name); + } + } + } + pub inline fn canPrintIdentifier(_: *Printer, name: string) bool { if (comptime is_json) return false; @@ -3214,7 +3243,7 @@ pub fn NewPrinter( p.printSpace(); } - for (s.items) |*item, i| { + for (s.items) |item, i| { if (i != 0) { p.print(","); if (s.is_single_line) { @@ -3227,13 +3256,7 @@ pub fn NewPrinter( p.printIndent(); } - const name = p.renamer.nameForSymbol(item.name.ref.?); - p.printIdentifier(name); - if (!strings.eql(name, item.alias)) { - p.print(" as"); - p.printSpace(); - p.printClauseAlias(item.alias); - } + p.printClauseItem(item); } if (!s.is_single_line) { @@ -3293,6 +3316,65 @@ pub fn NewPrinter( } p.printIndent(); p.printSpaceBeforeIdentifier(); + + const import_record = p.import_records[s.import_record_index]; + + if (comptime is_bun_platform) { + if (import_record.do_commonjs_transform_in_printer) { + assert(s.items.len > 0); + + p.print("var {"); + var symbol_counter: u32 = p.symbol_counter; + + for (s.items) |item, i| { + if (i > 0) { + p.print(","); + } + + p.print(item.original_name); + assert(item.original_name.len > 0); + p.print(":"); + // this is unsound + // this is technical debt + // we need to handle symbol collisions for this + p.print("$eXp0rT_"); + var buf: [16]u8 = undefined; + p.print(std.fmt.bufPrint(&buf, "{}", .{std.fmt.fmtSliceHexLower(&@bitCast([4]u8, symbol_counter))}) catch unreachable); + symbol_counter +|= 1; + } + + p.print("}=import.meta.require("); + p.printQuotedUTF8(import_record.path.text, true); + p.print(")"); + p.printSemicolonAfterStatement(); + p.print("export {"); + + // reset symbol counter back + symbol_counter = p.symbol_counter; + + for (s.items) |item, i| { + if (i > 0) { + p.print(","); + } + + // this is unsound + // this is technical debt + // we need to handle symbol collisions for this + p.print("$eXp0rT_"); + var buf: [16]u8 = undefined; + p.print(std.fmt.bufPrint(&buf, "{}", .{std.fmt.fmtSliceHexLower(&@bitCast([4]u8, symbol_counter))}) catch unreachable); + symbol_counter +|= 1; + p.print(" as "); + p.print(item.alias); + } + + p.print("}"); + p.printSemicolonAfterStatement(); + p.symbol_counter = symbol_counter; + return; + } + } + p.print("export"); p.printSpace(); p.print("{"); @@ -3336,7 +3418,7 @@ pub fn NewPrinter( p.printSpace(); p.print("from"); p.printSpace(); - p.printQuotedUTF8(p.import_records[s.import_record_index].path.text, false); + p.printQuotedUTF8(import_record.path.text, false); p.printSemicolonAfterStatement(); }, .s_local => |s| { @@ -3661,7 +3743,7 @@ pub fn NewPrinter( return p.printBundledImport(record, s); } - if (record.wrap_with_to_module or record.path.is_disabled) { + if (record.do_commonjs_transform_in_printer or record.path.is_disabled) { const require_ref = p.options.require_ref; const module_id = record.module_id; @@ -3703,13 +3785,7 @@ pub fn NewPrinter( if (s.items.len > 0) { p.print(", "); for (s.items) |item, i| { - p.print(item.alias); - const name = p.renamer.nameForSymbol(item.name.ref.?); - - if (!strings.eql(name, item.alias)) { - p.print(": "); - p.printSymbol(item.name.ref.?); - } + p.printClauseItemAs(item, true); if (i < s.items.len - 1) { p.print(", "); @@ -3718,12 +3794,7 @@ pub fn NewPrinter( } } else { for (s.items) |item, i| { - p.print(item.alias); - const name = p.renamer.nameForSymbol(item.name.ref.?); - if (!strings.eql(name, item.alias)) { - p.print(":"); - p.printSymbol(item.name.ref.?); - } + p.printClauseItemAs(item, true); if (i < s.items.len - 1) { p.print(", "); @@ -3817,7 +3888,7 @@ pub fn NewPrinter( p.options.unindent(); } - for (s.items) |*item, i| { + for (s.items) |item, i| { if (i != 0) { p.print(","); if (s.is_single_line) { @@ -3830,14 +3901,7 @@ pub fn NewPrinter( p.printIndent(); } - p.printClauseAlias(item.alias); - const name = p.renamer.nameForSymbol(item.name.ref.?); - if (!strings.eql(name, item.alias)) { - p.printSpace(); - p.printSpaceBeforeIdentifier(); - p.print("as "); - p.printIdentifier(name); - } + p.printClauseItem(item); } if (!s.is_single_line) { diff --git a/src/linker.zig b/src/linker.zig index 449367b00..e67339216 100644 --- a/src/linker.zig +++ b/src/linker.zig @@ -272,7 +272,7 @@ pub const Linker = struct { if (JSC.DisabledModule.has(import_record.path.text)) { import_record.path.is_disabled = true; - import_record.wrap_with_to_module = true; + import_record.do_commonjs_transform_in_printer = true; continue; } @@ -483,22 +483,22 @@ pub const Linker = struct { import_path_format, ) catch continue; - if (comptime !supports_dynamic_require) { - // If we're importing a CommonJS module as ESM - // We need to do the following transform: - // import React from 'react'; - // => - // import {_require} from 'RUNTIME_IMPORTS'; - // import * as react_module from 'react'; - // var React = _require(react_module).default; - // UNLESS it's a namespace import - // If it's a namespace import, assume it's safe. - // We can do this in the printer instead of creating a bunch of AST nodes here. - // But we need to at least tell the printer that this needs to happen. - if (loader != .napi and resolved_import.shouldAssumeCommonJS(import_record.kind)) { - import_record.wrap_with_to_module = true; - import_record.module_id = @truncate(u32, std.hash.Wyhash.hash(0, path.pretty)); - + // If we're importing a CommonJS module as ESM + // We need to do the following transform: + // import React from 'react'; + // => + // import {_require} from 'RUNTIME_IMPORTS'; + // import * as react_module from 'react'; + // var React = _require(react_module).default; + // UNLESS it's a namespace import + // If it's a namespace import, assume it's safe. + // We can do this in the printer instead of creating a bunch of AST nodes here. + // But we need to at least tell the printer that this needs to happen. + if (loader != .napi and resolved_import.shouldAssumeCommonJS(import_record.kind)) { + import_record.do_commonjs_transform_in_printer = true; + import_record.module_id = @truncate(u32, std.hash.Wyhash.hash(0, path.pretty)); + + if (comptime !supports_dynamic_require) { result.ast.needs_runtime = true; needs_require = true; } |