diff --git a/src/config.ts b/src/config.ts index e4efa5ba7c..d3fe03371a 100644 --- a/src/config.ts +++ b/src/config.ts @@ -73,7 +73,23 @@ const configSchema = { type: 'object', properties: { source: {type: 'string'}, - webDependencies: {type: 'array', items: {type: 'string'}}, + webDependencies: { + type: 'array', + items: { + anyOf: [ + {type: 'string'}, + { + type: 'array', + items: [ + { + type: 'string', + }, + {type: 'string'}, + ], + }, + ], + }, + }, dedupe: { type: 'array', items: {type: 'string'}, diff --git a/src/index.ts b/src/index.ts index f7ec2cf175..573ddc2722 100644 --- a/src/index.ts +++ b/src/index.ts @@ -223,6 +223,7 @@ export async function install( {hasBrowserlistConfig, isExplicit, lockfile}: InstallOptions, config: SnowpackConfig, ) { + // throw new Error('typescript sucks'); // @ts-ignore const { dedupe, namedExports, @@ -258,11 +259,17 @@ export async function install( const installTargetsMap: {[targetLoc: string]: InstallTarget[]} = {}; const skipFailures = !isExplicit; - for (const installSpecifier of allInstallSpecifiers) { + for (const installSpecifierOrArr of allInstallSpecifiers) { + const installSpecifier = Array.isArray(installSpecifierOrArr) + ? installSpecifierOrArr[1] + : installSpecifierOrArr; + const installSpecifierOrAlias = Array.isArray(installSpecifierOrArr) + ? installSpecifierOrArr[0] + : installSpecifierOrArr; const targetName = getWebDependencyName(installSpecifier); if (lockfile && lockfile.imports[installSpecifier]) { installEntrypoints[targetName] = lockfile.imports[installSpecifier]; - importMap.imports[installSpecifier] = `./${targetName}.js`; + importMap.imports[installSpecifierOrAlias] = `./${targetName}.js`; installResults.push([targetName, 'SUCCESS']); logUpdate(formatInstallResults(skipFailures)); continue; @@ -272,7 +279,7 @@ export async function install( if (targetType === 'JS') { const hashQs = useHash ? `?rev=${await generateHashFromFile(targetLoc)}` : ''; installEntrypoints[targetName] = targetLoc; - importMap.imports[installSpecifier] = `./${targetName}.js${hashQs}`; + importMap.imports[installSpecifierOrAlias] = `./${targetName}.js${hashQs}`; installTargetsMap[targetLoc] = installTargets.filter(t => installSpecifier === t.specifier); installResults.push([installSpecifier, 'SUCCESS']); } else if (targetType === 'ASSET') { diff --git a/src/resolve-remote.ts b/src/resolve-remote.ts index 457b7e72dc..def1dfbfb2 100644 --- a/src/resolve-remote.ts +++ b/src/resolve-remote.ts @@ -91,7 +91,10 @@ export async function resolveTargetsFromRemoteCDN( const newLockfile: ImportMap = {imports: {}}; const allInstallSpecifiers = new Set(installTargets.map(dep => dep.specifier)); - for (const installSpecifier of allInstallSpecifiers) { + for (const installSpecifierOrArr of allInstallSpecifiers) { + const installSpecifier = Array.isArray(installSpecifierOrArr) + ? installSpecifierOrArr[1] + : installSpecifierOrArr; const installSemver: string = (pkgManifest.dependencies || {})[installSpecifier] || (pkgManifest.devDependencies || {})[installSpecifier] || diff --git a/src/scan-imports.ts b/src/scan-imports.ts index c30ba23c1c..8849ca6264 100644 --- a/src/scan-imports.ts +++ b/src/scan-imports.ts @@ -22,7 +22,7 @@ const DEFAULT_IMPORT_REGEX = /import\s+(\w)+(,\s\{[\w\s]*\})?\s+from/s; * are metadata about what is actually being imported. */ export type InstallTarget = { - specifier: string; + specifier: string | [string, string]; all: boolean; default: boolean; namespace: boolean; @@ -33,7 +33,7 @@ function stripJsExtension(dep: string): string { return dep.replace(/\.m?js$/i, ''); } -function createInstallTarget(specifier: string, all = true): InstallTarget { +function createInstallTarget(specifier: string | [string, string], all = true): InstallTarget { return { specifier, all, @@ -124,7 +124,8 @@ export function scanDepList(depList: string[], cwd: string): InstallTarget[] { const nodeModulesLoc = nodePath.join(cwd, 'node_modules'); return depList .map(whitelistItem => { - if (!glob.hasMagic(whitelistItem)) { + const safelistName = Array.isArray(whitelistItem) ? whitelistItem[1] : whitelistItem; + if (!glob.hasMagic(safelistName)) { return [createInstallTarget(whitelistItem, true)]; } else { return scanDepList(glob.sync(whitelistItem, {cwd: nodeModulesLoc, nodir: true}), cwd); @@ -158,5 +159,9 @@ export async function scanImports({include, exclude}: ScanImportsParams): Promis .map(filePath => [filePath, fs.readFileSync(filePath, 'utf8')]) .map(([filePath, code]) => getInstallTargetsForFile(filePath, code)) .reduce((flat, item) => flat.concat(item), []) - .sort((impA, impB) => impA.specifier.localeCompare(impB.specifier)); + .sort((impA, impB) => { + const specifierA = Array.isArray(impA.specifier) ? impA.specifier[1] : impA.specifier; + const specifierB = Array.isArray(impB.specifier) ? impB.specifier[1] : impB.specifier; + return specifierA.localeCompare(specifierB); + }); }