diff --git a/packages/uni-cli-shared/src/json/manifest.ts b/packages/uni-cli-shared/src/json/manifest.ts index 888b66292e0139b5d6af1600afdff30e044855fe..986aa03a38dd1d7380d275abc7217bd780c8fc33 100644 --- a/packages/uni-cli-shared/src/json/manifest.ts +++ b/packages/uni-cli-shared/src/json/manifest.ts @@ -72,3 +72,7 @@ export function getRouterOptions(manifestJson: Record): { } { return extend({}, manifestJson.h5?.router) } + +export function isEnableTreeShaking(manifestJson: Record) { + return manifestJson.h5?.optimization?.treeShaking?.enable !== false +} diff --git a/packages/uni-cli-shared/src/vite/plugins/inject.ts b/packages/uni-cli-shared/src/vite/plugins/inject.ts index 746a79b813df611c9a85e688aad03d12e74262c3..a39fb59eefcde1c609414a7a73b3c84a21c31739 100644 --- a/packages/uni-cli-shared/src/vite/plugins/inject.ts +++ b/packages/uni-cli-shared/src/vite/plugins/inject.ts @@ -16,7 +16,13 @@ import { walk } from 'estree-walker' import { extend } from '@vue/shared' import MagicString from 'magic-string' -import { isProperty, isReference, isMemberExpression, isJsFile } from '../utils' +import { + isProperty, + isReference, + isMemberExpression, + isJsFile, + isAssignmentExpression, +} from '../utils' interface Scope { parent: Scope @@ -46,6 +52,7 @@ export function uniViteInjectPlugin(options: InjectOptions): Plugin { delete modules.sourceMap delete modules.callback + const reassignments = new Set() const modulesMap = new Map() const namespaceModulesMap = new Map() Object.keys(modules).forEach((name) => { @@ -105,7 +112,12 @@ export function uniViteInjectPlugin(options: InjectOptions): Plugin { const newImports = new Map() - function handleReference(node: BaseNode, name: string, keypath: string) { + function handleReference( + node: BaseNode, + name: string, + keypath: string, + parent?: BaseNode + ) { let mod = modulesMap.get(keypath) if (!mod && hasNamespace) { const mods = keypath.split('.') @@ -128,8 +140,15 @@ export function uniViteInjectPlugin(options: InjectOptions): Plugin { if (mod && !imports.has(name) && !scope.contains(name)) { if (typeof mod === 'string') mod = [mod, 'default'] if (mod[0] === id) return false - const hash = `${keypath}:${mod[0]}:${mod[1]}` + // 当 API 被覆盖定义后,不再摇树 + if (reassignments.has(hash)) { + return false + } + if (parent && isAssignmentExpression(parent)) { + reassignments.add(hash) + return false + } const importLocalName = name === keypath ? name : makeLegalIdentifier(`$inject_${keypath}`) @@ -184,7 +203,7 @@ export function uniViteInjectPlugin(options: InjectOptions): Plugin { if (isReference(node, parent)) { const { name, keypath } = flatten(node) - const handled = handleReference(node, name, keypath) + const handled = handleReference(node, name, keypath, parent) if (handled) { this.skip() } diff --git a/packages/uni-cli-shared/src/vite/utils/ast.ts b/packages/uni-cli-shared/src/vite/utils/ast.ts index b67c4aa275627584903e1fa41626cae465c9bf29..9fb0b2023a576b901901d914e6aefd9754eb74d2 100644 --- a/packages/uni-cli-shared/src/vite/utils/ast.ts +++ b/packages/uni-cli-shared/src/vite/utils/ast.ts @@ -4,6 +4,7 @@ import type { Property, Identifier, CallExpression, + AssignmentExpression, MemberExpression, MethodDefinition, ExportSpecifier, @@ -25,6 +26,10 @@ export const isProperty = (node: BaseNode): node is Property => export const isIdentifier = (node: BaseNode): node is Identifier => node.type === 'Identifier' +export const isAssignmentExpression = ( + node: BaseNode +): node is AssignmentExpression => node.type === 'AssignmentExpression' + export const isCallExpression = (node: BaseNode): node is CallExpression => node.type === 'CallExpression' diff --git a/packages/uni-h5-vite/src/plugins/inject.ts b/packages/uni-h5-vite/src/plugins/inject.ts index 1e9bc983ede72e078087771b71985f6be8bb5b68..952b63efa9ea63aee6a9083c21b78708530a520f 100644 --- a/packages/uni-h5-vite/src/plugins/inject.ts +++ b/packages/uni-h5-vite/src/plugins/inject.ts @@ -10,6 +10,8 @@ import { buildInCssSet, uniViteInjectPlugin, isCombineBuiltInCss, + isEnableTreeShaking, + parseManifestJsonOnce, } from '@dcloudio/uni-cli-shared' const apiJson = require(path.resolve(__dirname, '../../lib/api.json')) @@ -49,17 +51,27 @@ export function uniInjectPlugin(): Plugin { } }) } - const injectPlugin = uniViteInjectPlugin( - extend(uniInjectPluginOptions, { - callback, - }) - ) + let injectPlugin: Plugin + return { name: 'vite:uni-h5-inject', apply: 'build', enforce: 'post', configResolved(config) { resolvedConfig = config + const enableTreeShaking = isEnableTreeShaking( + parseManifestJsonOnce(process.env.UNI_INPUT_DIR) + ) + if (!enableTreeShaking) { + // 不启用摇树优化,移除 wx、uni 等 API 配置 + delete uniInjectPluginOptions['wx.'] + delete uniInjectPluginOptions['uni.'] + } + injectPlugin = uniViteInjectPlugin( + extend(uniInjectPluginOptions, { + callback, + }) + ) }, transform(code, id) { return injectPlugin.transform!.call(this, code, id) diff --git a/packages/uni-h5-vite/src/plugins/pagesJson.ts b/packages/uni-h5-vite/src/plugins/pagesJson.ts index 9d4b1b0fe6eeba5fff80d69adf039e29ec9e4d07..06d91be2aa0b10ab7719d9fdbc6beed1cb02d80b 100644 --- a/packages/uni-h5-vite/src/plugins/pagesJson.ts +++ b/packages/uni-h5-vite/src/plugins/pagesJson.ts @@ -11,6 +11,8 @@ import { normalizePagesRoute, normalizePagePath, normalizePath, + isEnableTreeShaking, + parseManifestJsonOnce, } from '@dcloudio/uni-cli-shared' export function uniPagesJsonPlugin(): Plugin { @@ -79,8 +81,11 @@ function getGlobal(ssr?: boolean) { // 兼容 wx 对象 function registerGlobalCode(config: ResolvedConfig, ssr?: boolean) { const name = getGlobal(ssr) - if (config.command === 'build' && !ssr) { - // 非SSR的发行模式,补充全局 uni 对象 + const enableTreeShaking = isEnableTreeShaking( + parseManifestJsonOnce(process.env.UNI_INPUT_DIR) + ) + if (enableTreeShaking && config.command === 'build' && !ssr) { + // 非 SSR 的发行模式,补充全局 uni 对象 return `${name}.uni = {};${name}.wx = {}` }