feat(webpack): support es module bundling (#10788)

This commit is contained in:
Nathan Walker
2025-09-18 13:03:17 -07:00
committed by GitHub
parent d6d3800884
commit 1e54baf198
20 changed files with 806 additions and 414 deletions

View File

@ -53,11 +53,11 @@ declare module globalThis {
function registerModule(name: string, loader: (name: string) => any): void;
/**
* Register all modules from a webpack context.
* The context is one created using the following webpack utility:
* Register all modules from a bundler context.
* For example, the context could be one created using the following webpack utility:
* https://webpack.js.org/guides/dependency-management/#requirecontext
*
* The extension map is optional, modules in the webpack context will have their original file extension (e.g. may be ".ts" or ".scss" etc.),
* The extension map is optional, modules in the bundler context will have their original file extension (e.g. may be ".ts" or ".scss" etc.),
* while the built-in module builders in {N} will look for ".js", ".css" or ".xml" files. Adding a map such as:
* ```
* { ".ts": ".js" }
@ -65,7 +65,7 @@ declare module globalThis {
* Will resolve lookups for .js to the .ts file.
* By default scss and ts files are mapped.
*/
function registerWebpackModules(context: { keys(): string[]; (key: string): any }, extensionMap?: { [originalFileExtension: string]: string });
function registerBundlerModules(context: { keys(): string[]; (key: string): any }, extensionMap?: { [originalFileExtension: string]: string });
/**
* The NativeScript XML builder, style-scope, application modules use various resources such as:
@ -91,7 +91,7 @@ declare module globalThis {
function loadModule(name: string, loadForUI?: boolean): any;
/**
* Checks if the module has been registered with `registerModule` or in `registerWebpackModules`
* Checks if the module has been registered with `registerModule` or in `registerBundlerModules`
* @param name Name of the module
*/
function moduleExists(name: string): boolean;
@ -100,8 +100,6 @@ declare module globalThis {
function _unregisterModule(name: string): void;
function _isModuleLoadedForUI(moduleName: string): boolean;
var onGlobalLayoutListener: any;
function zonedCallback<T = Function>(callback: T): T;
var Reflect: any;

View File

@ -170,15 +170,20 @@ export function initGlobal() {
modules.delete(name);
};
global._isModuleLoadedForUI = function _isModuleLoadedForUI(moduleName: string): boolean {
return modulesLoadedForUI.has(moduleName);
};
global.registerBundlerModules = function registerBundlerModules(context: Context, extensionMap: ExtensionMap = {}) {
const registerWithName = (nickName: string, moduleId: string) => {
modules.set(nickName, {
moduleId,
loader: () => {
return context(moduleId);
},
});
};
global.registerWebpackModules = function registerWebpackModules(context: Context, extensionMap: ExtensionMap = {}) {
context.keys().forEach((moduleId) => {
const registerModuleById = (moduleId: string) => {
const extDotIndex = moduleId.lastIndexOf('.');
const base = moduleId.substr(0, extDotIndex);
const originalExt = moduleId.substr(extDotIndex);
const base = moduleId.substring(0, extDotIndex);
const originalExt = moduleId.substring(extDotIndex);
const registerExt = extensionMap[originalExt] || defaultExtensionMap[originalExt] || originalExt;
// We prefer source files for webpack scenarios before compilation leftovers,
@ -187,47 +192,40 @@ export function initGlobal() {
const isSourceFile = originalExt !== registerExt;
const registerName = base + registerExt;
const registerWithName = (nickName: string) => {
modules.set(nickName, {
moduleId,
loader: () => {
return context(moduleId);
},
});
};
if (registerName.startsWith('./') && registerName.endsWith('.js')) {
const jsNickNames = [
// This is extremely short version like "main-page" that was promoted to be used with global.registerModule("module-name", loaderFunc);
registerName.substr(2, registerName.length - 5),
registerName.substring(2, registerName.length - 3),
// This is for supporting module names like "./main/main-page"
registerName.substr(0, registerName.length - 3),
registerName.substring(0, registerName.length - 3),
// This is for supporting module names like "main/main-page.js"
registerName.substr(2),
registerName.substring(2),
];
jsNickNames.forEach((jsNickName) => {
if (isSourceFile || !global.moduleExists(jsNickName)) {
registerWithName(jsNickName);
registerWithName(jsNickName, moduleId);
}
});
} else if (registerName.startsWith('./')) {
const moduleNickNames = [
// This is for supporting module names like "main/main-page.xml"
registerName.substr(2),
registerName.substring(2),
];
moduleNickNames.forEach((moduleNickName) => {
if (!global.moduleExists(moduleNickName)) {
registerWithName(moduleNickName);
registerWithName(moduleNickName, moduleId);
}
});
}
if (isSourceFile || !global.moduleExists(registerName)) {
registerWithName(registerName);
registerWithName(registerName, moduleId);
}
});
};
context.keys().forEach(registerModuleById);
};
global.moduleExists = function moduleExists(name: string): boolean {