From 2972d0c28ed232266bf5466f3354249d2d253f2f Mon Sep 17 00:00:00 2001 From: fxy060608 Date: Wed, 28 Apr 2021 15:56:26 +0800 Subject: [PATCH] feat(easycom): support hmr --- packages/shims-uni-app.d.ts | 6 ++ packages/uni-cli-shared/src/index.ts | 2 +- packages/uni-cli-shared/src/json/index.ts | 3 + .../uni-cli-shared/src/{ => json}/json.ts | 2 +- packages/uni-cli-shared/src/json/manifest.ts | 14 ++++ .../src/json/pages.ts} | 20 +++++- packages/uni-cli-shared/tsconfig.json | 6 +- packages/uni-shared/dist/uni-shared.cjs.js | 4 +- packages/uni-shared/dist/uni-shared.d.ts | 2 +- packages/uni-shared/dist/uni-shared.esm.js | 4 +- packages/uni-shared/src/utils.ts | 9 ++- packages/vite-plugin-uni/src/config/build.ts | 4 +- packages/vite-plugin-uni/src/config/define.ts | 18 +++-- .../src/configResolved/plugins/pagesJson.ts | 6 +- .../src/configureServer/easycom.ts | 7 +- .../src/handleHotUpdate/index.ts | 64 ++++++++++++------ packages/vite-plugin-uni/src/utils/easycom.ts | 65 +++++++++++------- .../src/utils/{define.ts => features.ts} | 67 +++++++++---------- packages/vite-plugin-uni/src/utils/index.ts | 3 +- 19 files changed, 201 insertions(+), 105 deletions(-) create mode 100644 packages/uni-cli-shared/src/json/index.ts rename packages/uni-cli-shared/src/{ => json}/json.ts (80%) create mode 100644 packages/uni-cli-shared/src/json/manifest.ts rename packages/{vite-plugin-uni/src/utils/pagesJson.ts => uni-cli-shared/src/json/pages.ts} (93%) rename packages/vite-plugin-uni/src/utils/{define.ts => features.ts} (84%) diff --git a/packages/shims-uni-app.d.ts b/packages/shims-uni-app.d.ts index 9297d1cbe..25b621c23 100644 --- a/packages/shims-uni-app.d.ts +++ b/packages/shims-uni-app.d.ts @@ -173,6 +173,12 @@ declare namespace UniApp { topWindow?: PagesJsonWindowOptions leftWindow?: PagesJsonWindowOptions rightWindow?: PagesJsonWindowOptions + easycom?: { + autoscan?: boolean + custom?: { + [name: string]: string + } + } } interface TabBarItemBaseOptions { diff --git a/packages/uni-cli-shared/src/index.ts b/packages/uni-cli-shared/src/index.ts index 516d35bce..bb5fe1ab4 100644 --- a/packages/uni-cli-shared/src/index.ts +++ b/packages/uni-cli-shared/src/index.ts @@ -3,4 +3,4 @@ export * from './url' export * from './json' export * from './utils' export * from './constants' -export * from './preprocess/index' +export * from './preprocess' diff --git a/packages/uni-cli-shared/src/json/index.ts b/packages/uni-cli-shared/src/json/index.ts new file mode 100644 index 000000000..53e718010 --- /dev/null +++ b/packages/uni-cli-shared/src/json/index.ts @@ -0,0 +1,3 @@ +export * from './json' +export * from './pages' +export * from './manifest' diff --git a/packages/uni-cli-shared/src/json.ts b/packages/uni-cli-shared/src/json/json.ts similarity index 80% rename from packages/uni-cli-shared/src/json.ts rename to packages/uni-cli-shared/src/json/json.ts index 5fec9d929..491ba73aa 100644 --- a/packages/uni-cli-shared/src/json.ts +++ b/packages/uni-cli-shared/src/json/json.ts @@ -1,5 +1,5 @@ import { parse } from 'jsonc-parser' -import { preJson } from './preprocess' +import { preJson } from '../preprocess' export function parseJson(jsonStr: string, shouldPre: boolean = false) { return parse(shouldPre ? preJson(jsonStr) : jsonStr) diff --git a/packages/uni-cli-shared/src/json/manifest.ts b/packages/uni-cli-shared/src/json/manifest.ts new file mode 100644 index 000000000..b01ada025 --- /dev/null +++ b/packages/uni-cli-shared/src/json/manifest.ts @@ -0,0 +1,14 @@ +import fs from 'fs' +import path from 'path' + +import { once } from '@dcloudio/uni-shared' + +import { parseJson } from './json' + +export const parseManifestJson = (inputDir: string) => { + return parseJson( + fs.readFileSync(path.join(inputDir, 'manifest.json'), 'utf8') + ) +} + +export const parseManifestJsonOnce = once(parseManifestJson) diff --git a/packages/vite-plugin-uni/src/utils/pagesJson.ts b/packages/uni-cli-shared/src/json/pages.ts similarity index 93% rename from packages/vite-plugin-uni/src/utils/pagesJson.ts rename to packages/uni-cli-shared/src/json/pages.ts index 6e6a38f20..77332cc29 100644 --- a/packages/vite-plugin-uni/src/utils/pagesJson.ts +++ b/packages/uni-cli-shared/src/json/pages.ts @@ -1,8 +1,24 @@ +import fs from 'fs' import path from 'path' import slash from 'slash' import { extend, hasOwn, isArray, isPlainObject } from '@vue/shared' -import { parseJson } from '@dcloudio/uni-cli-shared' -import { TABBAR_HEIGHT } from '@dcloudio/uni-shared' +import { once, TABBAR_HEIGHT } from '@dcloudio/uni-shared' + +import { parseJson } from './json' + +export const parsePagesJson = ( + inputDir: string, + platform: UniApp.PLATFORM, + normalize: boolean = true +) => { + const jsonStr = fs.readFileSync(path.join(inputDir, 'pages.json'), 'utf8') + if (normalize) { + return normalizePagesJson(jsonStr, platform) + } + return parseJson(jsonStr, true) as UniApp.PagesJson +} + +export const parsePagesJsonOnce = once(parsePagesJson) export function normalizePagesJson(jsonStr: string, platform: UniApp.PLATFORM) { let pagesJson: UniApp.PagesJson = { diff --git a/packages/uni-cli-shared/tsconfig.json b/packages/uni-cli-shared/tsconfig.json index ac63115cc..4f11ce016 100644 --- a/packages/uni-cli-shared/tsconfig.json +++ b/packages/uni-cli-shared/tsconfig.json @@ -3,5 +3,9 @@ "compilerOptions": { "outDir": "dist" }, - "include": ["src"] + "include": [ + "src", + "../shims-node.d.ts", + "../shims-uni-app.d.ts" + ] } diff --git a/packages/uni-shared/dist/uni-shared.cjs.js b/packages/uni-shared/dist/uni-shared.cjs.js index 4b25cb775..df73d1e47 100644 --- a/packages/uni-shared/dist/uni-shared.cjs.js +++ b/packages/uni-shared/dist/uni-shared.cjs.js @@ -185,13 +185,13 @@ function updateElementStyle(element, styles) { } function once(fn, ctx = null) { let res; - return (...args) => { + return ((...args) => { if (fn) { res = fn.apply(ctx, args); fn = null; } return res; - }; + }); } const encode = encodeURIComponent; diff --git a/packages/uni-shared/dist/uni-shared.d.ts b/packages/uni-shared/dist/uni-shared.d.ts index b713026f7..f07d70b98 100644 --- a/packages/uni-shared/dist/uni-shared.d.ts +++ b/packages/uni-shared/dist/uni-shared.d.ts @@ -49,7 +49,7 @@ export declare function normalizeTarget(el: HTMLElement): { export declare const ON_REACH_BOTTOM_DISTANCE = 50; -export declare function once(fn: (...args: any[]) => any, ctx?: unknown): (...args: any[]) => any; +export declare function once any>(fn: T, ctx?: unknown): T; /** * https://github.com/vuejs/vue-router-next/blob/master/src/query.ts diff --git a/packages/uni-shared/dist/uni-shared.esm.js b/packages/uni-shared/dist/uni-shared.esm.js index f7deb8eef..27e43e652 100644 --- a/packages/uni-shared/dist/uni-shared.esm.js +++ b/packages/uni-shared/dist/uni-shared.esm.js @@ -181,13 +181,13 @@ function updateElementStyle(element, styles) { } function once(fn, ctx = null) { let res; - return (...args) => { + return ((...args) => { if (fn) { res = fn.apply(ctx, args); fn = null; } return res; - }; + }); } const encode = encodeURIComponent; diff --git a/packages/uni-shared/src/utils.ts b/packages/uni-shared/src/utils.ts index 0c532cd8b..d9935c9ad 100644 --- a/packages/uni-shared/src/utils.ts +++ b/packages/uni-shared/src/utils.ts @@ -23,13 +23,16 @@ export function updateElementStyle( } } -export function once(fn: (...args: any[]) => any, ctx: unknown = null) { +export function once any>( + fn: T, + ctx: unknown = null +): T { let res: any - return (...args: any[]) => { + return ((...args: any[]) => { if (fn) { res = fn.apply(ctx, args) fn = null as any } return res - } + }) as T } diff --git a/packages/vite-plugin-uni/src/config/build.ts b/packages/vite-plugin-uni/src/config/build.ts index 154ef1ae9..a55b8a255 100644 --- a/packages/vite-plugin-uni/src/config/build.ts +++ b/packages/vite-plugin-uni/src/config/build.ts @@ -2,13 +2,13 @@ import path from 'path' import slash from 'slash' import { UserConfig } from 'vite' import { VitePluginUniResolvedOptions } from '..' -import { FEATURE_DEFINES, initEasycoms } from '../utils' +import { FEATURE_DEFINES, initEasycomsOnce } from '../utils' export function createBuild( options: VitePluginUniResolvedOptions, features: FEATURE_DEFINES ): UserConfig['build'] { - initEasycoms(options.inputDir) + initEasycomsOnce(options.inputDir, options.platform) return { polyfillDynamicImport: features.__UNI_FEATURE_PAGES__, rollupOptions: { diff --git a/packages/vite-plugin-uni/src/config/define.ts b/packages/vite-plugin-uni/src/config/define.ts index ecbdde4bf..bad8a1db4 100644 --- a/packages/vite-plugin-uni/src/config/define.ts +++ b/packages/vite-plugin-uni/src/config/define.ts @@ -1,10 +1,20 @@ import { ConfigEnv, UserConfig } from 'vite' import { VitePluginUniResolvedOptions } from '..' -import { getFeatures } from '../utils' +import { + parsePagesJsonOnce, + parseManifestJsonOnce, +} from '@dcloudio/uni-cli-shared' +import { initFeatures } from '../utils' export function createDefine( - options: VitePluginUniResolvedOptions, - env: ConfigEnv + { inputDir, platform }: VitePluginUniResolvedOptions, + { command }: ConfigEnv ): UserConfig['define'] { - return getFeatures(options, env.command) + return initFeatures({ + inputDir, + command, + platform, + pagesJson: parsePagesJsonOnce(inputDir, platform), + manifestJson: parseManifestJsonOnce(inputDir), + }) } diff --git a/packages/vite-plugin-uni/src/configResolved/plugins/pagesJson.ts b/packages/vite-plugin-uni/src/configResolved/plugins/pagesJson.ts index a8da3e36a..4c624bb96 100644 --- a/packages/vite-plugin-uni/src/configResolved/plugins/pagesJson.ts +++ b/packages/vite-plugin-uni/src/configResolved/plugins/pagesJson.ts @@ -4,13 +4,13 @@ import slash from 'slash' import { Plugin, ResolvedConfig } from 'vite' import { parse } from 'jsonc-parser' import { camelize, capitalize } from '@vue/shared' +import { normalizePagesJson } from '@dcloudio/uni-cli-shared' import { VitePluginUniResolvedOptions } from '../..' import { BASE_COMPONENTS_STYLE_PATH, FEATURE_DEFINES, H5_API_STYLE_PATH, H5_FRAMEWORK_STYLE_PATH, - normalizePagesJson, } from '../../utils' const pkg = require('@dcloudio/vite-plugin-uni/package.json') @@ -35,7 +35,7 @@ export function uniPagesJsonPlugin( code: (config.define!.__UNI_FEATURE_RPX__ ? registerGlobalCode : '') + (options.command === 'serve' ? registerDevServerGlobalCode : '') + - parsePagesJson(code, config, options), + generatePagesJsonCode(code, config, options), map: { mappings: '' }, } } @@ -54,7 +54,7 @@ interface PageRouteOptions { meta: Partial } -function parsePagesJson( +function generatePagesJsonCode( jsonStr: string, config: ResolvedConfig, options: VitePluginUniResolvedOptions diff --git a/packages/vite-plugin-uni/src/configureServer/easycom.ts b/packages/vite-plugin-uni/src/configureServer/easycom.ts index 35b58773a..dd8770856 100644 --- a/packages/vite-plugin-uni/src/configureServer/easycom.ts +++ b/packages/vite-plugin-uni/src/configureServer/easycom.ts @@ -1,13 +1,16 @@ import { ViteDevServer } from 'vite' import { debounce } from '@dcloudio/uni-shared' import { VitePluginUniResolvedOptions } from '..' -import { debugEasycom, initEasycoms } from '../utils' +import { debugEasycom, initEasycomsOnce } from '../utils' export const serveEasycom = ( server: ViteDevServer, options: VitePluginUniResolvedOptions ) => { - const { filter, refresh } = initEasycoms(options.inputDir) + const { filter, refresh } = initEasycomsOnce( + options.inputDir, + options.platform + ) const refreshEasycom = debounce(refresh, 100) server.watcher.on('all', (eventName, path) => { if (!['add', 'unlink'].includes(eventName)) { diff --git a/packages/vite-plugin-uni/src/handleHotUpdate/index.ts b/packages/vite-plugin-uni/src/handleHotUpdate/index.ts index 69ba720c7..597f1d1fb 100644 --- a/packages/vite-plugin-uni/src/handleHotUpdate/index.ts +++ b/packages/vite-plugin-uni/src/handleHotUpdate/index.ts @@ -2,8 +2,11 @@ import path from 'path' import debug from 'debug' import slash from 'slash' import { ModuleGraph, Plugin } from 'vite' + +import { parseManifestJson, parsePagesJson } from '@dcloudio/uni-cli-shared' + import { VitePluginUniResolvedOptions } from '..' -import { getFeatures } from '../utils' +import { initEasycomsOnce, initFeatures } from '../utils' const debugHmr = debug('uni:hmr') @@ -16,14 +19,12 @@ async function invalidate(file: string, moduleGraph: ModuleGraph) { }) } } - let invalidateFiles: string[] export function createHandleHotUpdate( options: VitePluginUniResolvedOptions ): Plugin['handleHotUpdate'] { return async function ({ file, server }) { if (!invalidateFiles) { - // options.inputDir 的赋值时机是在config中,不能直接使用在上边声明使用 invalidateFiles = [ path.resolve(options.inputDir, 'pages.json.js'), path.resolve(options.inputDir, 'manifest.json.js'), @@ -34,24 +35,49 @@ export function createHandleHotUpdate( // TODO 目前简单处理,当pages.json,manifest.json发生变化,就直接刷新,理想情况下,应该区分变化的内容,仅必要时做整页面刷新 const isPagesJson = file.endsWith('pages.json') const isManifestJson = file.endsWith('manifest.json') - if (isPagesJson || isManifestJson) { - debugHmr(file) - server.ws.send({ - type: 'custom', - event: 'invalidate', - data: {}, + if (!isPagesJson && !isManifestJson) { + return + } + debugHmr(file) + server.ws.send({ + type: 'custom', + event: 'invalidate', + data: {}, + }) + const { inputDir, command, platform } = options + const pagesJson = parsePagesJson(inputDir, platform) + // 更新define + Object.assign( + server.config.define!, + initFeatures({ + inputDir, + command, + platform, + pagesJson, + manifestJson: parseManifestJson(inputDir), }) - // 更新define - Object.assign( - server.config.define!, - getFeatures(options, server.config.command) - ) - debugHmr('define', server.config.define) - // 当pages.json,manifest.json发生变化时,作废pages.json.js缓存 - for (const file of invalidateFiles) { - await invalidate(file, server.moduleGraph) + ) + debugHmr('define', server.config.define) + if (isPagesJson) { + const easycom = pagesJson.easycom || {} + const { options, refresh } = initEasycomsOnce(inputDir, platform) + if ( + !equal( + { autoscan: easycom.autoscan, custom: easycom.custom }, + { autoscan: options.autoscan, custom: options.custom } + ) + ) { + refresh() } - return [] } + // 当pages.json,manifest.json发生变化时,作废pages.json.js缓存 + for (const file of invalidateFiles) { + await invalidate(file, server.moduleGraph) + } + return [] } } + +function equal(obj1: Record, obj2: Record) { + return JSON.stringify(obj1) === JSON.stringify(obj2) +} diff --git a/packages/vite-plugin-uni/src/utils/easycom.ts b/packages/vite-plugin-uni/src/utils/easycom.ts index fb63caffd..f6c415a55 100644 --- a/packages/vite-plugin-uni/src/utils/easycom.ts +++ b/packages/vite-plugin-uni/src/utils/easycom.ts @@ -5,12 +5,14 @@ import debug from 'debug' import { createFilter } from '@rollup/pluginutils' import { once } from '@dcloudio/uni-shared' +import { parsePagesJson, parsePagesJsonOnce } from '@dcloudio/uni-cli-shared' interface EasycomOption { dirs?: string[] rootDir?: string - custom?: EasycomCustom extensions?: string[] + autoscan?: boolean + custom?: EasycomCustom } interface EasycomMatcher { pattern: RegExp @@ -36,31 +38,44 @@ function clearEasycom() { easycomsInvalidCache.clear() } -export const initEasycoms = once((inputDir: string) => { - const componentsDir = path.resolve(inputDir, 'components') - const uniModulesDir = path.resolve(inputDir, 'uni_modules') - const initEasycomOptions = () => { - const easycomOptions = { - dirs: [componentsDir, ...initUniModulesEasycomDirs(uniModulesDir)], - rootDir: inputDir, - } - debugEasycom(easycomOptions) - return easycomOptions - } - initEasycom(initEasycomOptions()) - return { - filter: createFilter( - ['components/*/*.vue', 'uni_modules/*/components/*/*.vue'], - [], - { - resolve: inputDir, +export const initEasycomsOnce = once( + (inputDir: string, platform: UniApp.PLATFORM) => { + const componentsDir = path.resolve(inputDir, 'components') + const uniModulesDir = path.resolve(inputDir, 'uni_modules') + const initEasycomOptions = (pagesJson?: UniApp.PagesJson) => { + // 初始化时,从once中读取缓存,refresh时,实时读取 + const { easycom } = pagesJson || parsePagesJson(inputDir, platform, false) + const easycomOptions: EasycomOption = { + dirs: + easycom && easycom.autoscan === false + ? [] // 禁止自动扫描 + : [componentsDir, ...initUniModulesEasycomDirs(uniModulesDir)], + rootDir: inputDir, + autoscan: !!(easycom && easycom.autoscan), + custom: (easycom && easycom.custom) || {}, } - ), - refresh() { - initEasycom(initEasycomOptions()) - }, + debugEasycom(easycomOptions) + return easycomOptions + } + const options = initEasycomOptions(parsePagesJsonOnce(inputDir, platform)) + initEasycom(options) + const res = { + options, + filter: createFilter( + ['components/*/*.vue', 'uni_modules/*/components/*/*.vue'], + [], + { + resolve: inputDir, + } + ), + refresh() { + res.options = initEasycomOptions() + initEasycom(res.options) + }, + } + return res } -}) +) function initUniModulesEasycomDirs(uniModulesDir: string) { if (!fs.existsSync(uniModulesDir)) { @@ -89,7 +104,7 @@ function initEasycom({ }: EasycomOption) { clearEasycom() const easycomsObj = Object.create(null) - if (dirs && rootDir) { + if (dirs && dirs.length && rootDir) { Object.assign(easycomsObj, initAutoScanEasycoms(dirs, rootDir, extensions)) } if (custom) { diff --git a/packages/vite-plugin-uni/src/utils/define.ts b/packages/vite-plugin-uni/src/utils/features.ts similarity index 84% rename from packages/vite-plugin-uni/src/utils/define.ts rename to packages/vite-plugin-uni/src/utils/features.ts index f09f639d9..190f3a076 100644 --- a/packages/vite-plugin-uni/src/utils/define.ts +++ b/packages/vite-plugin-uni/src/utils/features.ts @@ -1,10 +1,7 @@ import fs from 'fs' import path from 'path' import { ConfigEnv } from 'vite' -import { parse } from 'jsonc-parser' import { isArray } from '@vue/shared' -import { VitePluginUniResolvedOptions } from '..' -import { normalizePagesJson } from './pagesJson' interface ProjectFeatures {} interface PagesFeatures { @@ -35,20 +32,18 @@ interface ManifestFeatures { i18nZhHant: boolean } -function resolveProjectFeature( - options: VitePluginUniResolvedOptions, - command: ConfigEnv['command'] -) { +function initProjectFeature({ command }: InitFeaturesOptions) { const features: ProjectFeatures = {} if (command === 'build') { } return features } -function resolvePagesFeature( - options: VitePluginUniResolvedOptions, - command: ConfigEnv['command'] -): PagesFeatures { +function initPagesFeature({ + pagesJson, + command, + inputDir, +}: InitFeaturesOptions): PagesFeatures { const features: PagesFeatures = { nvue: true, pages: true, @@ -71,10 +66,7 @@ function resolvePagesFeature( leftWindow, rightWindow, globalStyle, - } = normalizePagesJson( - fs.readFileSync(path.join(options.inputDir, 'pages.json'), 'utf8'), - options.platform - ) + } = pagesJson if (pages && pages.length === 1) { features.pages = false } @@ -104,7 +96,7 @@ function resolvePagesFeature( if (command === 'build') { if ( !pages.find((page) => - fs.existsSync(path.resolve(options.inputDir, page.path, '.nvue')) + fs.existsSync(path.resolve(inputDir, page.path, '.nvue')) ) ) { features.nvue = false @@ -153,9 +145,11 @@ function resolvePagesFeature( return features } -function resolveManifestFeature( - options: VitePluginUniResolvedOptions -): ManifestFeatures { +function initManifestFeature({ + manifestJson, + command, + platform, +}: InitFeaturesOptions): ManifestFeatures { const features: ManifestFeatures = { wx: false, wxs: true, @@ -169,23 +163,21 @@ function resolveManifestFeature( i18nZhHans: true, i18nZhHant: true, } - const manifest = parse( - fs.readFileSync(path.join(options.inputDir, 'manifest.json'), 'utf8') - ) - if (options.command === 'build') { + + if (command === 'build') { // TODO 需要预编译一遍? features.wxs = false features.longpress = false } if ( - manifest.h5 && - manifest.h5.router && - manifest.h5.router.mode === 'history' + manifestJson.h5 && + manifestJson.h5.router && + manifestJson.h5.router.mode === 'history' ) { features.routerMode = '"history"' } - const platform = manifest[options.platform] || {} - const manifestFeatures = platform.features + const platformJson = manifestJson[platform] || {} + const manifestFeatures = platformJson.features if (manifestFeatures) { const { i18n } = manifestFeatures if (isArray(i18n)) { @@ -210,12 +202,17 @@ function resolveManifestFeature( return features } -export type FEATURE_DEFINES = ReturnType +export type FEATURE_DEFINES = ReturnType -export function getFeatures( - options: VitePluginUniResolvedOptions, +interface InitFeaturesOptions { + pagesJson: UniApp.PagesJson + manifestJson: any + inputDir: string + platform: UniApp.PLATFORM command: ConfigEnv['command'] -) { +} + +export function initFeatures(options: InitFeaturesOptions) { const { wx, wxs, @@ -241,9 +238,9 @@ export function getFeatures( navigationBarSearchInput, navigationBarTransparent, } = Object.assign( - resolveManifestFeature(options), - resolvePagesFeature(options, command), - resolveProjectFeature(options, command) + initManifestFeature(options), + initPagesFeature(options), + initProjectFeature(options) ) return { __UNI_FEATURE_WX__: wx, // 是否启用小程序的组件实例 API,如:selectComponent 等(uni-core/src/service/plugin/appConfig) diff --git a/packages/vite-plugin-uni/src/utils/index.ts b/packages/vite-plugin-uni/src/utils/index.ts index 177be9036..eb160998a 100644 --- a/packages/vite-plugin-uni/src/utils/index.ts +++ b/packages/vite-plugin-uni/src/utils/index.ts @@ -1,6 +1,5 @@ export * from './filter' -export * from './define' +export * from './features' export * from './easycom' export * from './postcss' -export * from './pagesJson' export * from './constants' -- GitLab