diff --git a/.api/public.d.ts b/.api/public.d.ts index afb8008..e83602c 100644 --- a/.api/public.d.ts +++ b/.api/public.d.ts @@ -27,22 +27,6 @@ declare module "@cocos/ccbuild" { */ function enumerateAllDependents(meta: buildEngine.Result, featureUnits: string[]): string[]; export type ModuleFormat = "esm" | "cjs" | "system" | "iife"; - export type HasModuleSideEffects = (id: string, external: boolean) => boolean; - export type ModuleSideEffectsOption = boolean | "no-external" | string[] | HasModuleSideEffects; - export type TreeshakingPreset = "smallest" | "safest" | "recommended"; - export interface NormalizedTreeshakingOptions { - annotations: boolean; - correctVarValueBeforeDeclaration: boolean; - manualPureFunctions: readonly string[]; - moduleSideEffects: HasModuleSideEffects; - propertyReadSideEffects: boolean | "always"; - tryCatchDeoptimization: boolean; - unknownGlobalSideEffects: boolean; - } - export interface TreeshakingOptions extends Partial> { - moduleSideEffects?: ModuleSideEffectsOption; - preset?: TreeshakingPreset; - } export interface Options { /** * 引擎仓库目录。 @@ -178,7 +162,6 @@ declare module "@cocos/ccbuild" { * @note It's only avaiable when options.moduleFormat is 'system'. */ enableNamedRegisterForSystemJSModuleFormat?: boolean; - treeshake?: TreeshakingOptions; } export interface Result { /** @@ -231,6 +214,10 @@ declare module "@cocos/ccbuild" { * Gets all optimzie decorators */ getOptimizeDecorators(): ConfigInterface.IOptimizeDecorators; + /** + * Gets TreeShake config + */ + getTreeShakeConfig(): ConfigInterface.ITreeShakeConfig | undefined; /** * Gets all features defined. */ @@ -375,6 +362,10 @@ declare module "@cocos/ccbuild" { * The decorators to be optimize when build engine. */ optimizeDecorators: IOptimizeDecorators; + /** + * The TreeShake config + */ + treeShake?: ITreeShakeConfig; } export interface IndexConfig { modules?: Record): Pro onwarn: rollupWarningHandler, }; - if (options.treeshake) { - rollupOptions.treeshake = options.treeshake; + const treeshakeConfig = statsQuery.getTreeShakeConfig(); + const noSideEffectFiles = treeshakeConfig?.noSideEffectFiles; + if (noSideEffectFiles && noSideEffectFiles.length > 0) { + rollupOptions.treeshake = { + moduleSideEffects: (id: string): boolean => { + const relativePath = formatPath(ps.relative(engineRoot, id)); + if (noSideEffectFiles.includes(relativePath)) { + console.info(`>>> Found no side-effect path: ${relativePath}`); + return false; + } + return true; + } + }; + } else { + console.info(`>>> No treeshake config found!`); } const perf = true; diff --git a/modules/build-engine/src/index.ts b/modules/build-engine/src/index.ts index 67e901d..3ae4b8f 100644 --- a/modules/build-engine/src/index.ts +++ b/modules/build-engine/src/index.ts @@ -69,28 +69,7 @@ export async function buildEngine (options: buildEngine.Options): Promise boolean; - export type ModuleSideEffectsOption = boolean | 'no-external' | string[] | HasModuleSideEffects; - - export type TreeshakingPreset = 'smallest' | 'safest' | 'recommended'; - - export interface NormalizedTreeshakingOptions { - annotations: boolean; - correctVarValueBeforeDeclaration: boolean; - manualPureFunctions: readonly string[]; - moduleSideEffects: HasModuleSideEffects; - propertyReadSideEffects: boolean | 'always'; - tryCatchDeoptimization: boolean; - unknownGlobalSideEffects: boolean; - } - - // See https://rollupjs.org/configuration-options/#treeshake for more details. - export interface TreeshakingOptions extends Partial> { - moduleSideEffects?: ModuleSideEffectsOption; - preset?: TreeshakingPreset; - } - + export interface Options { /** * 引擎仓库目录。 @@ -258,8 +237,6 @@ export namespace buildEngine { * @note It's only avaiable when options.moduleFormat is 'system'. */ enableNamedRegisterForSystemJSModuleFormat?: boolean; - - treeshake?: TreeshakingOptions; } export interface Result { diff --git a/modules/stats-query/src/config-interface.ts b/modules/stats-query/src/config-interface.ts index 8e4a8f5..4e27709 100644 --- a/modules/stats-query/src/config-interface.ts +++ b/modules/stats-query/src/config-interface.ts @@ -31,6 +31,11 @@ export interface Config { * The decorators to be optimize when build engine. */ optimizeDecorators: IOptimizeDecorators; + + /** + * The TreeShake config + */ + treeShake?: ITreeShakeConfig; } export interface IndexConfig { @@ -150,4 +155,8 @@ export interface IOptimizeDecorators { * The decorators which should be removed directly when they only work in Cocos Creator editor. */ editorDecorators: string[], +} + +export interface ITreeShakeConfig { + noSideEffectFiles: string[]; } \ No newline at end of file diff --git a/modules/stats-query/src/index.ts b/modules/stats-query/src/index.ts index cf913d5..3c5c12f 100644 --- a/modules/stats-query/src/index.ts +++ b/modules/stats-query/src/index.ts @@ -52,6 +52,13 @@ export class StatsQuery { return this._config.optimizeDecorators; } + /** + * Gets TreeShake config + */ + public getTreeShakeConfig (): ConfigInterface.ITreeShakeConfig | undefined { + return this._config.treeShake; + } + /** * Gets all features defined. */ diff --git a/package-lock.json b/package-lock.json index 59b4a48..4e5c69c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cocos/ccbuild", - "version": "2.2.13", + "version": "2.2.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cocos/ccbuild", - "version": "2.2.13", + "version": "2.2.14", "hasInstallScript": true, "license": "MIT", "workspaces": [ diff --git a/package.json b/package.json index aa7d7c6..3e84ad5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cocos/ccbuild", - "version": "2.2.13", + "version": "2.2.14", "description": "The next generation of build tool for Cocos engine.", "main": "./lib/index.js", "types": "./lib/index.d.ts", diff --git a/scripts/test-build-cocos.js b/scripts/test-build-cocos.js index d89b7f2..0de5f1d 100644 --- a/scripts/test-build-cocos.js +++ b/scripts/test-build-cocos.js @@ -1,6 +1,6 @@ const ps = require('path'); const { ensureDir, emptyDir } = require('fs-extra'); -const { buildEngine } = require('../lib/src'); +const { buildEngine, StatsQuery } = require('../lib/src'); const argv = process.argv; @@ -47,16 +47,6 @@ const argv = process.argv; "wasmCompressionMode": 'brotli', "visualize": true, "inlineEnum": true, - treeshake: { - moduleSideEffects: (id, isExternal) => { - const fileName = ps.basename(id); - if (noSideEffectFiles.indexOf(fileName) >= 0) { - console.info(`--> Found fileName: ${fileName}`); - return false; - } - return true; - } - }, }; await ensureDir(outDir); diff --git a/test/build-engine/__snapshots__/engine-js.test.ts.snap b/test/build-engine/__snapshots__/engine-js.test.ts.snap index 58f7172..954518b 100644 --- a/test/build-engine/__snapshots__/engine-js.test.ts.snap +++ b/test/build-engine/__snapshots__/engine-js.test.ts.snap @@ -136,142 +136,6 @@ exports[`engine-js HTML5 with treeshake option 2`] = ` " `; -exports[`engine-js HTML5 without treeshake option 1`] = ` -[ - "cc.js", -] -`; - -exports[`engine-js HTML5 without treeshake option 2`] = ` -"System.register([], (function (exports) { - 'use strict'; - return { - execute: (function () { - - function tryDefineGlobal (name, value) { - const _global = typeof window === 'undefined' ? global : window; - if (typeof _global[name] === 'undefined') { - return (_global[name] = value); - } else { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return _global[name]; - } - } - tryDefineGlobal('CC_WECHAT', false); - tryDefineGlobal('CC_BAIDU', false); - tryDefineGlobal('CC_XIAOMI', false); - tryDefineGlobal('CC_ALIPAY', false); - tryDefineGlobal('CC_BYTEDANCE', false); - tryDefineGlobal('CC_OPPO', false); - tryDefineGlobal('CC_VIVO', false); - tryDefineGlobal('CC_HUAWEI', false); - tryDefineGlobal('CC_COCOSPLAY', false); - tryDefineGlobal('CC_QTT', false); - tryDefineGlobal('CC_LINKSURE', false); - tryDefineGlobal('CC_EDITOR', false); - tryDefineGlobal('CC_PREVIEW', false); - tryDefineGlobal('CC_BUILD', true); - tryDefineGlobal('CC_TEST', false); - tryDefineGlobal('CC_DEBUG', false); - tryDefineGlobal('CC_DEV', false); - tryDefineGlobal('CC_MINIGAME', false); - tryDefineGlobal('CC_RUNTIME_BASED', false); - tryDefineGlobal('CC_SUPPORT_JIT', true); - tryDefineGlobal('CC_JSB', false); - - var Pool = function () { - var _proto = Pool.prototype; - _proto.get = function get() { - return this._get(); - }; - function Pool(_0, _1) { - this.count = 0; - var size = _1 === undefined ? _0 : _1; - var cleanupFunc = _1 === undefined ? null : _0; - this._pool = new Array(size); - this._cleanup = cleanupFunc; - } - _proto._get = function _get() { - if (this.count > 0) { - --this.count; - var cache = this._pool[this.count]; - this._pool[this.count] = null; - return cache; - } - return null; - }; - _proto.put = function put(obj) { - var pool = this._pool; - if (this.count < pool.length) { - if (this._cleanup && this._cleanup(obj) === false) { - return; - } - pool[this.count] = obj; - ++this.count; - } - }; - _proto.resize = function resize(length) { - if (length >= 0) { - this._pool.length = length; - if (this.count > length) { - this.count = length; - } - } - }; - return Pool; - }(); - - console.log("I'm instantiate-jit.ts"); - console.log('side-effect'); - var Impure = function Impure() { - console.log('side-effect'); - }; - new Impure(); - var Assignments = function () { - function Assignments(targetExpression) { - this._exps = []; - this._targetExp = targetExpression; - } - var _proto2 = Assignments.prototype; - _proto2.append = function append(key, expression) { - this._exps.push([key, expression]); - }; - _proto2.writeCode = function writeCode(codeArray) { - console.info("writeCode"); - }; - return Assignments; - }(); - Assignments.pool = void 0; - Assignments.pool = new Pool(function (obj) { - obj._exps.length = 0; - obj._targetExp = null; - }, 1); - Assignments.pool.get = function (targetExpression) { - var cache = this._get() || new Assignments(); - cache._targetExp = targetExpression; - return cache; - }; - function compile() { - console.log(">>> jit compile ..."); - } - - var Prefab = exports("Prefab", function () { - function Prefab() {} - var _proto = Prefab.prototype; - _proto._instantiate = function _instantiate() { - { - compile(); - } - }; - return Prefab; - }()); - - }) - }; -})); -" -`; - exports[`engine-js WECHAT with treeshake option 1`] = ` [ "cc.js", @@ -332,139 +196,6 @@ exports[`engine-js WECHAT with treeshake option 2`] = ` " `; -exports[`engine-js WECHAT without treeshake option 1`] = ` -[ - "cc.js", -] -`; - -exports[`engine-js WECHAT without treeshake option 2`] = ` -"System.register([], (function (exports) { - 'use strict'; - return { - execute: (function () { - - function tryDefineGlobal (name, value) { - const _global = typeof window === 'undefined' ? global : window; - if (typeof _global[name] === 'undefined') { - return (_global[name] = value); - } else { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return _global[name]; - } - } - tryDefineGlobal('CC_WECHAT', true); - tryDefineGlobal('CC_BAIDU', false); - tryDefineGlobal('CC_XIAOMI', false); - tryDefineGlobal('CC_ALIPAY', false); - tryDefineGlobal('CC_BYTEDANCE', false); - tryDefineGlobal('CC_OPPO', false); - tryDefineGlobal('CC_VIVO', false); - tryDefineGlobal('CC_HUAWEI', false); - tryDefineGlobal('CC_COCOSPLAY', false); - tryDefineGlobal('CC_QTT', false); - tryDefineGlobal('CC_LINKSURE', false); - tryDefineGlobal('CC_EDITOR', false); - tryDefineGlobal('CC_PREVIEW', false); - tryDefineGlobal('CC_BUILD', true); - tryDefineGlobal('CC_TEST', false); - tryDefineGlobal('CC_DEBUG', false); - tryDefineGlobal('CC_DEV', false); - tryDefineGlobal('CC_MINIGAME', true); - tryDefineGlobal('CC_RUNTIME_BASED', false); - tryDefineGlobal('CC_SUPPORT_JIT', false); - tryDefineGlobal('CC_JSB', false); - - var Pool = function () { - var _proto = Pool.prototype; - _proto.get = function get() { - return this._get(); - }; - function Pool(_0, _1) { - this.count = 0; - var size = _1 === undefined ? _0 : _1; - var cleanupFunc = _1 === undefined ? null : _0; - this._pool = new Array(size); - this._cleanup = cleanupFunc; - } - _proto._get = function _get() { - if (this.count > 0) { - --this.count; - var cache = this._pool[this.count]; - this._pool[this.count] = null; - return cache; - } - return null; - }; - _proto.put = function put(obj) { - var pool = this._pool; - if (this.count < pool.length) { - if (this._cleanup && this._cleanup(obj) === false) { - return; - } - pool[this.count] = obj; - ++this.count; - } - }; - _proto.resize = function resize(length) { - if (length >= 0) { - this._pool.length = length; - if (this.count > length) { - this.count = length; - } - } - }; - return Pool; - }(); - - console.log("I'm instantiate-jit.ts"); - console.log('side-effect'); - var Impure = function Impure() { - console.log('side-effect'); - }; - new Impure(); - var Assignments = function () { - function Assignments(targetExpression) { - this._exps = []; - this._targetExp = targetExpression; - } - var _proto2 = Assignments.prototype; - _proto2.append = function append(key, expression) { - this._exps.push([key, expression]); - }; - _proto2.writeCode = function writeCode(codeArray) { - console.info("writeCode"); - }; - return Assignments; - }(); - Assignments.pool = void 0; - Assignments.pool = new Pool(function (obj) { - obj._exps.length = 0; - obj._targetExp = null; - }, 1); - Assignments.pool.get = function (targetExpression) { - var cache = this._get() || new Assignments(); - cache._targetExp = targetExpression; - return cache; - }; - - var Prefab = exports("Prefab", function () { - function Prefab() {} - var _proto = Prefab.prototype; - _proto._instantiate = function _instantiate() { - { - console.error("Dosn't support JIT"); - } - }; - return Prefab; - }()); - - }) - }; -})); -" -`; - exports[`engine-js build WASM module on platform maybe supporting WASM 1`] = ` [ "assets/wasm_c-_JUdaL1r.wasm", diff --git a/test/build-engine/engine-js.test.ts b/test/build-engine/engine-js.test.ts index 78bd9ed..dffd4f8 100644 --- a/test/build-engine/engine-js.test.ts +++ b/test/build-engine/engine-js.test.ts @@ -316,35 +316,6 @@ describe('engine-js', () => { await del(out, { force: true }); }); - test('WECHAT without treeshake option', async () => { - const out = ps.join(__dirname, './lib-js'); - - const options: buildEngine.Options = { - engine: ps.join(__dirname, '../test-engine-source'), - out, - platform: 'WECHAT', - moduleFormat: 'system', - compress: false, - split: false, - nativeCodeBundleMode: 'wasm', - assetURLFormat: 'runtime-resolved', - noDeprecatedFeatures: false, - sourceMap: false, - features: ['base'], - loose: true, - mode: 'BUILD', - flags: { - DEBUG: false, - WEBGPU: false - }, - }; - - await buildEngine(options); - expect(await getOutputDirStructure(out)).toMatchSnapshot(); - expect(await getOutputContent(ps.join(out, 'cc.js'))).toMatchSnapshot(); - await del(out, { force: true }); - }); - test('WECHAT with treeshake option', async () => { const out = ps.join(__dirname, './lib-js'); @@ -366,38 +337,6 @@ describe('engine-js', () => { DEBUG: false, WEBGPU: false }, - treeshake: { - moduleSideEffects: (id) => !id.endsWith('instantiate-jit.ts'), - } - }; - - await buildEngine(options); - expect(await getOutputDirStructure(out)).toMatchSnapshot(); - expect(await getOutputContent(ps.join(out, 'cc.js'))).toMatchSnapshot(); - await del(out, { force: true }); - }); - - test('HTML5 without treeshake option', async () => { - const out = ps.join(__dirname, './lib-js'); - - const options: buildEngine.Options = { - engine: ps.join(__dirname, '../test-engine-source'), - out, - platform: 'HTML5', - moduleFormat: 'system', - compress: false, - split: false, - nativeCodeBundleMode: 'wasm', - assetURLFormat: 'runtime-resolved', - noDeprecatedFeatures: false, - sourceMap: false, - features: ['base'], - loose: true, - mode: 'BUILD', - flags: { - DEBUG: false, - WEBGPU: false - }, }; await buildEngine(options); @@ -427,9 +366,6 @@ describe('engine-js', () => { DEBUG: false, WEBGPU: false }, - treeshake: { - moduleSideEffects: (id) => !id.endsWith('instantiate-jit.ts'), - } }; await buildEngine(options); diff --git a/test/test-engine-source/cc.config.json b/test/test-engine-source/cc.config.json index cac2143..1b8103d 100644 --- a/test/test-engine-source/cc.config.json +++ b/test/test-engine-source/cc.config.json @@ -424,5 +424,12 @@ "readOnly", "displayName", "tooltip", "group", "range", "rangeMin", "rangeMax", "rangeStep", "slide", "displayOrder", "unit", "radian", "multiline", "disallowAnimation" ] + }, + + "treeShake": { + "noSideEffectFiles": [ + "cocos/serialization/instantiate-jit.ts", + "cocos/game/splash-screen.ts" + ] } } diff --git a/test/test-engine-source/cc.config.schema.json b/test/test-engine-source/cc.config.schema.json index 6a1d2d1..22fb1a4 100644 --- a/test/test-engine-source/cc.config.schema.json +++ b/test/test-engine-source/cc.config.schema.json @@ -56,6 +56,10 @@ "optimizeDecorators": { "$ref": "#/definitions/IOptimizeDecorators", "description": "The decorators to be optimize when build engine." + }, + "treeShake": { + "$ref": "#/definitions/ITreeShakeConfig", + "description": "The TreeShake config" } }, "required": [ @@ -78,14 +82,21 @@ "description": "An engine feature.", "properties": { "dependentAssets": { - "description": "List of uuid that the feature depend on.", + "description": "List of uuid that the feature depends on.", "items": { "type": "string" }, "type": "array" }, "dependentModules": { - "description": "List of module that the feature depend on.", + "description": "List of module that the feature depends on.", + "items": { + "type": "string" + }, + "type": "array" + }, + "dependentScripts": { + "description": "List of script uuid that the feature depends on.", "items": { "type": "string" }, @@ -186,6 +197,21 @@ ], "type": "object" }, + "ITreeShakeConfig": { + "additionalProperties": false, + "properties": { + "noSideEffectFiles": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "noSideEffectFiles" + ], + "type": "object" + }, "IndexConfig": { "additionalProperties": false, "properties": {