Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions packages/uni-mp-vite/__tests__/independentVendorChunk.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { IndependentVendorChunk } from '../src/plugin/independentVendorChunk'
import { virtualPagePath } from '../src/plugins/entry'

const inputDir = '/proj/src'
const independentRoots = ['pkg6051indep/']

describe('IndependentVendorChunk.resolve', () => {
test('only independent subpackage importers go to that vendor', () => {
expect(
IndependentVendorChunk.resolve(
[`${inputDir}/pkg6051indep/class-probe.vue?vue&type=script`],
inputDir,
independentRoots
)
).toBe('pkg6051indep/common/vendor')
})

test('regular subpackage importers stay on main vendor', () => {
expect(
IndependentVendorChunk.resolve(
[`${inputDir}/pkg6051/class-probe.vue`],
inputDir,
independentRoots
)
).toBeUndefined()
})

test('shared with main package stays on main vendor', () => {
expect(
IndependentVendorChunk.resolve(
[
`${inputDir}/pkg6051indep/class-probe.vue`,
`${inputDir}/pages/index/index.vue`,
],
inputDir,
independentRoots
)
).toBeUndefined()
})

test('shared by two independent subpackages stays on main vendor', () => {
expect(
IndependentVendorChunk.resolve(
[
`${inputDir}/pkg6051indep/a.vue`,
`${inputDir}/pkgOther/b.vue`,
],
inputDir,
['pkg6051indep/', 'pkgOther/']
)
).toBeUndefined()
})

test('virtual page importer resolves into the independent root', () => {
expect(
IndependentVendorChunk.resolve(
[virtualPagePath('pkg6051indep/class-probe.vue')],
inputDir,
independentRoots
)
).toBe('pkg6051indep/common/vendor')
})

test('empty importers or roots do not move the chunk', () => {
expect(
IndependentVendorChunk.resolve(
[`${inputDir}/pkg6051indep/class-probe.vue`],
inputDir,
[]
)
).toBeUndefined()
expect(
IndependentVendorChunk.resolve([], inputDir, independentRoots)
).toBeUndefined()
})
})
15 changes: 14 additions & 1 deletion packages/uni-mp-vite/src/plugin/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
parseVirtualComponentPath,
parseVirtualPagePath,
} from '../plugins/entry'
import { IndependentVendorChunk } from './independentVendorChunk'

const debugChunk = debug('uni:chunk')

Expand Down Expand Up @@ -240,7 +241,8 @@ function createMoveToVendorChunkFn(): GetManualChunk | undefined {
}
return
}
const { hasOptimizationSubPackages, subPackages } = getSubPackages()
const { hasOptimizationSubPackages, subPackages, independentSubPackages } =
getSubPackages()
// 处理子包引用的 node_modules 中的文件
if (
hasOptimizationSubPackages &&
Expand All @@ -264,6 +266,17 @@ function createMoveToVendorChunkFn(): GetManualChunk | undefined {
return `${matchSubPackages.values().next().value}common/vendor`
}
}
// 独立分包不能引用主包 JS。仅被某一个独立分包引用的 npm 打进该分包 vendor。
// 不依赖 optimization.subPackages:这是微信运行时正确性,不是体积优化。
const independentVendor = IndependentVendorChunk.resolve(
getModuleInfo(id)?.importers || [],
inputDir,
independentSubPackages
)
if (independentVendor) {
debugChunk(independentVendor, normalizedId)
return independentVendor
}
// 非项目内的 js 资源,均打包到 vendor
debugChunk('common/vendor', normalizedId)
return 'common/vendor'
Expand Down
61 changes: 61 additions & 0 deletions packages/uni-mp-vite/src/plugin/independentVendorChunk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* 独立分包 npm vendor 落点。
* 微信独立分包不能 require 主包 JS;仅当全部 importer 落在同一个独立分包根下时,
* 才把该 npm 打进 `{root}common/vendor`,否则保持主包 common/vendor。
*/
import path from 'path'
import { normalizePath } from '@dcloudio/uni-cli-shared'
import {
isUniComponentUrl,
isUniPageUrl,
parseVirtualComponentPath,
parseVirtualPagePath,
} from '../plugins/entry'

export namespace IndependentVendorChunk {
export function resolveImporterFile(
importer: string,
inputDir: string
): string {
const raw = normalizePath(importer)
if (isUniPageUrl(raw)) {
return normalizePath(path.resolve(inputDir, parseVirtualPagePath(raw)))
}
if (isUniComponentUrl(raw)) {
return normalizePath(
path.resolve(inputDir, parseVirtualComponentPath(raw))
)
}
return raw.split('?')[0]
}

/**
* 微信独立分包不能引用主包 JS。
* 仅当全部 importer 落在同一个独立分包根下时,把 npm 打进 `{root}common/vendor`。
*/
export function resolve(
importers: readonly string[],
inputDir: string,
independentRoots: readonly string[]
): string | undefined {
if (!importers.length || !independentRoots.length) {
return
}
const normalizedInput = normalizePath(inputDir)
const matched = new Set<string>()
for (const importer of importers) {
const file = resolveImporterFile(importer, normalizedInput)
const root = independentRoots.find((subPackagePath) =>
file.startsWith(`${normalizedInput}/${subPackagePath}`)
)
if (!root) {
return
}
matched.add(root)
}
if (matched.size !== 1) {
return
}
return `${[...matched][0]}common/vendor`
}
}
16 changes: 13 additions & 3 deletions packages/uni-mp-vite/src/plugins/entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,17 @@ export function parseComponentStyleIsolation(content: string) {

let hasOptimizationSubPackages = false // 是否开启分包优化配置
let subPackages: string[] = []
let independentSubPackages: string[] = []
function normalizeSubPackageRoot(root: string) {
return `${root.replace(/\/$/, '')}/`
}
function initSubPackages() {
const inputDir = normalizePath(process.env.UNI_INPUT_DIR)
const pagesJsonFile = path.resolve(inputDir, 'pages.json')
if (!fs.existsSync(pagesJsonFile)) {
hasOptimizationSubPackages = false
subPackages = []
independentSubPackages = []
return
}
const platform = process.env.UNI_PLATFORM
Expand All @@ -76,14 +81,19 @@ function initSubPackages() {
platform,
{ subpackages: true }
)
subPackages = Object.values(appJson.subPackages || appJson.subpackages || {})
.filter(Boolean)
.map(({ root }) => `${root.replace(/\/$/, '')}/`)
const packages = Object.values(
appJson.subPackages || appJson.subpackages || {}
).filter(Boolean)
subPackages = packages.map(({ root }) => normalizeSubPackageRoot(root))
independentSubPackages = packages
.filter((pkg) => pkg.independent)
.map(({ root }) => normalizeSubPackageRoot(root))
}
export function getSubPackages() {
return {
hasOptimizationSubPackages,
subPackages,
independentSubPackages,
}
}

Expand Down