提交 1e730ae3 编写于 作者: fxy060608's avatar fxy060608

wip(app): app watcher

上级 ad69e765
......@@ -29,5 +29,7 @@ declare namespace NodeJS {
UNI_COMPILER: 'vue' | 'nvue'
UNI_RENDERER_NATIVE: 'appService' | 'pages'
UNI_NVUE_APP_STYLES: string
UNI_APP_CHANGED_FILES: string
UNI_APP_CHANGED_PAGES: string
}
}
......@@ -649,7 +649,10 @@ function getBaseSystemInfo() {
if (typeof __SYSTEM_INFO__ !== 'undefined') {
return window.__SYSTEM_INFO__;
}
const { resolutionWidth } = plus.screen.getCurrentSize();
// 好像开发时刷新,偶发的 plus.screen.getCurrentSize 为 undefined
const { resolutionWidth } = plus.screen.getCurrentSize() || {
resolutionWidth: 0,
};
return {
platform: (plus.os.name || '').toLowerCase(),
pixelRatio: plus.screen.scale,
......@@ -13043,7 +13046,11 @@ function deviceId$1 () {
}
function getScreenInfo() {
const { resolutionWidth, resolutionHeight } = plus.screen.getCurrentSize();
// 好像开发时刷新,偶发的 plus.screen.getCurrentSize 为 undefined
const { resolutionWidth, resolutionHeight } = plus.screen.getCurrentSize() || {
resolutionWidth: 0,
resolutionHeight: 0,
};
return {
screenWidth: Math.round(resolutionWidth),
screenHeight: Math.round(resolutionHeight),
......
......@@ -7,7 +7,10 @@ export function getBaseSystemInfo() {
if (typeof __SYSTEM_INFO__ !== 'undefined') {
return (window as any).__SYSTEM_INFO__
}
const { resolutionWidth } = plus.screen.getCurrentSize()
// 好像开发时刷新,偶发的 plus.screen.getCurrentSize 为 undefined
const { resolutionWidth } = plus.screen.getCurrentSize() || {
resolutionWidth: 0,
}
return {
platform: (plus.os.name || '').toLowerCase(),
pixelRatio: plus.screen.scale!,
......
......@@ -9,7 +9,12 @@ import deviceId from '../../../helpers/uuid'
type SafeAreaInsets = Required<PlusNavigatorSafeAreaInsets>
function getScreenInfo() {
const { resolutionWidth, resolutionHeight } = plus.screen.getCurrentSize()
// 好像开发时刷新,偶发的 plus.screen.getCurrentSize 为 undefined
const { resolutionWidth, resolutionHeight } =
plus.screen.getCurrentSize() || {
resolutionWidth: 0,
resolutionHeight: 0,
}
return {
screenWidth: Math.round(resolutionWidth),
screenHeight: Math.round(resolutionHeight),
......
......@@ -28,9 +28,8 @@ export function initNVuePlugins() {
uniManifestJsonPlugin(),
uniPagesJsonPlugin({ renderer, appService }),
uniViteInjectPlugin('uni:app-inject', initAppProvide()),
uniStatsPlugin(),
uniAppNVuePlugin({ appService }),
uniEsbuildPlugin({ renderer, appService }),
...(appService ? [uniTemplatePlugin({ renderer })] : []),
...(appService ? [uniStatsPlugin(), uniTemplatePlugin({ renderer })] : []),
]
}
import type { Plugin } from 'vite'
import type { Plugin, ResolvedConfig } from 'vite'
import type { BuildOptions, PluginBuild } from 'esbuild'
import path from 'path'
......@@ -7,6 +7,7 @@ import debug from 'debug'
import {
APP_CONFIG_SERVICE,
hash,
removeExt,
transformWithEsbuild,
} from '@dcloudio/uni-cli-shared'
......@@ -17,14 +18,18 @@ import { APP_CSS_JS } from './appCss'
const debugEsbuild = debug('uni:app-nvue-esbuild')
const emittedHashMap = new WeakMap<ResolvedConfig, Map<string, string>>()
export function uniEsbuildPlugin({
appService,
}: {
renderer?: 'native'
appService: boolean
}): Plugin {
let resolvedConfig: ResolvedConfig
let buildOptions: BuildOptions
const outputDir = process.env.UNI_OUTPUT_DIR
let isFirst = true
return {
name: 'uni:app-nvue-esbuild',
enforce: 'post',
......@@ -39,6 +44,8 @@ export function uniEsbuildPlugin({
write: false,
plugins: [esbuildGlobalPlugin(esbuildGlobals(appService))],
}
resolvedConfig = config
emittedHashMap.set(resolvedConfig, new Map<string, string>())
},
async writeBundle(_, bundle) {
const entryPoints: string[] = []
......@@ -55,14 +62,31 @@ export function uniEsbuildPlugin({
if (!entryPoints.length) {
return
}
buildAppCss()
const emittedHash = emittedHashMap.get(resolvedConfig)!
const changedFiles: string[] = []
if (buildAppCss()) {
changedFiles.push(APP_CONFIG_SERVICE)
}
debugEsbuild('start', entryPoints.length, entryPoints)
for (const filename of entryPoints) {
await buildNVuePage(filename, buildOptions).then((code) => {
return fs.outputFile(path.resolve(outputDir, filename), code)
const outputFileHash = hash(code)
if (emittedHash.get(filename) !== outputFileHash) {
changedFiles.push(filename)
emittedHash.set(filename, outputFileHash)
return fs.outputFile(path.resolve(outputDir, filename), code)
}
})
}
if (!isFirst && changedFiles.length) {
process.env[
changedFiles.includes(APP_CONFIG_SERVICE)
? 'UNI_APP_CHANGED_FILES'
: 'UNI_APP_CHANGED_PAGES'
] = JSON.stringify(changedFiles)
}
debugEsbuild('end')
isFirst = false
},
}
}
......@@ -76,28 +100,29 @@ function buildAppCss() {
if (!fs.existsSync(appCssJsFilename)) {
return
}
const appConfigServiceFilename = path.join(
process.env.UNI_OUTPUT_DIR,
APP_CONFIG_SERVICE
)
if (!fs.existsSync(appConfigServiceFilename)) {
return
}
const appCssJsCode = fs.readFileSync(appCssJsFilename, 'utf8')
const appCssJsFn = new Function('exports', appCssJsCode)
const exports = { styles: [] }
appCssJsFn(exports)
const appCssJsonCode = JSON.stringify(exports.styles)
if (process.env.UNI_NVUE_APP_STYLES === appCssJsonCode) {
return
}
process.env.UNI_NVUE_APP_STYLES = appCssJsonCode
// 首次 build 时,可能还没生成 app-config-service 的文件,故仅写入环境变量
const appConfigServiceFilename = path.join(
process.env.UNI_OUTPUT_DIR,
APP_CONFIG_SERVICE
)
if (!fs.existsSync(appConfigServiceFilename)) {
return
}
const appConfigServiceCode = fs.readFileSync(appConfigServiceFilename, 'utf8')
fs.writeFileSync(
appConfigServiceFilename,
wrapperNVueAppStyles(appConfigServiceCode)
)
return true
}
function buildNVuePage(filename: string, options: BuildOptions) {
......
import { extend } from '@vue/shared'
import { RollupWatcher } from 'rollup'
import { BuildOptions, createLogger, ServerOptions } from 'vite'
import { M, output } from '@dcloudio/uni-cli-shared'
import { APP_CONFIG_SERVICE, M, output } from '@dcloudio/uni-cli-shared'
import { CliOptions } from '.'
import { build, buildSSR } from './build'
import { createServer, createSSRServer } from './server'
......@@ -42,11 +42,20 @@ export async function runDev(options: CliOptions & ServerOptions) {
)
}
const files = process.env.UNI_APP_CHANGED_FILES
if (files && !files.includes('app-config-service.js')) {
process.env.UNI_APP_CHANGED_FILES = ''
const pages = process.env.UNI_APP_CHANGED_PAGES
const changedFiles = pages || files
process.env.UNI_APP_CHANGED_PAGES = ''
process.env.UNI_APP_CHANGED_FILES = ''
if (changedFiles && !changedFiles.includes(APP_CONFIG_SERVICE)) {
if (pages) {
return output(
'log',
M['dev.watching.end.pages'].replace('{pages}', changedFiles)
)
}
return output(
'log',
M['dev.watching.end.files'].replace('{files}', files)
M['dev.watching.end.files'].replace('{files}', changedFiles)
)
}
return output('log', M['dev.watching.end'])
......
......@@ -98,6 +98,10 @@ export async function buildApp(options: CliOptions) {
if ((options as BuildOptions).manifest) {
return buildManifestJson()
}
let appWatcher: AppWatcher | undefined
if ((options as ServerOptions).watch) {
appWatcher = new AppWatcher()
}
if (process.env.UNI_RENDERER === 'native') {
// 纯原生渲染时,main.js + App.vue 需要跟页面分开,独立编译(因为需要包含 Vuex 等共享内容)
process.env.UNI_COMPILER = 'nvue'
......@@ -105,11 +109,15 @@ export async function buildApp(options: CliOptions) {
const nvueAppBuilder = await buildByVite(
addConfigFile(
extend(
{ nvueApp: true, nvue: true },
{ nvueAppService: true, nvue: true },
initBuildOptions(options, cleanOptions(options) as BuildOptions)
)
)
)
if (appWatcher) {
appWatcher.setFirstWatcher(nvueAppBuilder as RollupWatcher)
}
process.env.UNI_RENDERER_NATIVE = 'pages'
const nvueBuilder = await buildByVite(
addConfigFile(
......@@ -119,12 +127,11 @@ export async function buildApp(options: CliOptions) {
)
)
)
if ((options as ServerOptions).watch) {
return initAppWatcher(
nvueAppBuilder as RollupWatcher,
nvueBuilder as RollupWatcher
)
if (appWatcher) {
appWatcher.setSecondWatcher(nvueBuilder as RollupWatcher)
return appWatcher
}
return
}
// 指定为 vue 方便 App 插件初始化 vue 所需插件列表
process.env.UNI_COMPILER = 'vue'
......@@ -133,6 +140,9 @@ export async function buildApp(options: CliOptions) {
initBuildOptions(options, cleanOptions(options) as BuildOptions)
)
)
if (appWatcher) {
appWatcher.setFirstWatcher(vueBuilder as RollupWatcher)
}
// 临时指定为 nvue 方便 App 插件初始化 nvue 所需插件列表
process.env.UNI_COMPILER = 'nvue'
const nvueBuilder = await buildByVite(
......@@ -146,11 +156,9 @@ export async function buildApp(options: CliOptions) {
// 还原为 vue
process.env.UNI_COMPILER = 'vue'
if ((options as ServerOptions).watch) {
return initAppWatcher(
vueBuilder as RollupWatcher,
nvueBuilder as RollupWatcher
)
if (appWatcher) {
appWatcher.setSecondWatcher(nvueBuilder as RollupWatcher)
return appWatcher
}
}
......@@ -160,9 +168,27 @@ class AppWatcher {
private _secondStart: boolean = false
private _secondEnd: boolean = false
private _callback!: (event: RollupWatcherEvent) => void
on(callback: (event: RollupWatcherEvent) => void) {
on(_event: string, callback: (event: RollupWatcherEvent) => void) {
this._callback = callback
}
setFirstWatcher(firstWatcher: RollupWatcher) {
firstWatcher.on('event', (event) => {
if (event.code === 'BUNDLE_START') {
this._bundleFirstStart(event)
} else if (event.code === 'BUNDLE_END') {
this._bundleFirstEnd(event)
}
})
}
setSecondWatcher(secondWatcher: RollupWatcher) {
secondWatcher.on('event', (event) => {
if (event.code === 'BUNDLE_START') {
this._bundleSecondStart(event)
} else if (event.code === 'BUNDLE_END') {
this._bundleSecondEnd(event)
}
})
}
_bundleFirstStart(event: RollupWatcherEvent) {
this._firstStart = true
this._bundleStart(event)
......@@ -190,29 +216,3 @@ class AppWatcher {
}
}
}
function initAppWatcher(
firstWatcher: RollupWatcher,
secondWatcher: RollupWatcher
) {
const appWatcher = new AppWatcher()
firstWatcher.on('event', (event) => {
if (event.code === 'BUNDLE_START') {
appWatcher._bundleFirstStart(event)
} else if (event.code === 'BUNDLE_END') {
appWatcher._bundleFirstEnd(event)
}
})
secondWatcher.on('event', (event) => {
if (event.code === 'BUNDLE_START') {
appWatcher._bundleSecondStart(event)
} else if (event.code === 'BUNDLE_END') {
appWatcher._bundleSecondEnd(event)
}
})
return {
on(_, fn) {
appWatcher.on(fn as (event: RollupWatcherEvent) => void)
},
} as RollupWatcher
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册