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
23 changes: 19 additions & 4 deletions packages/hap-packager/src/common/info.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ export function resolveFile(scriptFilePath) {
* @return {array}
*/
export function getEntryFiles(entry) {
const entryFiles = Object.keys(entry || {}).map((file) => {
const normalizedEntry = getNormalizedEntry(entry)
const entryFiles = Object.keys(normalizedEntry).map((file) => {
return file + '.js'
})
return entryFiles
Expand All @@ -47,9 +48,10 @@ export function getEntryFiles(entry) {
*/
export function getLiteEntryFiles(entry) {
const liteEntry = []
Object.keys(entry || {}).forEach((file) => {
const fileInfo = entry[file]
const importStr = fileInfo.import[0] || ''
const normalizedEntry = getNormalizedEntry(entry)
Object.keys(normalizedEntry).forEach((file) => {
const fileInfo = normalizedEntry[file]
const importStr = (fileInfo && fileInfo.import && fileInfo.import[0]) || ''
if (importStr.indexOf('?') >= 0) {
const paramStr = importStr.split('?')[1]
const paramArr = paramStr.split('&')
Expand All @@ -61,6 +63,19 @@ export function getLiteEntryFiles(entry) {
return liteEntry
}

/**
* 获取当前生效的 webpack entry 配置。
* 支持 watch 模式下通过 entry 函数动态刷新入口。
* @param {object|function} entry
* @return {object}
*/
export function getNormalizedEntry(entry) {
if (typeof entry === 'function') {
return entry() || {}
}
return entry || {}
}

/**
* 获取骨架屏配置信息
* @param {String} src - 项目src路径
Expand Down
10 changes: 7 additions & 3 deletions packages/hap-packager/src/plugins/handler-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

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

let ConcatSource

Expand All @@ -22,6 +22,7 @@ HandlerPlugin.prototype.apply = function (compiler) {
ConcatSource = compiler.webpack.sources.ConcatSource
const workersPath = this.options.workers
const enableE2e = this.options.enableE2e
const entryState = this.options.entryState
compiler.hooks.compilation.tap('HandlerPlugin', function (compilation) {
compilation.hooks.processAssets.tap(
{
Expand All @@ -30,8 +31,11 @@ HandlerPlugin.prototype.apply = function (compiler) {
},
() => {
// 如果进行抽取公共js则需通过入口文件来判断是不是抽取出的Chunks
const entryFiles = getEntryFiles(compiler.options.entry)
const liteEntryFiles = getLiteEntryFiles(compiler.options.entry)
const currentEntry = entryState
? entryState.current
: getNormalizedEntry(compiler.options.entry)
const entryFiles = getEntryFiles(currentEntry)
const liteEntryFiles = getLiteEntryFiles(currentEntry)
const { originType } = compileOptionsObject || {}
const isDevMode = globalConfig.mode === 'development'
compilation.chunks.forEach(function (chunk) {
Expand Down
9 changes: 6 additions & 3 deletions packages/hap-packager/src/plugins/resource-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
globalConfig
} from '@hap-toolkit/shared-utils'

import { name } from '../common/info'
import { name, getNormalizedEntry } from '../common/info'
import { updateManifest } from '../common/shared'

const { PACKAGER_BUILD_DONE } = eventBus
Expand Down Expand Up @@ -221,10 +221,13 @@ ResourcePlugin.prototype.apply = function (compiler) {
const webpackOptions = compiler.options
// 监听时处理
compiler.hooks.watchRun.tapAsync('ResourcePlugin', function (watching, callback) {
Object.keys(webpackOptions.entry).forEach(function (key) {
const currentEntry = options.entryState
? options.entryState.current
: getNormalizedEntry(webpackOptions.entry)
Object.keys(currentEntry).forEach(function (key) {
// 重置 changedJS
globalConfig.changedJS = {}
const val = webpackOptions.entry[key]
const val = currentEntry[key]
if (val instanceof Array && !/app\.js/.test(key)) {
// 删除webpack-dev-server注入的watch依赖
val[0].indexOf('webpack-dev-server') !== -1 && val.shift()
Expand Down
7 changes: 5 additions & 2 deletions packages/hap-packager/src/plugins/splitchunks-adapt-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import path from 'path'
import Compilation from 'webpack/lib/Compilation'
import { getEntryFiles } from '../common/info'
import { getEntryFiles, getNormalizedEntry } from '../common/info'
import { compileOptionsMeta } from '@hap-toolkit/shared-utils'
import { isEmptyObject } from '@hap-toolkit/compiler'

Expand Down Expand Up @@ -106,7 +106,10 @@ class SplitChunksAdaptPlugin {

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

const chunksMap = Array.from(chunks)
.filter((chunk) => {
Expand Down
8 changes: 0 additions & 8 deletions packages/hap-packager/src/post-handler/lite-card-post.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,6 @@
}
} else if (Array.isArray(actions.url)) {
let hasBinding = false
const rawUrlList = actions.url.map((url) => {
if (isExpr(url)) {
hasBinding = true
let { rawExpr } = getPrefixExpr(url)
return `{{${rawExpr}}}`
}
return url
})

const prefixUrlList = actions.url.map((url) => {
if (isExpr(url)) {
Expand All @@ -83,7 +75,7 @@

if (hasBinding) {
delete actions.url
actions['$url'] = rawUrlList

Check failure on line 78 in packages/hap-packager/src/post-handler/lite-card-post.js

View workflow job for this annotation

GitHub Actions / unit-test

'rawUrlList' is not defined

Check failure on line 78 in packages/hap-packager/src/post-handler/lite-card-post.js

View workflow job for this annotation

GitHub Actions / test-cov

'rawUrlList' is not defined
actions['#url'] = prefixUrlList
}
}
Expand Down
4 changes: 4 additions & 0 deletions packages/hap-packager/src/webpack.post.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ function postHook(webpackConf, defaultsOptions, quickappConfig = {}) {
pathSrc,
subpackages,
workers,
entryState,
originType,
useTreeShaking
} = defaultsOptions
Expand Down Expand Up @@ -119,6 +120,7 @@ function postHook(webpackConf, defaultsOptions, quickappConfig = {}) {
if (globalConfig.isSmartMode) {
webpackConf.plugins.push(
new SplitChunksAdaptPlugin({
entryState,
subpackages,
disableSubpackages: compileOptionsObject.disableSubpackages
})
Expand All @@ -133,6 +135,7 @@ function postHook(webpackConf, defaultsOptions, quickappConfig = {}) {
new HandlerPlugin({
pathSrc: pathSrc,
workers: workers,
entryState,
enableE2e: compileOptionsObject.enableE2e,
useTreeShaking
}),
Expand All @@ -143,6 +146,7 @@ function postHook(webpackConf, defaultsOptions, quickappConfig = {}) {
new ResourcePlugin({
src: pathSrc,
dest: pathBuild,
entryState,
comment: rpkComment,
projectRoot: globalConfig.projectPath,
configDebugInManifest,
Expand Down
8 changes: 6 additions & 2 deletions packages/hap-toolkit/src/gen-webpack-conf/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ export default async function genWebpackConf(launchOptions, mode) {

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

// 环境变量
const env = {
Expand Down Expand Up @@ -228,7 +229,7 @@ export default async function genWebpackConf(launchOptions, mode) {
context: cwd,
mode,
cache,
entry: entries,
entry: () => entryState.current,
output: {
globalObject: 'window',
path: BUILD_DIR,
Expand Down Expand Up @@ -293,7 +294,9 @@ export default async function genWebpackConf(launchOptions, mode) {
},
new ManifestWatchPlugin({
appRoot: cwd,
root: SRC_DIR
root: SRC_DIR,
buildDir: BUILD_DIR,
entryState
})
],
resolve: {
Expand Down Expand Up @@ -503,6 +506,7 @@ export default async function genWebpackConf(launchOptions, mode) {
useTreeShaking:
quickappConfig && quickappConfig.useTreeShaking ? !!quickappConfig.useTreeShaking : false,
workers,
entryState,
cwd,
originType: compileOptionsObject.originType,
ideConfig: launchOptions.ideConfig
Expand Down
78 changes: 65 additions & 13 deletions packages/hap-toolkit/src/plugins/manifest-watch-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import path from 'path'
import fs from 'fs'
import { colorconsole, readJson, logger, eventBus } from '@hap-toolkit/shared-utils'
import { resolveEntries } from '../utils'

Expand All @@ -21,6 +22,8 @@ export default class ManifestWatchPlugin {
constructor(options) {
this.appRoot = options.appRoot
this.root = options.root
this.buildDir = options.buildDir
this.entryState = options.entryState
this.manifestFile = path.resolve(this.root, 'manifest.json')
let entries = {}
try {
Expand All @@ -31,32 +34,81 @@ export default class ManifestWatchPlugin {
this.list = Object.keys(entries)
this.list = sort(this.list)
}
hasChanged(newList) {
const sorted = sort(newList)
const changed = JSON.stringify(sorted) !== JSON.stringify(this.list)

getRemovedEntries(newList) {
const newSet = new Set(newList)
return this.list.filter((key) => !newSet.has(key))
}

updateEntries(entries) {
const newList = sort(Object.keys(entries))
const removedEntries = this.getRemovedEntries(newList)
const changed = JSON.stringify(newList) !== JSON.stringify(this.list)
if (changed) {
this.list = sorted
this.list = newList
this.entryState && (this.entryState.current = entries)
}
return {
changed,
removedEntries
}
return changed
}

removeBuildArtifacts(entryKeys) {
if (!this.buildDir || !entryKeys || entryKeys.length === 0) {
return
}
entryKeys.forEach((entryKey) => {
const entryDir = path.dirname(entryKey)
if (entryDir && entryDir !== '.') {
const targetDir = path.join(this.buildDir, entryDir)
if (fs.existsSync(targetDir)) {
fs.rmSync(targetDir, { recursive: true, force: true })
this.removeEmptyParentDirs(path.dirname(targetDir))
}
return
}

;[
`${entryKey}.js`,
`${entryKey}.js.map`,
`${entryKey}.css.json`,
`${entryKey}.template.json`
].forEach((relativeFile) => {
const targetFile = path.join(this.buildDir, relativeFile)
if (!fs.existsSync(targetFile)) {
return
}
fs.unlinkSync(targetFile)
this.removeEmptyParentDirs(path.dirname(targetFile))
})
})
}

removeEmptyParentDirs(dir) {
while (dir && dir.startsWith(this.buildDir) && dir !== this.buildDir) {
if (!fs.existsSync(dir) || fs.readdirSync(dir).length > 0) {
return
}
fs.rmdirSync(dir)
dir = path.dirname(dir)
}
}

apply(compiler) {
compiler.hooks.watchRun.tapAsync('watch', (compiler, callback) => {
eventBus.emit(PACKAGER_WATCH_START)
logger.clear()
try {
const modifiedFiles = compiler.modifiedFiles
// 当发生变化的文件是 app.json,且 list 列表有增/删时,更新入口文件
// TODO 页面减少时不会移除 entry
// https://stackoverflow.com/a/39401288/1087831
// 当发生变化的文件是 manifest.json,且入口列表有增删时,更新当前编译入口
if (modifiedFiles && modifiedFiles.has(this.manifestFile)) {
/** @readonly */
const manifest = readJson(this.manifestFile)
const entries = resolveEntries(manifest, this.root, this.appRoot)
const newList = Object.keys(entries)
if (this.hasChanged(newList)) {
// 增删页面要修改 webpack entries
this.list = newList
compiler.options.entry = entries
const { changed, removedEntries } = this.updateEntries(entries)
if (changed) {
this.removeBuildArtifacts(removedEntries)
}
}
} catch (err) {
Expand Down
Loading