From 8d4efd12b8b4b08c04d4750ad942279fd99f4d2e Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Thu, 3 Jun 2021 07:09:27 +0200 Subject: [PATCH 1/4] Reference types when normalizing options --- src/rollup/rollup.ts | 2 +- src/utils/options/normalizeInputOptions.ts | 100 ++++++------ src/utils/options/normalizeOutputOptions.ts | 161 ++++++++++---------- 3 files changed, 128 insertions(+), 135 deletions(-) diff --git a/src/rollup/rollup.ts b/src/rollup/rollup.ts index 235439dcb29..9d9f8a1119d 100644 --- a/src/rollup/rollup.ts +++ b/src/rollup/rollup.ts @@ -218,7 +218,7 @@ function getOutputOptions( setAssetSource: emitError }; } - ) as GenericConfigObject, + ), inputOptions, unsetInputOptions ); diff --git a/src/utils/options/normalizeInputOptions.ts b/src/utils/options/normalizeInputOptions.ts index 857095b9f22..63cf1059645 100644 --- a/src/utils/options/normalizeInputOptions.ts +++ b/src/utils/options/normalizeInputOptions.ts @@ -1,19 +1,13 @@ import * as acorn from 'acorn'; import { - ExternalOption, HasModuleSideEffects, - InputOption, InputOptions, - ManualChunksOption, ModuleSideEffectsOption, NormalizedInputOptions, PreserveEntrySignaturesOption, PureModulesOption, RollupBuild, - RollupCache, - TreeshakingOptions, - WarningHandler, - WarningHandlerWithDefault + WarningHandler } from '../../rollup/types'; import { ensureArray } from '../ensureArray'; import { errInvalidOption, warnDeprecationWithOptions } from '../error'; @@ -28,41 +22,40 @@ export interface CommandConfigObject { } export function normalizeInputOptions( - config: GenericConfigObject + config: InputOptions ): { options: NormalizedInputOptions; unsetOptions: Set } { // These are options that may trigger special warnings or behaviour later // if the user did not select an explicit value const unsetOptions = new Set(); - const context = (config.context as string | undefined) ?? 'undefined'; + const context = config.context ?? 'undefined'; const onwarn = getOnwarn(config); - const strictDeprecations = (config.strictDeprecations as boolean | undefined) || false; + const strictDeprecations = config.strictDeprecations || false; const options: NormalizedInputOptions & InputOptions = { - acorn: (getAcorn(config) as unknown) as Record, + acorn: (getAcorn(config) as unknown) as NormalizedInputOptions['acorn'], acornInjectPlugins: getAcornInjectPlugins(config), cache: getCache(config), context, - experimentalCacheExpiry: (config.experimentalCacheExpiry as number | undefined) ?? 10, - external: getIdMatcher(config.external as ExternalOption), + experimentalCacheExpiry: config.experimentalCacheExpiry ?? 10, + external: getIdMatcher(config.external), inlineDynamicImports: getInlineDynamicImports(config, onwarn, strictDeprecations), input: getInput(config), - makeAbsoluteExternalsRelative: - (config.makeAbsoluteExternalsRelative as boolean | 'ifRelativeSource' | undefined) ?? true, + makeAbsoluteExternalsRelative: config.makeAbsoluteExternalsRelative ?? true, manualChunks: getManualChunks(config, onwarn, strictDeprecations), moduleContext: getModuleContext(config, context), onwarn, - perf: (config.perf as boolean | undefined) || false, - plugins: ensureArray(config.plugins) as Plugin[], + perf: config.perf || false, + plugins: ensureArray(config.plugins), preserveEntrySignatures: getPreserveEntrySignatures(config, unsetOptions), preserveModules: getPreserveModules(config, onwarn, strictDeprecations), - preserveSymlinks: (config.preserveSymlinks as boolean | undefined) || false, - shimMissingExports: (config.shimMissingExports as boolean | undefined) || false, + preserveSymlinks: config.preserveSymlinks || false, + shimMissingExports: config.shimMissingExports || false, strictDeprecations, treeshake: getTreeshake(config, onwarn, strictDeprecations) }; warnUnknownOptions( - config, + config as GenericConfigObject, [...Object.keys(options), 'watch'], 'input options', options.onwarn, @@ -71,8 +64,9 @@ export function normalizeInputOptions( return { options, unsetOptions }; } -const getOnwarn = (config: GenericConfigObject): WarningHandler => { - return config.onwarn +const getOnwarn = (config: InputOptions): NormalizedInputOptions['onwarn'] => { + const { onwarn } = config; + return onwarn ? warning => { warning.toString = () => { let str = ''; @@ -84,25 +78,25 @@ const getOnwarn = (config: GenericConfigObject): WarningHandler => { return str; }; - (config.onwarn as WarningHandlerWithDefault)(warning, defaultOnWarn); + onwarn(warning, defaultOnWarn); } : defaultOnWarn; }; -const getAcorn = (config: GenericConfigObject): acorn.Options => ({ +const getAcorn = (config: InputOptions): acorn.Options => ({ allowAwaitOutsideFunction: true, ecmaVersion: 'latest', preserveParens: false, sourceType: 'module', - ...(config.acorn as Record) + ...config.acorn }); -const getAcornInjectPlugins = (config: GenericConfigObject): (() => unknown)[] => - ensureArray(config.acornInjectPlugins) as any; +const getAcornInjectPlugins = ( + config: InputOptions +): NormalizedInputOptions['acornInjectPlugins'] => ensureArray(config.acornInjectPlugins); -const getCache = (config: GenericConfigObject): false | undefined | RollupCache => { - return (config.cache as RollupBuild)?.cache || (config.cache as false | undefined | RollupCache); -}; +const getCache = (config: InputOptions): NormalizedInputOptions['cache'] => + ((config.cache as unknown) as RollupBuild)?.cache || config.cache; const getIdMatcher = >( option: @@ -135,11 +129,11 @@ const getIdMatcher = >( }; const getInlineDynamicImports = ( - config: GenericConfigObject, + config: InputOptions, warn: WarningHandler, strictDeprecations: boolean -): boolean | undefined => { - const configInlineDynamicImports = config.inlineDynamicImports as boolean | undefined; +): NormalizedInputOptions['inlineDynamicImports'] => { + const configInlineDynamicImports = config.inlineDynamicImports; if (configInlineDynamicImports) { warnDeprecationWithOptions( 'The "inlineDynamicImports" option is deprecated. Use the "output.inlineDynamicImports" option instead.', @@ -151,17 +145,17 @@ const getInlineDynamicImports = ( return configInlineDynamicImports; }; -const getInput = (config: GenericConfigObject): string[] | { [entryAlias: string]: string } => { - const configInput = config.input as InputOption | undefined; +const getInput = (config: InputOptions): NormalizedInputOptions['input'] => { + const configInput = config.input; return configInput == null ? [] : typeof configInput === 'string' ? [configInput] : configInput; }; const getManualChunks = ( - config: GenericConfigObject, + config: InputOptions, warn: WarningHandler, strictDeprecations: boolean -): ManualChunksOption | undefined => { - const configManualChunks = config.manualChunks as ManualChunksOption | undefined; +): NormalizedInputOptions['manualChunks'] => { + const configManualChunks = config.manualChunks; if (configManualChunks) { warnDeprecationWithOptions( 'The "manualChunks" option is deprecated. Use the "output.manualChunks" option instead.', @@ -174,9 +168,9 @@ const getManualChunks = ( }; const getModuleContext = ( - config: GenericConfigObject, + config: InputOptions, context: string -): ((id: string) => string) => { +): NormalizedInputOptions['moduleContext'] => { const configModuleContext = config.moduleContext as | ((id: string) => string | null | undefined) | { [id: string]: string } @@ -195,9 +189,9 @@ const getModuleContext = ( }; const getPreserveEntrySignatures = ( - config: GenericConfigObject, + config: InputOptions, unsetOptions: Set -): PreserveEntrySignaturesOption => { +): NormalizedInputOptions['preserveEntrySignatures'] => { const configPreserveEntrySignatures = config.preserveEntrySignatures as | PreserveEntrySignaturesOption | undefined; @@ -208,11 +202,11 @@ const getPreserveEntrySignatures = ( }; const getPreserveModules = ( - config: GenericConfigObject, + config: InputOptions, warn: WarningHandler, strictDeprecations: boolean -): boolean | undefined => { - const configPreserveModules = config.preserveModules as boolean | undefined; +): NormalizedInputOptions['preserveModules'] => { + const configPreserveModules = config.preserveModules; if (configPreserveModules) { warnDeprecationWithOptions( 'The "preserveModules" option is deprecated. Use the "output.preserveModules" option instead.', @@ -225,23 +219,15 @@ const getPreserveModules = ( }; const getTreeshake = ( - config: GenericConfigObject, + config: InputOptions, warn: WarningHandler, strictDeprecations: boolean -): - | false - | { - annotations: boolean; - moduleSideEffects: HasModuleSideEffects; - propertyReadSideEffects: boolean | 'always'; - tryCatchDeoptimization: boolean; - unknownGlobalSideEffects: boolean; - } => { - const configTreeshake = config.treeshake as boolean | TreeshakingOptions; +): NormalizedInputOptions['treeshake'] => { + const configTreeshake = config.treeshake; if (configTreeshake === false) { return false; } - if (configTreeshake && configTreeshake !== true) { + if (configTreeshake && typeof configTreeshake === 'object') { if (typeof configTreeshake.pureExternalModules !== 'undefined') { warnDeprecationWithOptions( `The "treeshake.pureExternalModules" option is deprecated. The "treeshake.moduleSideEffects" option should be used instead. "treeshake.pureExternalModules: true" is equivalent to "treeshake.moduleSideEffects: 'no-external'"`, diff --git a/src/utils/options/normalizeOutputOptions.ts b/src/utils/options/normalizeOutputOptions.ts index a67860d0ef8..00d12056289 100644 --- a/src/utils/options/normalizeOutputOptions.ts +++ b/src/utils/options/normalizeOutputOptions.ts @@ -1,13 +1,8 @@ import { - GetInterop, - GlobalsOption, InternalModuleFormat, InteropType, - ManualChunksOption, - ModuleFormat, NormalizedInputOptions, NormalizedOutputOptions, - OptionsPaths, OutputOptions, SourcemapPathTransformOption } from '../../rollup/types'; @@ -18,7 +13,7 @@ import { sanitizeFileName as defaultSanitizeFileName } from '../sanitizeFileName import { GenericConfigObject, warnUnknownOptions } from './options'; export function normalizeOutputOptions( - config: GenericConfigObject, + config: OutputOptions, inputOptions: NormalizedInputOptions, unsetInputOptions: Set ): { options: NormalizedOutputOptions; unsetOptions: Set } { @@ -26,7 +21,7 @@ export function normalizeOutputOptions( // if the user did not select an explicit value const unsetOptions = new Set(unsetInputOptions); - const compact = (config.compact as boolean | undefined) || false; + const compact = config.compact || false; const format = getFormat(config); const inlineDynamicImports = getInlineDynamicImports(config, inputOptions); const preserveModules = getPreserveModules(config, inlineDynamicImports, inputOptions); @@ -34,65 +29,70 @@ export function normalizeOutputOptions( const outputOptions: NormalizedOutputOptions & OutputOptions = { amd: getAmd(config), - assetFileNames: - (config.assetFileNames as string | undefined) ?? 'assets/[name]-[hash][extname]', + assetFileNames: config.assetFileNames ?? 'assets/[name]-[hash][extname]', banner: getAddon(config, 'banner'), - chunkFileNames: (config.chunkFileNames as string | undefined) ?? '[name]-[hash].js', + chunkFileNames: config.chunkFileNames ?? '[name]-[hash].js', compact, dir: getDir(config, file), dynamicImportFunction: getDynamicImportFunction(config, inputOptions), entryFileNames: getEntryFileNames(config, unsetOptions), - esModule: (config.esModule as boolean | undefined) ?? true, + esModule: config.esModule ?? true, exports: getExports(config, unsetOptions), - extend: (config.extend as boolean | undefined) || false, - externalLiveBindings: (config.externalLiveBindings as boolean | undefined) ?? true, + extend: config.extend || false, + externalLiveBindings: config.externalLiveBindings ?? true, file, footer: getAddon(config, 'footer'), format, - freeze: (config.freeze as boolean | undefined) ?? true, - globals: (config.globals as GlobalsOption | undefined) || {}, - hoistTransitiveImports: (config.hoistTransitiveImports as boolean | undefined) ?? true, + freeze: config.freeze ?? true, + globals: config.globals || {}, + hoistTransitiveImports: config.hoistTransitiveImports ?? true, indent: getIndent(config, compact), inlineDynamicImports, interop: getInterop(config, inputOptions), intro: getAddon(config, 'intro'), manualChunks: getManualChunks(config, inlineDynamicImports, preserveModules, inputOptions), minifyInternalExports: getMinifyInternalExports(config, format, compact), - name: config.name as string | undefined, - namespaceToStringTag: (config.namespaceToStringTag as boolean | undefined) || false, - noConflict: (config.noConflict as boolean | undefined) || false, + name: config.name, + namespaceToStringTag: config.namespaceToStringTag || false, + noConflict: config.noConflict || false, outro: getAddon(config, 'outro'), - paths: (config.paths as OptionsPaths | undefined) || {}, - plugins: ensureArray(config.plugins) as Plugin[], - preferConst: (config.preferConst as boolean | undefined) || false, + paths: config.paths || {}, + plugins: ensureArray(config.plugins), + preferConst: config.preferConst || false, preserveModules, preserveModulesRoot: getPreserveModulesRoot(config), - sanitizeFileName: (typeof config.sanitizeFileName === 'function' - ? config.sanitizeFileName - : config.sanitizeFileName === false - ? id => id - : defaultSanitizeFileName) as NormalizedOutputOptions['sanitizeFileName'], - sourcemap: (config.sourcemap as boolean | 'inline' | 'hidden' | undefined) || false, - sourcemapExcludeSources: (config.sourcemapExcludeSources as boolean | undefined) || false, - sourcemapFile: config.sourcemapFile as string | undefined, + sanitizeFileName: + typeof config.sanitizeFileName === 'function' + ? config.sanitizeFileName + : config.sanitizeFileName === false + ? id => id + : defaultSanitizeFileName, + sourcemap: config.sourcemap || false, + sourcemapExcludeSources: config.sourcemapExcludeSources || false, + sourcemapFile: config.sourcemapFile, sourcemapPathTransform: config.sourcemapPathTransform as | SourcemapPathTransformOption | undefined, - strict: (config.strict as boolean | undefined) ?? true, - systemNullSetters: (config.systemNullSetters as boolean | undefined) || false, - validate: (config.validate as boolean | undefined) || false + strict: config.strict ?? true, + systemNullSetters: config.systemNullSetters || false, + validate: config.validate || false }; - warnUnknownOptions(config, Object.keys(outputOptions), 'output options', inputOptions.onwarn); + warnUnknownOptions( + config as GenericConfigObject, + Object.keys(outputOptions), + 'output options', + inputOptions.onwarn + ); return { options: outputOptions, unsetOptions }; } const getFile = ( - config: GenericConfigObject, + config: OutputOptions, preserveModules: boolean, inputOptions: NormalizedInputOptions -): string | undefined => { - const file = config.file as string | undefined; +): NormalizedOutputOptions['file'] => { + const { file } = config; if (typeof file === 'string') { if (preserveModules) { return error({ @@ -110,8 +110,8 @@ const getFile = ( return file; }; -const getFormat = (config: GenericConfigObject): InternalModuleFormat => { - const configFormat = config.format as ModuleFormat | undefined; +const getFormat = (config: OutputOptions): NormalizedOutputOptions['format'] => { + const configFormat = config.format; switch (configFormat) { case undefined: case 'es': @@ -137,12 +137,11 @@ const getFormat = (config: GenericConfigObject): InternalModuleFormat => { }; const getInlineDynamicImports = ( - config: GenericConfigObject, + config: OutputOptions, inputOptions: NormalizedInputOptions -): boolean => { +): NormalizedOutputOptions['inlineDynamicImports'] => { const inlineDynamicImports = - ((config.inlineDynamicImports as boolean | undefined) ?? inputOptions.inlineDynamicImports) || - false; + (config.inlineDynamicImports ?? inputOptions.inlineDynamicImports) || false; const { input } = inputOptions; if (inlineDynamicImports && (Array.isArray(input) ? input : Object.keys(input)).length > 1) { return error({ @@ -154,12 +153,11 @@ const getInlineDynamicImports = ( }; const getPreserveModules = ( - config: GenericConfigObject, + config: OutputOptions, inlineDynamicImports: boolean, inputOptions: NormalizedInputOptions -): boolean => { - const preserveModules = - ((config.preserveModules as boolean | undefined) ?? inputOptions.preserveModules) || false; +): NormalizedOutputOptions['preserveModules'] => { + const preserveModules = (config.preserveModules ?? inputOptions.preserveModules) || false; if (preserveModules) { if (inlineDynamicImports) { return error({ @@ -178,20 +176,22 @@ const getPreserveModules = ( return preserveModules; }; -const getPreserveModulesRoot = (config: GenericConfigObject): string | undefined => { - const preserveModulesRoot = config.preserveModulesRoot as string | null | undefined; +const getPreserveModulesRoot = ( + config: OutputOptions +): NormalizedOutputOptions['preserveModulesRoot'] => { + const { preserveModulesRoot } = config; if (preserveModulesRoot === null || preserveModulesRoot === undefined) { return undefined; } return resolve(preserveModulesRoot); }; -const getAmd = (config: GenericConfigObject): NormalizedOutputOptions['amd'] => { +const getAmd = (config: OutputOptions): NormalizedOutputOptions['amd'] => { const collection: { autoId: boolean; basePath: string; define: string; id?: string } = { autoId: false, basePath: '', define: 'define', - ...(config.amd as OutputOptions['amd']) + ...config.amd }; if ((collection.autoId || collection.basePath) && collection.id) { @@ -225,16 +225,21 @@ const getAmd = (config: GenericConfigObject): NormalizedOutputOptions['amd'] => return normalized; }; -const getAddon = (config: GenericConfigObject, name: string): (() => string | Promise) => { - const configAddon = config[name] as string | (() => string | Promise); +const getAddon = (config: OutputOptions, name: string): (() => string | Promise) => { + const configAddon = (config as GenericConfigObject)[name] as + | string + | (() => string | Promise); if (typeof configAddon === 'function') { return configAddon; } return () => configAddon || ''; }; -const getDir = (config: GenericConfigObject, file: string | undefined): string | undefined => { - const dir = config.dir as string | undefined; +const getDir = ( + config: OutputOptions, + file: string | undefined +): NormalizedOutputOptions['dir'] => { + const { dir } = config; if (typeof dir === 'string' && typeof file === 'string') { return error({ code: 'INVALID_OPTION', @@ -246,10 +251,10 @@ const getDir = (config: GenericConfigObject, file: string | undefined): string | }; const getDynamicImportFunction = ( - config: GenericConfigObject, + config: OutputOptions, inputOptions: NormalizedInputOptions -): string | undefined => { - const configDynamicImportFunction = config.dynamicImportFunction as string | undefined; +): NormalizedOutputOptions['dynamicImportFunction'] => { + const configDynamicImportFunction = config.dynamicImportFunction; if (configDynamicImportFunction) { warnDeprecation( `The "output.dynamicImportFunction" option is deprecated. Use the "renderDynamicImport" plugin hook instead.`, @@ -260,8 +265,11 @@ const getDynamicImportFunction = ( return configDynamicImportFunction; }; -const getEntryFileNames = (config: GenericConfigObject, unsetOptions: Set): string => { - const configEntryFileNames = config.entryFileNames as string | undefined; +const getEntryFileNames = ( + config: OutputOptions, + unsetOptions: Set +): NormalizedOutputOptions['entryFileNames'] => { + const configEntryFileNames = config.entryFileNames; if (configEntryFileNames == null) { unsetOptions.add('entryFileNames'); } @@ -269,32 +277,33 @@ const getEntryFileNames = (config: GenericConfigObject, unsetOptions: Set -): 'default' | 'named' | 'none' | 'auto' { - const configExports = config.exports as string | undefined; +): NormalizedOutputOptions['exports'] { + const configExports = config.exports; if (configExports == null) { unsetOptions.add('exports'); } else if (!['default', 'named', 'none', 'auto'].includes(configExports)) { return error(errInvalidExportOptionValue(configExports)); } - return (configExports as 'default' | 'named' | 'none' | 'auto') || 'auto'; + return configExports || 'auto'; } -const getIndent = (config: GenericConfigObject, compact: boolean): string | true => { +const getIndent = (config: OutputOptions, compact: boolean): NormalizedOutputOptions['indent'] => { if (compact) { return ''; } - const configIndent = config.indent as string | boolean | undefined; + const configIndent = config.indent; return configIndent === false ? '' : configIndent ?? true; }; const ALLOWED_INTEROP_TYPES = new Set(['auto', 'esModule', 'default', 'defaultOnly', true, false]); + const getInterop = ( - config: GenericConfigObject, + config: OutputOptions, inputOptions: NormalizedInputOptions -): GetInterop => { - const configInterop = config.interop as InteropType | GetInterop | undefined; +): NormalizedOutputOptions['interop'] => { + const configInterop = config.interop; const validatedInteropTypes = new Set(); const validateInterop = (interop: InteropType): InteropType => { if (!validatedInteropTypes.has(interop)) { @@ -341,13 +350,12 @@ const getInterop = ( }; const getManualChunks = ( - config: GenericConfigObject, + config: OutputOptions, inlineDynamicImports: boolean, preserveModules: boolean, inputOptions: NormalizedInputOptions -): ManualChunksOption => { - const configManualChunks = - (config.manualChunks as ManualChunksOption | undefined) || inputOptions.manualChunks; +): NormalizedOutputOptions['manualChunks'] => { + const configManualChunks = config.manualChunks || inputOptions.manualChunks; if (configManualChunks) { if (inlineDynamicImports) { return error({ @@ -367,9 +375,8 @@ const getManualChunks = ( }; const getMinifyInternalExports = ( - config: GenericConfigObject, + config: OutputOptions, format: InternalModuleFormat, compact: boolean -): boolean => - (config.minifyInternalExports as boolean | undefined) ?? - (compact || format === 'es' || format === 'system'); +): NormalizedOutputOptions['minifyInternalExports'] => + config.minifyInternalExports ?? (compact || format === 'es' || format === 'system'); From b6be32c2d0ba57ff085a73916591bd09dc83500f Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Thu, 3 Jun 2021 08:09:04 +0200 Subject: [PATCH 2/4] Add string presets for the treeshake option --- src/rollup/types.d.ts | 2 +- src/utils/options/mergeOptions.ts | 3 ++ src/utils/options/normalizeInputOptions.ts | 53 +++++++++++-------- .../treeshake-presets/safest/_config.js | 22 ++++++++ .../treeshake-presets/safest/_expected.js | 15 ++++++ .../samples/treeshake-presets/safest/dep.js | 1 + .../samples/treeshake-presets/safest/main.js | 15 ++++++ .../treeshake-presets/smallest/_config.js | 22 ++++++++ .../treeshake-presets/smallest/_expected.js | 1 + .../samples/treeshake-presets/smallest/dep.js | 1 + .../treeshake-presets/smallest/main.js | 15 ++++++ .../samples/treeshake-presets/true/_config.js | 22 ++++++++ .../treeshake-presets/true/_expected.js | 15 ++++++ .../samples/treeshake-presets/true/dep.js | 1 + .../samples/treeshake-presets/true/main.js | 15 ++++++ 15 files changed, 181 insertions(+), 22 deletions(-) create mode 100644 test/form/samples/treeshake-presets/safest/_config.js create mode 100644 test/form/samples/treeshake-presets/safest/_expected.js create mode 100644 test/form/samples/treeshake-presets/safest/dep.js create mode 100644 test/form/samples/treeshake-presets/safest/main.js create mode 100644 test/form/samples/treeshake-presets/smallest/_config.js create mode 100644 test/form/samples/treeshake-presets/smallest/_expected.js create mode 100644 test/form/samples/treeshake-presets/smallest/dep.js create mode 100644 test/form/samples/treeshake-presets/smallest/main.js create mode 100644 test/form/samples/treeshake-presets/true/_config.js create mode 100644 test/form/samples/treeshake-presets/true/_expected.js create mode 100644 test/form/samples/treeshake-presets/true/dep.js create mode 100644 test/form/samples/treeshake-presets/true/main.js diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index 00cc25bf187..0a42f741e99 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -541,7 +541,7 @@ export interface InputOptions { preserveSymlinks?: boolean; shimMissingExports?: boolean; strictDeprecations?: boolean; - treeshake?: boolean | TreeshakingOptions; + treeshake?: boolean | 'smallest' | 'safest' | TreeshakingOptions; watch?: WatcherOptions | false; } diff --git a/src/utils/options/mergeOptions.ts b/src/utils/options/mergeOptions.ts index 4543df8d69a..8c37e6d3f22 100644 --- a/src/utils/options/mergeOptions.ts +++ b/src/utils/options/mergeOptions.ts @@ -120,6 +120,9 @@ function mergeInputOptions( preserveSymlinks: getOption('preserveSymlinks'), shimMissingExports: getOption('shimMissingExports'), strictDeprecations: getOption('strictDeprecations'), + // TODO Lukas implement "preset" form + // TODO Lukas command line string usage overrides this option + // TODO Lukas config strings are changed to the "preset" form treeshake: getObjectOption(config, overrides, 'treeshake'), watch: getWatch(config, overrides, 'watch') }; diff --git a/src/utils/options/normalizeInputOptions.ts b/src/utils/options/normalizeInputOptions.ts index 63cf1059645..1ee24774855 100644 --- a/src/utils/options/normalizeInputOptions.ts +++ b/src/utils/options/normalizeInputOptions.ts @@ -227,28 +227,39 @@ const getTreeshake = ( if (configTreeshake === false) { return false; } - if (configTreeshake && typeof configTreeshake === 'object') { - if (typeof configTreeshake.pureExternalModules !== 'undefined') { - warnDeprecationWithOptions( - `The "treeshake.pureExternalModules" option is deprecated. The "treeshake.moduleSideEffects" option should be used instead. "treeshake.pureExternalModules: true" is equivalent to "treeshake.moduleSideEffects: 'no-external'"`, - true, - warn, - strictDeprecations - ); + if (configTreeshake) { + if (typeof configTreeshake === 'object') { + if (typeof configTreeshake.pureExternalModules !== 'undefined') { + warnDeprecationWithOptions( + `The "treeshake.pureExternalModules" option is deprecated. The "treeshake.moduleSideEffects" option should be used instead. "treeshake.pureExternalModules: true" is equivalent to "treeshake.moduleSideEffects: 'no-external'"`, + true, + warn, + strictDeprecations + ); + } + return { + annotations: configTreeshake.annotations !== false, + moduleSideEffects: getHasModuleSideEffects( + configTreeshake.moduleSideEffects, + configTreeshake.pureExternalModules, + warn + ), + propertyReadSideEffects: + (configTreeshake.propertyReadSideEffects === 'always' && 'always') || + configTreeshake.propertyReadSideEffects !== false, + tryCatchDeoptimization: configTreeshake.tryCatchDeoptimization !== false, + unknownGlobalSideEffects: configTreeshake.unknownGlobalSideEffects !== false + }; + } + if (configTreeshake === 'smallest') { + return { + annotations: true, + moduleSideEffects: () => false, + propertyReadSideEffects: false, + tryCatchDeoptimization: false, + unknownGlobalSideEffects: false + }; } - return { - annotations: configTreeshake.annotations !== false, - moduleSideEffects: getHasModuleSideEffects( - configTreeshake.moduleSideEffects, - configTreeshake.pureExternalModules, - warn - ), - propertyReadSideEffects: - (configTreeshake.propertyReadSideEffects === 'always' && 'always') || - configTreeshake.propertyReadSideEffects !== false, - tryCatchDeoptimization: configTreeshake.tryCatchDeoptimization !== false, - unknownGlobalSideEffects: configTreeshake.unknownGlobalSideEffects !== false - }; } return { annotations: true, diff --git a/test/form/samples/treeshake-presets/safest/_config.js b/test/form/samples/treeshake-presets/safest/_config.js new file mode 100644 index 00000000000..d95a982ec8b --- /dev/null +++ b/test/form/samples/treeshake-presets/safest/_config.js @@ -0,0 +1,22 @@ +const assert = require('assert'); +const path = require('path'); + +module.exports = { + description: 'handles treeshake preset "safest""', + options: { + treeshake: 'safest', + plugins: [ + { + buildStart(options) { + assert.strictEqual(options.treeshake.propertyReadSideEffects, true); + assert.strictEqual(options.treeshake.tryCatchDeoptimization, true); + assert.strictEqual(options.treeshake.unknownGlobalSideEffects, true); + assert.strictEqual( + options.treeshake.moduleSideEffects(path.join(__dirname, 'dep.js')), + true + ); + } + } + ] + } +}; diff --git a/test/form/samples/treeshake-presets/safest/_expected.js b/test/form/samples/treeshake-presets/safest/_expected.js new file mode 100644 index 00000000000..3df383b997e --- /dev/null +++ b/test/form/samples/treeshake-presets/safest/_expected.js @@ -0,0 +1,15 @@ +console.log('dep'); + +console.log('main'); + +({ + get foo() { + console.log('effect'); + } +}.foo); + +try { + const noeffect = 1; +} catch {} + +unknownGlobal; diff --git a/test/form/samples/treeshake-presets/safest/dep.js b/test/form/samples/treeshake-presets/safest/dep.js new file mode 100644 index 00000000000..b74a9837c07 --- /dev/null +++ b/test/form/samples/treeshake-presets/safest/dep.js @@ -0,0 +1 @@ +console.log('dep'); diff --git a/test/form/samples/treeshake-presets/safest/main.js b/test/form/samples/treeshake-presets/safest/main.js new file mode 100644 index 00000000000..2ef8f761fe7 --- /dev/null +++ b/test/form/samples/treeshake-presets/safest/main.js @@ -0,0 +1,15 @@ +import './dep.js'; + +console.log('main'); + +({ + get foo() { + console.log('effect'); + } +}.foo); + +try { + const noeffect = 1; +} catch {} + +unknownGlobal; diff --git a/test/form/samples/treeshake-presets/smallest/_config.js b/test/form/samples/treeshake-presets/smallest/_config.js new file mode 100644 index 00000000000..ac49dae5a46 --- /dev/null +++ b/test/form/samples/treeshake-presets/smallest/_config.js @@ -0,0 +1,22 @@ +const assert = require('assert'); +const path = require('path'); + +module.exports = { + description: 'handles treeshake preset "smallest"', + options: { + treeshake: 'smallest', + plugins: [ + { + buildStart(options) { + assert.strictEqual(options.treeshake.propertyReadSideEffects, false); + assert.strictEqual(options.treeshake.tryCatchDeoptimization, false); + assert.strictEqual(options.treeshake.unknownGlobalSideEffects, false); + assert.strictEqual( + options.treeshake.moduleSideEffects(path.join(__dirname, 'dep.js')), + false + ); + } + } + ] + } +}; diff --git a/test/form/samples/treeshake-presets/smallest/_expected.js b/test/form/samples/treeshake-presets/smallest/_expected.js new file mode 100644 index 00000000000..c0b933d7b56 --- /dev/null +++ b/test/form/samples/treeshake-presets/smallest/_expected.js @@ -0,0 +1 @@ +console.log('main'); diff --git a/test/form/samples/treeshake-presets/smallest/dep.js b/test/form/samples/treeshake-presets/smallest/dep.js new file mode 100644 index 00000000000..b74a9837c07 --- /dev/null +++ b/test/form/samples/treeshake-presets/smallest/dep.js @@ -0,0 +1 @@ +console.log('dep'); diff --git a/test/form/samples/treeshake-presets/smallest/main.js b/test/form/samples/treeshake-presets/smallest/main.js new file mode 100644 index 00000000000..2ef8f761fe7 --- /dev/null +++ b/test/form/samples/treeshake-presets/smallest/main.js @@ -0,0 +1,15 @@ +import './dep.js'; + +console.log('main'); + +({ + get foo() { + console.log('effect'); + } +}.foo); + +try { + const noeffect = 1; +} catch {} + +unknownGlobal; diff --git a/test/form/samples/treeshake-presets/true/_config.js b/test/form/samples/treeshake-presets/true/_config.js new file mode 100644 index 00000000000..9a024352632 --- /dev/null +++ b/test/form/samples/treeshake-presets/true/_config.js @@ -0,0 +1,22 @@ +const assert = require('assert'); +const path = require('path'); + +module.exports = { + description: 'handles treeshake preset true', + options: { + treeshake: true, + plugins: [ + { + buildStart(options) { + assert.strictEqual(options.treeshake.propertyReadSideEffects, true); + assert.strictEqual(options.treeshake.tryCatchDeoptimization, true); + assert.strictEqual(options.treeshake.unknownGlobalSideEffects, true); + assert.strictEqual( + options.treeshake.moduleSideEffects(path.join(__dirname, 'dep.js')), + true + ); + } + } + ] + } +}; diff --git a/test/form/samples/treeshake-presets/true/_expected.js b/test/form/samples/treeshake-presets/true/_expected.js new file mode 100644 index 00000000000..3df383b997e --- /dev/null +++ b/test/form/samples/treeshake-presets/true/_expected.js @@ -0,0 +1,15 @@ +console.log('dep'); + +console.log('main'); + +({ + get foo() { + console.log('effect'); + } +}.foo); + +try { + const noeffect = 1; +} catch {} + +unknownGlobal; diff --git a/test/form/samples/treeshake-presets/true/dep.js b/test/form/samples/treeshake-presets/true/dep.js new file mode 100644 index 00000000000..b74a9837c07 --- /dev/null +++ b/test/form/samples/treeshake-presets/true/dep.js @@ -0,0 +1 @@ +console.log('dep'); diff --git a/test/form/samples/treeshake-presets/true/main.js b/test/form/samples/treeshake-presets/true/main.js new file mode 100644 index 00000000000..2ef8f761fe7 --- /dev/null +++ b/test/form/samples/treeshake-presets/true/main.js @@ -0,0 +1,15 @@ +import './dep.js'; + +console.log('main'); + +({ + get foo() { + console.log('effect'); + } +}.foo); + +try { + const noeffect = 1; +} catch {} + +unknownGlobal; From 47d3139a66a832484bee809ce61aba692ccd100b Mon Sep 17 00:00:00 2001 From: rxliuli Date: Sun, 6 Jun 2021 12:29:46 +0800 Subject: [PATCH 3/4] feat: Export define defines the auxiliary function of the configuration --- src/rollup/rollup.ts | 12 +++++++++++- src/rollup/types.d.ts | 5 ++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/rollup/rollup.ts b/src/rollup/rollup.ts index 9d9f8a1119d..f956f5e863d 100644 --- a/src/rollup/rollup.ts +++ b/src/rollup/rollup.ts @@ -20,6 +20,7 @@ import { OutputOptions, Plugin, RollupBuild, + RollupOptions, RollupOutput, RollupWatcher } from './types'; @@ -218,7 +219,7 @@ function getOutputOptions( setAssetSource: emitError }; } - ), + ) as GenericConfigObject, inputOptions, unsetInputOptions ); @@ -282,3 +283,12 @@ function writeOutputFile( return Promise.all([writeFile(fileName, source), writeSourceMapPromise]); } + +/** + * Auxiliary function for defining rollup configuration + * Mainly to facilitate IDE code prompts, after all, export default does not prompt, even if you add @type annotations, it is not accurate + * @param options + */ +export function define(options: T): T { + return options; +} diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index 0a42f741e99..cb2e10f4844 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -541,7 +541,7 @@ export interface InputOptions { preserveSymlinks?: boolean; shimMissingExports?: boolean; strictDeprecations?: boolean; - treeshake?: boolean | 'smallest' | 'safest' | TreeshakingOptions; + treeshake?: boolean | TreeshakingOptions; watch?: WatcherOptions | false; } @@ -883,3 +883,6 @@ interface AcornNode { start: number; type: string; } + +export function define(options: RollupOptions): RollupOptions; +export function define(options: RollupOptions[]): RollupOptions[]; From ee36ce3f755e17be13a356c00d2de46393c26792 Mon Sep 17 00:00:00 2001 From: rxliuli Date: Sun, 6 Jun 2021 12:34:43 +0800 Subject: [PATCH 4/4] refactor: Rename define => defineConfig --- src/rollup/rollup.ts | 2 +- src/rollup/types.d.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rollup/rollup.ts b/src/rollup/rollup.ts index f956f5e863d..721d26cd60e 100644 --- a/src/rollup/rollup.ts +++ b/src/rollup/rollup.ts @@ -289,6 +289,6 @@ function writeOutputFile( * Mainly to facilitate IDE code prompts, after all, export default does not prompt, even if you add @type annotations, it is not accurate * @param options */ -export function define(options: T): T { +export function defineConfig(options: T): T { return options; } diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index cb2e10f4844..cab04c563aa 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -884,5 +884,5 @@ interface AcornNode { type: string; } -export function define(options: RollupOptions): RollupOptions; -export function define(options: RollupOptions[]): RollupOptions[]; +export function defineConfig(options: RollupOptions): RollupOptions; +export function defineConfig(options: RollupOptions[]): RollupOptions[];