diff --git a/src/AureliaDependenciesPlugin.ts b/src/AureliaDependenciesPlugin.ts index e982673..24ac1f2 100644 --- a/src/AureliaDependenciesPlugin.ts +++ b/src/AureliaDependenciesPlugin.ts @@ -15,8 +15,8 @@ class AureliaDependency extends IncludeDependency { class Template { apply(dep: AureliaDependency, source: Webpack.Source) { // Get the module id, fallback to using the module request - let moduleId: string = dep.request; - if (dep.module && typeof dep.module[preserveModuleName] === 'string') { + let moduleId = dep.request; + if (dep.module && typeof dep.module[preserveModuleName] === "string") { moduleId = dep.module[preserveModuleName]; } diff --git a/src/PreserveModuleNamePlugin.ts b/src/PreserveModuleNamePlugin.ts index a12917b..3851de0 100644 --- a/src/PreserveModuleNamePlugin.ts +++ b/src/PreserveModuleNamePlugin.ts @@ -17,7 +17,7 @@ * - The path to the module itself: /home/usr/pkg/node_modules * - The module name: mod * - The relative path: dir/file.js - * - Map the parsed path data to _nodeModuleResourcesMap by the parsed module name and its resource location + * - Map the parsed path data to nodeModuleResourcesMap by the parsed module name and its resource location * - Example Map: * { * 'aurelia-templating-router': { @@ -52,7 +52,7 @@ * - If there are multiple entry points: * - Pick the most shallow resource * - If they are both as shallow as possible choose index over module name match - * - Map the normalized module id to _nodeModuleResourceIdMap by the resource file + * - Map the normalized module id to nodeModuleResourceIdMap by the resource file * - Example Map: * { * '/home/usr/pkg/node_modules/aurelia-templating-router/dist/native-modules/router-view.js': 'aurelia-templating-router/router-view.js', @@ -92,8 +92,8 @@ import path = require("path"); export const preserveModuleName = Symbol(); // node_module maps -const _nodeModuleResourcesMap: NodeModule.ResourcesMap = {}; -const _nodeModuleResourceIdMap: NodeModule.ResourceIdMap = {}; +const nodeModuleResourcesMap: NodeModule.ResourcesMap = {}; +const nodeModuleResourceIdMap: NodeModule.ResourceIdMap = {}; const TAP_NAME = "Aurelia:PreserveModuleName"; @@ -124,7 +124,7 @@ export class PreserveModuleNamePlugin { } // Map and parse the modules if needed - modulesBeforeConcat.forEach((m) => mapNodeModule(m)); + modulesBeforeConcat.forEach(mapNodeModule); parseNodeModules(); for (let module of getPreservedModules(modules)) { @@ -137,8 +137,6 @@ export class PreserveModuleNamePlugin { // Get the module id let id = getModuleId(realModule, roots, alias); - if (!id) - throw new Error(`Can't figure out a normalized module name for ${realModule.rawRequest}, please call PLATFORM.moduleName() somewhere to help.`); // Remove default extensions normalizers.forEach(n => id = id!.replace(n, "")); @@ -147,6 +145,7 @@ export class PreserveModuleNamePlugin { if (/^async[?!]/.test(realModule.rawRequest)) id = "async!" + id; + id = id.replace(/\\/g, "/"); if (module.buildMeta) // meta can be null if the module contains errors module.buildMeta["aurelia-id"] = id; if (!this.isDll) { @@ -168,21 +167,13 @@ function getPreservedModules(modules: Webpack.Module[]) { } // Preserve the module if its dependencies are also preserved - const reasons = (m.reasons && Array.isArray(m.reasons)) ? m.reasons : []; - return reasons.some((reason) => Boolean(reason.dependency && reason.dependency[preserveModuleName])); + return m.reasons.some(reason => (reason.dependency && reason.dependency[preserveModuleName])); }) ); } -/** - * Check if a module exists in node_modules/ - * - * @param {Webpack.Module} module The module to check - * - * @return {Boolean} True if it exists in node_modules/, false otherwise - */ -function isNodeModule(module: Webpack.Module): boolean { - return !(!module || !module.resource || !(/\bnode_modules\b/i.test(module.resource))); +function isNodeModule(module: Webpack.Module) { + return (module.resource && /\bnode_modules\b/i.test(module.resource)); } /** @@ -234,10 +225,10 @@ function mapNodeModule(module: Webpack.Module) { } // Map it - if (!_nodeModuleResourcesMap[moduleData.name]) { - _nodeModuleResourcesMap[moduleData.name] = {}; + if (!nodeModuleResourcesMap[moduleData.name]) { + nodeModuleResourcesMap[moduleData.name] = {}; } - _nodeModuleResourcesMap[moduleData.name][module.resource] = moduleData; + nodeModuleResourcesMap[moduleData.name][module.resource] = moduleData; } /** @@ -266,13 +257,13 @@ function mapNodeModule(module: Webpack.Module) { * @return {undefined} */ function parseNodeModules() { - if (!_nodeModuleResourcesMap || !Object.keys(_nodeModuleResourcesMap).length) { + if (!nodeModuleResourcesMap || !Object.keys(nodeModuleResourcesMap).length) { return; } // Parse each module - for (const moduleKey in _nodeModuleResourcesMap) { - const moduleResources: NodeModule.ModuleResource = _nodeModuleResourcesMap[moduleKey]; + for (const moduleKey in nodeModuleResourcesMap) { + const moduleResources: NodeModule.ModuleResource = nodeModuleResourcesMap[moduleKey]; // Keep track of the common resource path and possible module entry points let commonPathParts: string[] = []; @@ -281,15 +272,15 @@ function parseNodeModules() { // Parse each resource in the module for (const resource in moduleResources) { const data: NodeModule.Data = moduleResources[resource]; - const pathParts: string[] = data.relative.split('/'); + const pathParts = data.relative.split("/"); const resourceFile: string | null = pathParts.splice(-1)[0]; if (!resourceFile) { continue; } // Entry? - const resourceName: string = resourceFile.replace(/\..*/, ''); - if (resourceName === moduleKey || resourceName === 'index') { + const resourceName = resourceFile.replace(/\..*/, ""); + if (resourceName === moduleKey || resourceName === "index") { possibleEntryPoints.push(resource); } @@ -314,12 +305,12 @@ function parseNodeModules() { } // Convert common path to string - let commonPath: string = commonPathParts.join('/'); - commonPath = (commonPath.startsWith('/')) ? commonPath : `/${commonPath}`; + let commonPath = commonPathParts.join("/"); + commonPath = (commonPath.startsWith("/")) ? commonPath : `/${commonPath}`; // If there is more than one possible entry point, use the most shallow resource let moduleEntry: string | null = null; - possibleEntryPoints.forEach((resource: string) => { + possibleEntryPoints.forEach((resource) => { const data: NodeModule.Data = moduleResources[resource]; // No entry yet? @@ -328,7 +319,7 @@ function parseNodeModules() { } // Shallow? - else if (moduleEntry.split('/').length > data.relative.split('/').length) { + else if (moduleEntry.split("/").length > data.relative.split("/").length) { moduleEntry = data.relative; } @@ -340,25 +331,25 @@ function parseNodeModules() { }); // If an entry point still hasnt been found and there is only one resource, use that - const resourceKeys: string[] = Object.keys(moduleResources); + const resourceKeys = Object.keys(moduleResources); if (!moduleEntry && resourceKeys.length === 1) { moduleEntry = moduleResources[resourceKeys[0]].relative; } // Map the resources to the module id - resourceKeys.forEach((resource: string) => { + resourceKeys.forEach((resource) => { const data: NodeModule.Data = moduleResources[resource]; // Entry? if (moduleEntry === data.relative) { - _nodeModuleResourceIdMap[resource] = moduleKey; + nodeModuleResourceIdMap[resource] = moduleKey; return; } // Build the id from the resources common path - let key: string = data.relative.replace(new RegExp(`^${escapeString(commonPath)}`), ''); - key = (key.startsWith('/')) ? key : `/${key}`; - _nodeModuleResourceIdMap[resource] = `${moduleKey}${key}`; + let key = data.relative.replace(new RegExp(`^${escapeString(commonPath)}`), ""); + key = (key.startsWith("/")) ? key : `/${key}`; + nodeModuleResourceIdMap[resource] = `${moduleKey}${key}`; }); } } @@ -373,14 +364,14 @@ function parseNodeModules() { * @return {string|null} The relative path if available, null otherwise */ function getRelativeModule(module: Webpack.Module, paths: string[]): string | null { - if (!module || !module.resource || !paths || !paths.length) { + if (!module.resource || !paths || !paths.length) { return null; } // Try to find the module in the resolver paths for (let i = 0, len = paths.length; i < len; i++) { - const relative: string = path.relative(paths[i], module.resource); - if (!relative.startsWith('..')) { + const relative = path.relative(paths[i], module.resource); + if (!relative.startsWith("..")) { return relative; } } @@ -398,19 +389,19 @@ function getRelativeModule(module: Webpack.Module, paths: string[]): string | nu * @return {string|null} The alias path if available, null otherwise */ function getAliasModule(module: Webpack.Module, aliases: { [key: string]: string } | null): string | null { - if (!module || !module.resource || !aliases || !Object.keys(aliases).length) { + if (!module.resource || !aliases || !Object.keys(aliases).length) { return null; } // Look for the module in each alias for (let alias in aliases) { - const relative: string = path.relative(path.resolve(aliases[alias]), module.resource); - if (relative.startsWith('..')) { + const relative = path.relative(path.resolve(aliases[alias]), module.resource); + if (relative.startsWith("..")) { continue; } // Absolute alias? - alias = alias.replace(/\$$/, ''); + alias = alias.replace(/\$$/, ""); return (relative && relative.length) ? `${alias}/${relative}` : alias; } @@ -425,13 +416,9 @@ function getAliasModule(module: Webpack.Module, aliases: { [key: string]: string * @param {string[]} paths The webpack resolver module paths * @param {[{ [key: string]: string }|null} aliases The webpack aliases * - * @return {string|null} The module id if available, null otherwise + * @return {string} The module id */ -function getModuleId(module: Webpack.Module, paths: string[], aliases: { [key: string]: string } | null): string | null { - if (!module) { - return null; - } - +function getModuleId(module: Webpack.Module, paths: string[], aliases: { [key: string]: string } | null): string { // Handling module ids can be a bit tricky // Modules can be included in any of the following ways: // import { Module } from 'module' @@ -456,14 +443,23 @@ function getModuleId(module: Webpack.Module, paths: string[], aliases: { [key: s // In order to have the aurelia-loader work correctly, we need to coerce everything to absolute ids // Is it a node_module? if (isNodeModule(module)) { - return _nodeModuleResourceIdMap[module.resource]; + return nodeModuleResourceIdMap[module.resource]; } // Get the module relative to the webpack resolver paths let moduleId = getRelativeModule(module, paths); // Fallback to parsing aliases if needed - return (moduleId) ? moduleId : getAliasModule(module, aliases); + if (!moduleId) { + moduleId = getAliasModule(module, aliases); + } + + // Still nothing? + if (!moduleId) { + throw new Error(`Can't figure out a normalized module name for ${module.rawRequest}, please call PLATFORM.moduleName() somewhere to help.`); + } + + return moduleId; } /** @@ -474,9 +470,5 @@ function getModuleId(module: Webpack.Module, paths: string[], aliases: { [key: s * @return {string|null} The escaped string */ function escapeString(str: string): string | null { - if (typeof str !== 'string') { - return null; - } - - return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"); } diff --git a/src/webpack.d.ts b/src/webpack.d.ts index d61f69e..57b92ec 100644 --- a/src/webpack.d.ts +++ b/src/webpack.d.ts @@ -57,10 +57,15 @@ declare namespace Webpack { range: [number, number]; // Those types are not correct, but that's enough to compile this project property: IdentifierExpression; - object: { name: string; type: string; } & MemberExpression; + object: { name: string; type: string; } & (MemberExpression | Identifier); type: "MemberExpression"; } + export class Identifier { + name: string; + type: "Identifier"; + } + export class IdentifierExpression { range: [number, number]; name: string;