Skip to content

Commit d84d9fa

Browse files
authored
fix: 修复manifest.json增删入口后无法正常编译的问题 (#164)
1 parent 683063e commit d84d9fa

8 files changed

Lines changed: 113 additions & 28 deletions

File tree

packages/hap-packager/src/common/info.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ export function resolveFile(scriptFilePath) {
3434
* @return {array}
3535
*/
3636
export function getEntryFiles(entry) {
37-
const entryFiles = Object.keys(entry || {}).map((file) => {
37+
const normalizedEntry = getNormalizedEntry(entry)
38+
const entryFiles = Object.keys(normalizedEntry).map((file) => {
3839
return file + '.js'
3940
})
4041
return entryFiles
@@ -47,9 +48,10 @@ export function getEntryFiles(entry) {
4748
*/
4849
export function getLiteEntryFiles(entry) {
4950
const liteEntry = []
50-
Object.keys(entry || {}).forEach((file) => {
51-
const fileInfo = entry[file]
52-
const importStr = fileInfo.import[0] || ''
51+
const normalizedEntry = getNormalizedEntry(entry)
52+
Object.keys(normalizedEntry).forEach((file) => {
53+
const fileInfo = normalizedEntry[file]
54+
const importStr = (fileInfo && fileInfo.import && fileInfo.import[0]) || ''
5355
if (importStr.indexOf('?') >= 0) {
5456
const paramStr = importStr.split('?')[1]
5557
const paramArr = paramStr.split('&')
@@ -61,6 +63,19 @@ export function getLiteEntryFiles(entry) {
6163
return liteEntry
6264
}
6365

66+
/**
67+
* 获取当前生效的 webpack entry 配置。
68+
* 支持 watch 模式下通过 entry 函数动态刷新入口。
69+
* @param {object|function} entry
70+
* @return {object}
71+
*/
72+
export function getNormalizedEntry(entry) {
73+
if (typeof entry === 'function') {
74+
return entry() || {}
75+
}
76+
return entry || {}
77+
}
78+
6479
/**
6580
* 获取骨架屏配置信息
6681
* @param {String} src - 项目src路径

packages/hap-packager/src/plugins/handler-plugin.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import Compilation from 'webpack/lib/Compilation'
77
import { globalConfig, compileOptionsObject, compileOptionsMeta } from '@hap-toolkit/shared-utils'
8-
import { getEntryFiles, getLiteEntryFiles } from '../common/info'
8+
import { getEntryFiles, getLiteEntryFiles, getNormalizedEntry } from '../common/info'
99

1010
let ConcatSource
1111

@@ -22,6 +22,7 @@ HandlerPlugin.prototype.apply = function (compiler) {
2222
ConcatSource = compiler.webpack.sources.ConcatSource
2323
const workersPath = this.options.workers
2424
const enableE2e = this.options.enableE2e
25+
const entryState = this.options.entryState
2526
compiler.hooks.compilation.tap('HandlerPlugin', function (compilation) {
2627
compilation.hooks.processAssets.tap(
2728
{
@@ -30,8 +31,11 @@ HandlerPlugin.prototype.apply = function (compiler) {
3031
},
3132
() => {
3233
// 如果进行抽取公共js则需通过入口文件来判断是不是抽取出的Chunks
33-
const entryFiles = getEntryFiles(compiler.options.entry)
34-
const liteEntryFiles = getLiteEntryFiles(compiler.options.entry)
34+
const currentEntry = entryState
35+
? entryState.current
36+
: getNormalizedEntry(compiler.options.entry)
37+
const entryFiles = getEntryFiles(currentEntry)
38+
const liteEntryFiles = getLiteEntryFiles(currentEntry)
3539
const { originType } = compileOptionsObject || {}
3640
const isDevMode = globalConfig.mode === 'development'
3741
compilation.chunks.forEach(function (chunk) {

packages/hap-packager/src/plugins/resource-plugin.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
globalConfig
1919
} from '@hap-toolkit/shared-utils'
2020

21-
import { name } from '../common/info'
21+
import { name, getNormalizedEntry } from '../common/info'
2222
import { updateManifest } from '../common/shared'
2323

2424
const { PACKAGER_BUILD_DONE } = eventBus
@@ -221,10 +221,13 @@ ResourcePlugin.prototype.apply = function (compiler) {
221221
const webpackOptions = compiler.options
222222
// 监听时处理
223223
compiler.hooks.watchRun.tapAsync('ResourcePlugin', function (watching, callback) {
224-
Object.keys(webpackOptions.entry).forEach(function (key) {
224+
const currentEntry = options.entryState
225+
? options.entryState.current
226+
: getNormalizedEntry(webpackOptions.entry)
227+
Object.keys(currentEntry).forEach(function (key) {
225228
// 重置 changedJS
226229
globalConfig.changedJS = {}
227-
const val = webpackOptions.entry[key]
230+
const val = currentEntry[key]
228231
if (val instanceof Array && !/app\.js/.test(key)) {
229232
// 删除webpack-dev-server注入的watch依赖
230233
val[0].indexOf('webpack-dev-server') !== -1 && val.shift()

packages/hap-packager/src/plugins/splitchunks-adapt-plugin.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import path from 'path'
77
import Compilation from 'webpack/lib/Compilation'
8-
import { getEntryFiles } from '../common/info'
8+
import { getEntryFiles, getNormalizedEntry } from '../common/info'
99
import { compileOptionsMeta } from '@hap-toolkit/shared-utils'
1010
import { isEmptyObject } from '@hap-toolkit/compiler'
1111

@@ -106,7 +106,10 @@ class SplitChunksAdaptPlugin {
106106

107107
// 这个钩子负责生成chunkFileMapStr,兼容release包里找不到文件路径,因为压缩后会把文件名打为数字id
108108
compilation.hooks.optimizeChunkIds.tap(pluginName, (chunks) => {
109-
entryFiles = getEntryFiles(compiler.options.entry)
109+
const currentEntry = options.entryState
110+
? options.entryState.current
111+
: getNormalizedEntry(compiler.options.entry)
112+
entryFiles = getEntryFiles(currentEntry)
110113

111114
const chunksMap = Array.from(chunks)
112115
.filter((chunk) => {

packages/hap-packager/src/webpack.post.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ function postHook(webpackConf, defaultsOptions, quickappConfig = {}) {
4747
pathSrc,
4848
subpackages,
4949
workers,
50+
entryState,
5051
originType,
5152
useTreeShaking
5253
} = defaultsOptions
@@ -119,6 +120,7 @@ function postHook(webpackConf, defaultsOptions, quickappConfig = {}) {
119120
if (globalConfig.isSmartMode) {
120121
webpackConf.plugins.push(
121122
new SplitChunksAdaptPlugin({
123+
entryState,
122124
subpackages,
123125
disableSubpackages: compileOptionsObject.disableSubpackages
124126
})
@@ -133,6 +135,7 @@ function postHook(webpackConf, defaultsOptions, quickappConfig = {}) {
133135
new HandlerPlugin({
134136
pathSrc: pathSrc,
135137
workers: workers,
138+
entryState,
136139
enableE2e: compileOptionsObject.enableE2e,
137140
useTreeShaking
138141
}),
@@ -143,6 +146,7 @@ function postHook(webpackConf, defaultsOptions, quickappConfig = {}) {
143146
new ResourcePlugin({
144147
src: pathSrc,
145148
dest: pathBuild,
149+
entryState,
146150
comment: rpkComment,
147151
projectRoot: globalConfig.projectPath,
148152
configDebugInManifest,

packages/hap-toolkit/__tests__/compile.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ describe('测试compile', () => {
4747
},
4848
'development'
4949
)
50-
expect(conf.entry).toMatchSnapshot()
50+
expect(conf.entry()).toMatchSnapshot()
5151
})
5252

5353
it(

packages/hap-toolkit/src/gen-webpack-conf/index.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ export default async function genWebpackConf(launchOptions, mode) {
162162

163163
// 页面文件
164164
const entries = resolveEntries(manifest, SRC_DIR, cwd)
165+
const entryState = { current: entries }
165166

166167
// 环境变量
167168
const env = {
@@ -228,7 +229,7 @@ export default async function genWebpackConf(launchOptions, mode) {
228229
context: cwd,
229230
mode,
230231
cache,
231-
entry: entries,
232+
entry: () => entryState.current,
232233
output: {
233234
globalObject: 'window',
234235
path: BUILD_DIR,
@@ -293,7 +294,9 @@ export default async function genWebpackConf(launchOptions, mode) {
293294
},
294295
new ManifestWatchPlugin({
295296
appRoot: cwd,
296-
root: SRC_DIR
297+
root: SRC_DIR,
298+
buildDir: BUILD_DIR,
299+
entryState
297300
})
298301
],
299302
resolve: {
@@ -503,6 +506,7 @@ export default async function genWebpackConf(launchOptions, mode) {
503506
useTreeShaking:
504507
quickappConfig && quickappConfig.useTreeShaking ? !!quickappConfig.useTreeShaking : false,
505508
workers,
509+
entryState,
506510
cwd,
507511
originType: compileOptionsObject.originType,
508512
ideConfig: launchOptions.ideConfig

packages/hap-toolkit/src/plugins/manifest-watch-plugin.js

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
import path from 'path'
7+
import fs from 'fs'
78
import { colorconsole, readJson, logger, eventBus } from '@hap-toolkit/shared-utils'
89
import { resolveEntries } from '../utils'
910

@@ -21,6 +22,8 @@ export default class ManifestWatchPlugin {
2122
constructor(options) {
2223
this.appRoot = options.appRoot
2324
this.root = options.root
25+
this.buildDir = options.buildDir
26+
this.entryState = options.entryState
2427
this.manifestFile = path.resolve(this.root, 'manifest.json')
2528
let entries = {}
2629
try {
@@ -31,32 +34,81 @@ export default class ManifestWatchPlugin {
3134
this.list = Object.keys(entries)
3235
this.list = sort(this.list)
3336
}
34-
hasChanged(newList) {
35-
const sorted = sort(newList)
36-
const changed = JSON.stringify(sorted) !== JSON.stringify(this.list)
37+
38+
getRemovedEntries(newList) {
39+
const newSet = new Set(newList)
40+
return this.list.filter((key) => !newSet.has(key))
41+
}
42+
43+
updateEntries(entries) {
44+
const newList = sort(Object.keys(entries))
45+
const removedEntries = this.getRemovedEntries(newList)
46+
const changed = JSON.stringify(newList) !== JSON.stringify(this.list)
3747
if (changed) {
38-
this.list = sorted
48+
this.list = newList
49+
this.entryState && (this.entryState.current = entries)
50+
}
51+
return {
52+
changed,
53+
removedEntries
3954
}
40-
return changed
4155
}
56+
57+
removeBuildArtifacts(entryKeys) {
58+
if (!this.buildDir || !entryKeys || entryKeys.length === 0) {
59+
return
60+
}
61+
entryKeys.forEach((entryKey) => {
62+
const entryDir = path.dirname(entryKey)
63+
if (entryDir && entryDir !== '.') {
64+
const targetDir = path.join(this.buildDir, entryDir)
65+
if (fs.existsSync(targetDir)) {
66+
fs.rmSync(targetDir, { recursive: true, force: true })
67+
this.removeEmptyParentDirs(path.dirname(targetDir))
68+
}
69+
return
70+
}
71+
72+
;[
73+
`${entryKey}.js`,
74+
`${entryKey}.js.map`,
75+
`${entryKey}.css.json`,
76+
`${entryKey}.template.json`
77+
].forEach((relativeFile) => {
78+
const targetFile = path.join(this.buildDir, relativeFile)
79+
if (!fs.existsSync(targetFile)) {
80+
return
81+
}
82+
fs.unlinkSync(targetFile)
83+
this.removeEmptyParentDirs(path.dirname(targetFile))
84+
})
85+
})
86+
}
87+
88+
removeEmptyParentDirs(dir) {
89+
while (dir && dir.startsWith(this.buildDir) && dir !== this.buildDir) {
90+
if (!fs.existsSync(dir) || fs.readdirSync(dir).length > 0) {
91+
return
92+
}
93+
fs.rmdirSync(dir)
94+
dir = path.dirname(dir)
95+
}
96+
}
97+
4298
apply(compiler) {
4399
compiler.hooks.watchRun.tapAsync('watch', (compiler, callback) => {
44100
eventBus.emit(PACKAGER_WATCH_START)
45101
logger.clear()
46102
try {
47103
const modifiedFiles = compiler.modifiedFiles
48-
// 当发生变化的文件是 app.json,且 list 列表有增/删时,更新入口文件
49-
// TODO 页面减少时不会移除 entry
50-
// https://stackoverflow.com/a/39401288/1087831
104+
// 当发生变化的文件是 manifest.json,且入口列表有增删时,更新当前编译入口
51105
if (modifiedFiles && modifiedFiles.has(this.manifestFile)) {
52106
/** @readonly */
53107
const manifest = readJson(this.manifestFile)
54108
const entries = resolveEntries(manifest, this.root, this.appRoot)
55-
const newList = Object.keys(entries)
56-
if (this.hasChanged(newList)) {
57-
// 增删页面要修改 webpack entries
58-
this.list = newList
59-
compiler.options.entry = entries
109+
const { changed, removedEntries } = this.updateEntries(entries)
110+
if (changed) {
111+
this.removeBuildArtifacts(removedEntries)
60112
}
61113
}
62114
} catch (err) {

0 commit comments

Comments
 (0)