diff --git a/src/config.ts b/src/config.ts index e4efa5ba7c..929b4ca758 100644 --- a/src/config.ts +++ b/src/config.ts @@ -2,7 +2,7 @@ import path from 'path'; import {cosmiconfigSync} from 'cosmiconfig'; import {Plugin} from 'rollup'; import {validate} from 'jsonschema'; -import merge from 'deepmerge'; +import {all as merge} from 'deepmerge'; const CONFIG_NAME = 'snowpack'; @@ -17,7 +17,8 @@ type DeepPartial = { // interface this library uses internally export interface SnowpackConfig { source: 'local' | 'pika'; - webDependencies?: string[]; + webDependencies?: {[packageName: string]: string}; + entrypoints?: string[]; dedupe?: string[]; namedExports?: {[filepath: string]: string[]}; installOptions: { @@ -51,8 +52,7 @@ export interface CLIFlags extends Partial { } // default settings -const DEFAULT_CONFIG: SnowpackConfig = { - source: 'local', +const DEFAULT_CONFIG: Partial = { dedupe: [], installOptions: { clean: false, @@ -73,7 +73,12 @@ const configSchema = { type: 'object', properties: { source: {type: 'string'}, - webDependencies: {type: 'array', items: {type: 'string'}}, + entrypoints: {type: 'array', items: {type: 'string'}}, + webDependencies: { + type: ['array', 'object'], + additionalProperties: {type: 'string'}, + items: {type: 'string'}, + }, dedupe: { type: 'array', items: {type: 'string'}, @@ -126,13 +131,21 @@ function expandCliFlags(flags: CLIFlags): DeepPartial { return result; } -/** resolve --dest relative to cwd */ -function normalizeDest(config: SnowpackConfig) { +/** resolve --dest relative to cwd, and set the default "source" */ +function normalizeConfig(config: SnowpackConfig): SnowpackConfig { config.installOptions.dest = path.resolve(process.cwd(), config.installOptions.dest); + if (Array.isArray(config.webDependencies)) { + config.entrypoints = config.webDependencies; + delete config.webDependencies; + } + if (!config.source) { + const isDetailedObject = config.webDependencies && typeof config.webDependencies === 'object'; + config.source = isDetailedObject ? 'pika' : 'local'; + } return config; } -export default function loadConfig(flags: CLIFlags) { +export default function loadConfig(flags: CLIFlags, pkgManifest: any) { const cliConfig = expandCliFlags(flags); const explorerSync = cosmiconfigSync(CONFIG_NAME, { @@ -160,7 +173,9 @@ export default function loadConfig(flags: CLIFlags) { if (!result || !result.config || result.isEmpty) { // if CLI flags present, apply those as overrides return { - config: normalizeDest(merge(DEFAULT_CONFIG, cliConfig)), + config: normalizeConfig( + merge([DEFAULT_CONFIG, cliConfig as any]), + ), errors, }; } @@ -174,11 +189,16 @@ export default function loadConfig(flags: CLIFlags) { }); // if valid, apply config over defaults - const mergedConfig = merge(DEFAULT_CONFIG, config); + const mergedConfig = merge([ + DEFAULT_CONFIG, + {webDependencies: pkgManifest.webDependencies}, + config, + cliConfig as any, + ]); // if CLI flags present, apply those as overrides return { - config: normalizeDest(merge(mergedConfig, cliConfig)), + config: normalizeConfig(mergedConfig), errors: validation.errors.map(msg => `${path.basename(result.filepath)}: ${msg.toString()}`), }; } diff --git a/src/index.ts b/src/index.ts index f7ec2cf175..4541d996af 100644 --- a/src/index.ts +++ b/src/index.ts @@ -395,7 +395,7 @@ export async function install( if (Object.keys(installEntrypoints).length > 0) { try { const packageBundle = await rollup(inputOptions); - logUpdate(''); + logUpdate(formatInstallResults(skipFailures)); await packageBundle.write(outputOptions); } catch (err) { const {loc} = err as RollupError; @@ -486,8 +486,17 @@ export async function cli(args: string[]) { await clearCache(); } + // Load the current package manifest + let pkgManifest: any; + try { + pkgManifest = require(path.join(cwd, 'package.json')); + } catch (err) { + console.log(chalk.red('[ERROR] package.json required but no file was found.')); + process.exit(0); + } + // load config - const {config, errors} = loadConfig(cliFlags); + const {config, errors} = loadConfig(cliFlags, pkgManifest); // handle config errors (if any) if (Array.isArray(errors) && errors.length) { @@ -510,18 +519,10 @@ export async function cli(args: string[]) { const { installOptions: {clean, dest, exclude, include}, - webDependencies, + entrypoints: configInstallTargets, source, } = config; - let pkgManifest: any; - try { - pkgManifest = require(path.join(cwd, 'package.json')); - } catch (err) { - console.log(chalk.red('[ERROR] package.json required but no file was found.')); - process.exit(0); - } - const implicitDependencies = [ ...Object.keys(pkgManifest.peerDependencies || {}), ...Object.keys(pkgManifest.dependencies || {}), @@ -535,15 +536,15 @@ export async function cli(args: string[]) { let isExplicit = false; const installTargets: InstallTarget[] = []; - if (webDependencies) { + if (configInstallTargets) { isExplicit = true; - installTargets.push(...scanDepList(webDependencies, cwd)); + installTargets.push(...scanDepList(configInstallTargets, cwd)); } if (include) { isExplicit = true; installTargets.push(...(await scanImports({include, exclude}))); } - if (!webDependencies && !include) { + if (!isExplicit) { installTargets.push(...scanDepList(implicitDependencies, cwd)); } if (installTargets.length === 0) { diff --git a/src/resolve-remote.ts b/src/resolve-remote.ts index 457b7e72dc..599a42f5cd 100644 --- a/src/resolve-remote.ts +++ b/src/resolve-remote.ts @@ -93,6 +93,8 @@ export async function resolveTargetsFromRemoteCDN( const allInstallSpecifiers = new Set(installTargets.map(dep => dep.specifier)); for (const installSpecifier of allInstallSpecifiers) { const installSemver: string = + (config.webDependencies || {})[installSpecifier] || + (pkgManifest.webDependencies || {})[installSpecifier] || (pkgManifest.dependencies || {})[installSpecifier] || (pkgManifest.devDependencies || {})[installSpecifier] || (pkgManifest.peerDependencies || {})[installSpecifier] || diff --git a/src/rollup-plugin-remote-cdn.ts b/src/rollup-plugin-remote-cdn.ts index 864fe429b5..914609f7c9 100644 --- a/src/rollup-plugin-remote-cdn.ts +++ b/src/rollup-plugin-remote-cdn.ts @@ -28,7 +28,7 @@ export function rollupPluginDependencyCache({log}: {log: (url: string) => void}) // If the source path is a CDN path including a hash, it's assumed the // file will never change and it is safe to pull from our local cache // without a network request. - log(source); + log(cacheKey); if (HAS_CDN_HASH_REGEX.test(source)) { const cachedResult = await cacache.get .info(RESOURCE_CACHE, cacheKey) @@ -61,6 +61,7 @@ export function rollupPluginDependencyCache({log}: {log: (url: string) => void}) return null; } const cacheKey = id.substring(CACHED_FILE_ID_PREFIX.length); + log(cacheKey); const cachedResult = await cacache.get(RESOURCE_CACHE, cacheKey); return cachedResult.data.toString('utf8'); }, diff --git a/test/integration/config-invalid/expected-output.txt b/test/integration/config-invalid/expected-output.txt index e492356a6b..f156fc5323 100644 --- a/test/integration/config-invalid/expected-output.txt +++ b/test/integration/config-invalid/expected-output.txt @@ -1,2 +1,2 @@ ⠼ snowpack installing... -✖ package.json: snowpack.webDependencies is not of a type(s) array \ No newline at end of file +✖ package.json: snowpack.webDependencies is not of a type(s) array,object \ No newline at end of file