From 158ee9a69c824b71b62cf987fe943a167f47f936 Mon Sep 17 00:00:00 2001 From: Anton Gilgur Date: Tue, 31 Dec 2019 13:28:28 -0500 Subject: [PATCH] (types/refactor): be more specific than 'any' in build code (#401) - add types for all options and use those types throughout the build/watch code - fix some incorrect types in a few places that became more obvious or errors once types were added - fix default target from 'web' (not an option) to 'browser' - extract createBuildConfigs into a separate file as it's fairly long and has some relatively complex code - and refactor it a bit to make it a bit easier to read as well as easier to type (and type cast) Co-authored-by: Jared Palmer --- src/createBuildConfigs.ts | 89 +++++++++++++++++++++++++++++++++ src/index.ts | 101 +++++++------------------------------- src/types.ts | 46 +++++++++++++---- 3 files changed, 145 insertions(+), 91 deletions(-) create mode 100644 src/createBuildConfigs.ts diff --git a/src/createBuildConfigs.ts b/src/createBuildConfigs.ts new file mode 100644 index 000000000..b53bdee54 --- /dev/null +++ b/src/createBuildConfigs.ts @@ -0,0 +1,89 @@ +import { RollupOptions, OutputOptions } from 'rollup'; +import * as fs from 'fs-extra'; +import { concatAllArray } from 'jpjs'; + +import { paths } from './constants'; +import { TsdxOptions, NormalizedOpts } from './types'; + +import { createRollupConfig } from './createRollupConfig'; + +// check for custom tsdx.config.js +let tsdxConfig = { + rollup(config: RollupOptions, _options: TsdxOptions): RollupOptions { + return config; + }, +}; + +if (fs.existsSync(paths.appConfig)) { + tsdxConfig = require(paths.appConfig); +} + +export async function createBuildConfigs( + opts: NormalizedOpts +): Promise> { + const allInputs = concatAllArray( + opts.input.map((input: string) => + createAllFormats(opts, input).map( + (options: TsdxOptions, index: number) => ({ + ...options, + // We want to know if this is the first run for each entryfile + // for certain plugins (e.g. css) + writeMeta: index === 0, + }) + ) + ) + ); + + return await Promise.all( + allInputs.map(async (options: TsdxOptions) => { + // pass the full rollup config to tsdx.config.js override + const config = await createRollupConfig(options); + return tsdxConfig.rollup(config, options); + }) + ); +} + +function createAllFormats( + opts: NormalizedOpts, + input: string +): [TsdxOptions, ...TsdxOptions[]] { + return [ + opts.format.includes('cjs') && { + ...opts, + format: 'cjs', + env: 'development', + input, + }, + opts.format.includes('cjs') && { + ...opts, + format: 'cjs', + env: 'production', + input, + }, + opts.format.includes('esm') && { ...opts, format: 'esm', input }, + opts.format.includes('umd') && { + ...opts, + format: 'umd', + env: 'development', + input, + }, + opts.format.includes('umd') && { + ...opts, + format: 'umd', + env: 'production', + input, + }, + opts.format.includes('system') && { + ...opts, + format: 'system', + env: 'development', + input, + }, + opts.format.includes('system') && { + ...opts, + format: 'system', + env: 'production', + input, + }, + ].filter(Boolean) as [TsdxOptions, ...TsdxOptions[]]; +} diff --git a/src/index.ts b/src/index.ts index 4b8e117ea..e176d8fc8 100755 --- a/src/index.ts +++ b/src/index.ts @@ -25,7 +25,7 @@ import shell from 'shelljs'; import ora from 'ora'; import { paths } from './constants'; import * as Messages from './messages'; -import { createRollupConfig } from './createRollupConfig'; +import { createBuildConfigs } from './createBuildConfigs'; import { createJestConfig } from './createJestConfig'; import { createEslintConfig } from './createEslintConfig'; import { resolveApp, safePackageName, clearConsole } from './utils'; @@ -33,7 +33,13 @@ import { concatAllArray } from 'jpjs'; import getInstallCmd from './getInstallCmd'; import getInstallArgs from './getInstallArgs'; import { Input, Select } from 'enquirer'; -import { PackageJson, TsdxOptions } from './types'; +import { + PackageJson, + WatchOpts, + BuildOpts, + ModuleFormat, + NormalizedOpts, +} from './types'; import { createProgressEstimator } from './createProgressEstimator'; import { templates } from './templates'; import { composePackageJson } from './templates/utils'; @@ -47,17 +53,6 @@ try { appPackageJson = fs.readJSONSync(paths.appPackageJson); } catch (e) {} -// check for custom tsdx.config.js -let tsdxConfig = { - rollup(config: RollupOptions, _options: TsdxOptions): RollupOptions { - return config; - }, -}; - -if (fs.existsSync(paths.appConfig)) { - tsdxConfig = require(paths.appConfig); -} - export const isDir = (name: string) => fs .stat(name) @@ -80,8 +75,11 @@ async function jsOrTs(filename: string) { return resolveApp(`${filename}${extension}`); } -async function getInputs(entries: string[], source?: string) { - let inputs: any[] = []; +async function getInputs( + entries?: string | string[], + source?: string +): Promise { + let inputs: string[] = []; let stub: any[] = []; stub .concat( @@ -96,67 +94,6 @@ async function getInputs(entries: string[], source?: string) { return concatAllArray(inputs); } -async function createBuildConfigs( - opts: any -): Promise> { - return await Promise.all( - concatAllArray( - opts.input.map((input: string) => - [ - opts.format.includes('cjs') && { - ...opts, - format: 'cjs', - env: 'development', - input, - }, - opts.format.includes('cjs') && { - ...opts, - format: 'cjs', - env: 'production', - input, - }, - opts.format.includes('esm') && { ...opts, format: 'esm', input }, - opts.format.includes('umd') && { - ...opts, - format: 'umd', - env: 'development', - input, - }, - opts.format.includes('umd') && { - ...opts, - format: 'umd', - env: 'production', - input, - }, - opts.format.includes('system') && { - ...opts, - format: 'system', - env: 'development', - input, - }, - opts.format.includes('system') && { - ...opts, - format: 'system', - env: 'production', - input, - }, - ] - .filter(Boolean) - .map((options: TsdxOptions, index: number) => ({ - ...options, - // We want to know if this is the first run for each entryfile - // for certain plugins (e.g. css) - writeMeta: index === 0, - })) - ) - ).map(async (options: TsdxOptions) => { - // pass the full rollup config to tsdx.config.js override - const config = await createRollupConfig(options); - return tsdxConfig.rollup(config, options); - }) - ); -} - async function moveTypes() { try { // Move the typescript types to the base of the ./dist folder @@ -320,7 +257,7 @@ prog .describe('Rebuilds on any change') .option('--entry, -i', 'Entry module(s)') .example('watch --entry src/foo.tsx') - .option('--target', 'Specify your target environment', 'web') + .option('--target', 'Specify your target environment', 'browser') .example('watch --target node') .option('--name', 'Specify name exposed in UMD builds') .example('watch --name Foo') @@ -346,7 +283,7 @@ prog .example('build --transpileOnly') .option('--extractErrors', 'Extract invariant errors to ./errors/codes.json.') .example('build --extractErrors') - .action(async (dirtyOpts: any) => { + .action(async (dirtyOpts: WatchOpts) => { const opts = await normalizeOpts(dirtyOpts); const buildConfigs = await createBuildConfigs(opts); if (!opts.noClean) { @@ -438,7 +375,7 @@ prog .describe('Build your project once and exit') .option('--entry, -i', 'Entry module(s)') .example('build --entry src/foo.tsx') - .option('--target', 'Specify your target environment', 'web') + .option('--target', 'Specify your target environment', 'browser') .example('build --target node') .option('--name', 'Specify name exposed in UMD builds') .example('build --name Foo') @@ -455,7 +392,7 @@ prog .example( 'build --extractErrors=https://reactjs.org/docs/error-decoder.html?invariant=' ) - .action(async (dirtyOpts: any) => { + .action(async (dirtyOpts: BuildOpts) => { const opts = await normalizeOpts(dirtyOpts); const buildConfigs = await createBuildConfigs(opts); await cleanDistFolder(); @@ -491,7 +428,7 @@ prog } }); -async function normalizeOpts(opts: any) { +async function normalizeOpts(opts: WatchOpts): Promise { return { ...opts, name: opts.name || appPackageJson.name, @@ -501,7 +438,7 @@ async function normalizeOpts(opts: any) { return 'esm'; } return format; - }), + }) as [ModuleFormat, ...ModuleFormat[]], }; } diff --git a/src/types.ts b/src/types.ts index 88a9a3a21..e5e92cc5f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,18 +1,46 @@ -export interface TsdxOptions { - // path to file - input: string; - // Name of package - name: string; +interface SharedOpts { // JS target target: 'node' | 'browser'; - // Module format - format: 'cjs' | 'umd' | 'esm' | 'system'; - // Environment - env: 'development' | 'production'; // Path to tsconfig file tsconfig?: string; // Is error extraction running? extractErrors?: boolean; +} + +export type ModuleFormat = 'cjs' | 'umd' | 'esm' | 'system'; + +export interface BuildOpts extends SharedOpts { + name?: string; + entry?: string | string[]; + format: 'cjs,esm'; + target: 'browser'; +} + +export interface WatchOpts extends BuildOpts { + verbose?: boolean; + noClean?: boolean; + // callback hooks + onFirstSuccess?: string; + onSuccess?: string; + onFailure?: string; +} + +export interface NormalizedOpts + extends Omit { + name: string; + input: string[]; + format: [ModuleFormat, ...ModuleFormat[]]; +} + +export interface TsdxOptions extends SharedOpts { + // Name of package + name: string; + // path to file + input: string; + // Environment + env: 'development' | 'production'; + // Module format + format: ModuleFormat; // Is minifying? minify?: boolean; // Is this the very first rollup config (and thus should one-off metadata be extracted)?