Skip to content

Commit

Permalink
add buildProject JS API, clean up config API (#1862)
Browse files Browse the repository at this point in the history
* add basic JS build API, clean up config API

* add build file output result
  • Loading branch information
FredKSchott committed Dec 9, 2020
1 parent 2e4195d commit 8d5290f
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 39 deletions.
2 changes: 2 additions & 0 deletions snowpack/index.esm.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import Pkg from './lib/index.js';

export const startDevServer = Pkg.startDevServer;
export const buildProject = Pkg.buildProject;
export const loadAndValidateConfig = Pkg.loadAndValidateConfig;
export const createConfiguration = Pkg.createConfiguration;
export const getUrlForFile = Pkg.getUrlForFile;
58 changes: 54 additions & 4 deletions snowpack/src/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ import {
CommandOptions,
ImportMap,
MountEntry,
OnFileChangeCallback,
SnowpackBuildResult,
SnowpackBuildResultFileManifest,
SnowpackConfig,
SnowpackSourceFile,
} from '../types/snowpack';
Expand Down Expand Up @@ -55,6 +58,19 @@ function handleFileError(err: Error, builder: FileBuilder) {
process.exit(1);
}

function createBuildFileManifest(allFiles: FileBuilder[]): SnowpackBuildResultFileManifest {
const result: SnowpackBuildResultFileManifest = {};
for (const sourceFile of allFiles) {
for (const outputFile of Object.entries(sourceFile.output)) {
result[outputFile[0]] = {
source: url.fileURLToPath(sourceFile.fileURL),
contents: outputFile[1],
};
}
}
return result;
}

async function installOptimizedDependencies(
scannedFiles: SnowpackSourceFile[],
installDest: string,
Expand Down Expand Up @@ -320,7 +336,7 @@ class FileBuilder {
}
}

export async function command(commandOptions: CommandOptions) {
export async function buildProject(commandOptions: CommandOptions): Promise<SnowpackBuildResult> {
const {config, lockfile} = commandOptions;
const isDev = !!config.buildOptions.watch;
const isSSR = !!config.experiments.ssr;
Expand Down Expand Up @@ -526,6 +542,8 @@ export async function command(commandOptions: CommandOptions) {
}
await parallelWorkQueue.onIdle();

const buildResultManifest = createBuildFileManifest(allBuildPipelineFiles);

// 5. Optimize the build.
if (!config.buildOptions.watch) {
if (config.experiments.optimize || config.plugins.some((p) => p.optimize)) {
Expand All @@ -548,7 +566,15 @@ export async function command(commandOptions: CommandOptions) {
}
await runPipelineCleanupStep(config);
logger.info(`${colors.underline(colors.green(colors.bold('▶ Build Complete!')))}\n\n`);
return;
return {
result: buildResultManifest,
onFileChange: () => {
throw new Error('buildProject().onFileChange() only supported in "watch" mode.');
},
shutdown: () => {
throw new Error('buildProject().shutdown() only supported in "watch" mode.');
},
};
}

// "--watch --hmr" mode - Tell users about the HMR WebSocket URL
Expand All @@ -572,6 +598,7 @@ export async function command(commandOptions: CommandOptions) {
if (!mountEntryResult) {
return;
}
onFileChangeCallback({filePath: fileLoc});
const [mountKey, mountEntry] = mountEntryResult;
const finalUrl = getUrlForFileMount({fileLoc, mountKey, mountEntry, config})!;
const finalDest = path.join(buildDirectoryLoc, finalUrl);
Expand Down Expand Up @@ -637,6 +664,29 @@ export async function command(commandOptions: CommandOptions) {
watcher.on('change', (fileLoc) => onWatchEvent(fileLoc));
watcher.on('unlink', (fileLoc) => onDeleteEvent(fileLoc));

// We intentionally never want to exit in watch mode!
return new Promise(() => {});
// Allow the user to hook into this callback, if they like (noop by default)
let onFileChangeCallback: OnFileChangeCallback = () => {};

return {
result: buildResultManifest,
onFileChange: (callback) => (onFileChangeCallback = callback),
async shutdown() {
await watcher.close();
},
};
}

export async function command(commandOptions: CommandOptions) {
try {
await buildProject(commandOptions);
} catch (err) {
logger.error(err.message);
logger.debug(err.stack);
process.exit(1);
}

if (commandOptions.config.buildOptions.watch) {
// We intentionally never want to exit in watch mode!
return new Promise(() => {});
}
}
4 changes: 2 additions & 2 deletions snowpack/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,7 @@ export function validatePluginLoadResult(
}

export function createConfiguration(
config: SnowpackUserConfig,
config: SnowpackUserConfig = {},
): [ValidatorResult['errors'], undefined] | [null, SnowpackConfig] {
const {errors: validationErrors} = validate(config, configSchema, {
propertyName: CONFIG_NAME,
Expand All @@ -903,7 +903,7 @@ export function createConfiguration(
return [null, normalizeConfig(mergedConfig)];
}

export function loadAndValidateConfig(flags: CLIFlags, pkgManifest: any): SnowpackConfig {
export function loadConfigurationForCLI(flags: CLIFlags, pkgManifest: any): SnowpackConfig {
const explorerSync = cosmiconfigSync(CONFIG_NAME, {
// only support these 5 types of config for now
searchPlaces: [
Expand Down
29 changes: 6 additions & 23 deletions snowpack/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,18 @@ import {command as initCommand} from './commands/init';
import {command as buildCommand} from './commands/build';
import {command as installCommand} from './commands/install';
import {command as devCommand} from './commands/dev';
import {loadAndValidateConfig} from './config.js';
import {logger} from './logger';
import {CLIFlags} from './types/snowpack';
import {loadConfigurationForCLI} from './config';
import {CLIFlags, CommandOptions} from './types/snowpack';
import {clearCache, readLockfile} from './util.js';
export {createConfiguration} from './config.js';
export * from './types/snowpack';

// Stable API (remember to include all in "./index.esm.js" wrapper)
export {startDevServer} from './commands/dev';
export {loadAndValidateConfig};
export {buildProject} from './commands/build';
export {loadConfigurationForCLI as loadAndValidateConfig, createConfiguration} from './config.js';
export {getUrlForFile} from './build/file-urls';

/** @deprecated: Promoted to startDevServer() **/
export const unstable__startDevServer = () => {
throw new Error(`[snowpack 2.15] unstable__startServer() is now startDevServer()`);
};
/** @deprecated: Promoted to loadAndValidateConfig() **/
export const unstable__loadAndValidateConfig = () => {
throw new Error(
`[snowpack 2.15] unstable__loadAndValidateConfig() is now loadAndValidateConfig()`,
);
};
/** @deprecated: Promoted to getUrlForFile() **/
export const unstable__getUrlForFile = () => {
throw new Error(`[snowpack 2.15] unstable__getUrlForFile() is now getUrlForFile()`);
};

const cwd = process.cwd();

function printHelp() {
Expand Down Expand Up @@ -112,16 +97,14 @@ export async function cli(args: string[]) {
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
}

const config = loadAndValidateConfig(cliFlags, pkgManifest);
const config = loadConfigurationForCLI(cliFlags, pkgManifest);
logger.debug(`config loaded: ${util.format(config)}`);
const lockfile = await readLockfile(cwd);
logger.debug(`lockfile ${lockfile ? 'loaded.' : 'not loaded'}`);
const commandOptions = {
const commandOptions: CommandOptions = {
cwd,
config,
lockfile,
pkgManifest,
logger,
};

if (cmd === 'add') {
Expand Down
10 changes: 2 additions & 8 deletions snowpack/src/sources/skypack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,7 @@ export default {

async load(
spec: string,
{
config,
lockfile,
pkgManifest,
}: {config: SnowpackConfig; lockfile: ImportMap | null; pkgManifest: any},
{config, lockfile}: {config: SnowpackConfig; lockfile: ImportMap | null},
): Promise<string> {
let body: string;
if (
Expand All @@ -74,9 +70,7 @@ export default {
} else if (lockfile && lockfile.imports[packageName + '/']) {
body = (await fetchCDN(lockfile.imports[packageName + '/'] + packagePath)).body;
} else {
const _packageSemver =
(config.webDependencies && config.webDependencies[packageName]) ||
(pkgManifest?.dependencies && pkgManifest.dependencies[packageName]);
const _packageSemver = config.webDependencies && config.webDependencies[packageName];
if (!_packageSemver) {
logFetching(packageName);
}
Expand Down
15 changes: 13 additions & 2 deletions snowpack/src/types/snowpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,17 @@ export interface SnowpackDevServer {
shutdown(): Promise<void>;
}

export type SnowpackBuildResultFileManifest = Record<
string,
{source: string; contents: string | Buffer}
>;

export interface SnowpackBuildResult {
result: SnowpackBuildResultFileManifest;
onFileChange: (callback: OnFileChangeCallback) => void;
shutdown(): Promise<void>;
}

export type SnowpackBuiltFile = {
code: string | Buffer;
map?: string;
Expand Down Expand Up @@ -299,10 +310,10 @@ export interface ImportMap {
}

export interface CommandOptions {
// TODO(fks): remove `cwd`, replace with a new `config.root` property on SnowpackConfig.
cwd: string;
config: SnowpackConfig;
lockfile: ImportMap | null;
pkgManifest: any;
}

export type LoggerLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent'; // same as Pino
Expand All @@ -328,7 +339,7 @@ export interface PackageSource {
*/
load(
spec: string,
options: {config: SnowpackConfig; lockfile: ImportMap | null; pkgManifest: any},
options: {config: SnowpackConfig; lockfile: ImportMap | null},
): Promise<Buffer | string>;
/** Resolve a package import to URL (ex: "react" -> "/web_modules/react") */
resolvePackageImport(spec: string, importMap: ImportMap, config: SnowpackConfig): string | false;
Expand Down

1 comment on commit 8d5290f

@vercel
Copy link

@vercel vercel bot commented on 8d5290f Dec 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.