提交 137f4572 编写于 作者: fxy060608's avatar fxy060608

feat: hmr

上级 ba4ca932
declare var tt: any
declare var qa: any
declare var swan: any
declare var __PLATFORM__:
| 'h5'
| 'app-plus'
| 'mp-alipay'
| 'mp-baidu'
| 'mp-qq'
| 'mp-toutiao'
| 'mp-weixin'
| 'quickapp-webview'
declare var __PLATFORM__: UniApp.PLATFORM
declare var __PLATFORM_PREFIX__: 'wx' | 'qq' | 'my' | 'swan' | 'tt' | 'qa'
declare var __GLOBAL__: Record<string, any>
......@@ -22,6 +14,7 @@ declare var __VUE_OPTIONS_API__: boolean
declare var __UNI_FEATURE_WX__: boolean
declare var __UNI_FEATURE_WXS__: boolean
declare var __UNI_FEATURE_NVUE__: boolean
declare var __UNI_FEATURE_PROMISE__: boolean
declare var __UNI_FEATURE_LONGPRESS__: boolean
declare var __UNI_FEATURE_ROUTER_MODE__: 'hash' | 'history'
......
declare namespace UniApp {
type PLATFORM =
| 'h5'
| 'app-plus'
| 'mp-alipay'
| 'mp-baidu'
| 'mp-qq'
| 'mp-toutiao'
| 'mp-weixin'
| 'quickapp-webview'
interface LayoutWindowOptions {
matchMedia?: {
minWidth?: number
......@@ -53,22 +62,35 @@ declare namespace UniApp {
refreshOptions?: PageRefreshOptions
}
interface PagesJsonPageStyle {
enablePullDownRefresh?: boolean
}
interface PagesJsonPageOptions {
path: string
style?: Record<string, any>
style?: PagesJsonPageStyle
}
interface PagesJsonSubpackagesOptions {
root: string
pages: PagesJsonPageOptions[]
}
interface PagesJsonWindowOptions extends PagesJsonPageOptions {
matchMedia: {
minWidth: number
}
}
interface PagesJson {
pages: PagesJsonPageOptions[]
subpackages?: PagesJsonSubpackagesOptions[]
subPackages?: PagesJsonSubpackagesOptions[]
globalStyle?: {}
globalStyle?: PagesJsonPageStyle
tabBar?: {
list: []
}
topWindow?: PagesJsonWindowOptions
leftWindow?: PagesJsonWindowOptions
rightWindow?: PagesJsonWindowOptions
}
}
......@@ -987,12 +987,12 @@ var AppComponent = defineComponent({
setup() {
useCssVar();
useAppLifecycle();
const {appClass, onLayoutChange} = useAppClass();
const {clazz, onChange: onChange2} = useAppClass();
return () => (openBlock(), createBlock("uni-app", {
class: appClass.value
class: clazz.value
}, [
createVNode(Layout, {
onChange: onLayoutChange
onChange: onChange2
}, null, 8, ["onChange"])
], 2));
}
......@@ -1014,44 +1014,27 @@ function useAppLifecycle() {
function useAppClass() {
const showTabBar = ref(false);
const showMaxWidth = ref(false);
function onLayoutChange(type, value) {
function onChange2(type, value) {
if (type === "showTabBar") {
showTabBar.value = value;
} else if (type === "showMaxWidth") {
showMaxWidth.value = value;
}
}
const appClass = computed(() => {
const clazz = computed(() => {
return {
"uni-app--showtabbar": showTabBar.value,
"uni-app--maxwidth": showMaxWidth.value
};
});
return {
appClass,
onLayoutChange
clazz,
onChange: onChange2
};
}
const _sfc_main$r = {};
const _hoisted_1$d = /* @__PURE__ */ createVNode("uni-top-window", null, null, -1);
function _sfc_render$p(_ctx, _cache) {
const _component_router_view = resolveComponent("router-view");
return openBlock(), createBlock("uni-layout", null, [
_hoisted_1$d,
createVNode("uni-content", null, [
createVNode("uni-main", null, [
(openBlock(), createBlock(KeepAlive, null, [
createVNode(_component_router_view)
], 1024))
])
])
]);
}
_sfc_main$r.render = _sfc_render$p;
function initSystemComponents(app) {
AppComponent.name = COMPONENT_NAME_PREFIX + AppComponent.name;
app.component(AppComponent.name, AppComponent);
app.component(_sfc_main$r.name, _sfc_main$r);
}
function initMixin(app) {
app.mixin({
......
......@@ -25,20 +25,20 @@ export default defineComponent({
setup() {
useCssVar()
useAppLifecycle()
const { appClass, onLayoutChange } = useAppClass()
const { clazz, onChange } = useAppClass()
return () => (
openBlock(),
createBlock(
'uni-app',
{
class: appClass.value,
class: clazz.value,
},
[
createVNode(
Layout,
{
onChange: onLayoutChange,
onChange,
},
null,
8 /* PROPS */,
......@@ -70,21 +70,21 @@ function useAppLifecycle() {
function useAppClass() {
const showTabBar = ref(false)
const showMaxWidth = ref(false)
function onLayoutChange(type: string, value: boolean) {
function onChange(type: string, value: boolean) {
if (type === 'showTabBar') {
showTabBar.value = value
} else if (type === 'showMaxWidth') {
showMaxWidth.value = value
}
}
const appClass = computed(() => {
const clazz = computed(() => {
return {
'uni-app--showtabbar': showTabBar.value,
'uni-app--maxwidth': showMaxWidth.value,
}
})
return {
appClass,
onLayoutChange,
clazz,
onChange,
}
}
......@@ -3,27 +3,9 @@ import { App } from 'vue'
import { COMPONENT_NAME_PREFIX } from '@dcloudio/uni-shared'
import AppComponent from '../components/app/index'
// import PageComponent from '../components/page/index.vue'
// import AsyncErrorComponent from '../components/async-error/index.vue'
// import AsyncLoadingComponent from '../components/async-loading/index.vue'
import LayoutComponent from '../components/app/test.vue'
export function initSystemComponents(app: App) {
// @ts-ignore
AppComponent.name = COMPONENT_NAME_PREFIX + AppComponent.name
// @ts-ignore
// PageComponent.name = COMPONENT_NAME_PREFIX + PageComponent.name
// @ts-ignore
// AsyncErrorComponent.name = COMPONENT_NAME_PREFIX + AsyncErrorComponent.name
// @ts-ignore
// AsyncLoadingComponent.name =
// COMPONENT_NAME_PREFIX + AsyncLoadingComponent.name
app.component(AppComponent.name, AppComponent)
// app.component(PageComponent.name, PageComponent)
// app.component(AsyncErrorComponent.name, AsyncErrorComponent)
// app.component(AsyncLoadingComponent.name, AsyncLoadingComponent)
app.component(LayoutComponent.name, LayoutComponent)
}
import fs from 'fs'
import path from 'path'
import { parse } from 'jsonc-parser'
import { ConfigEnv, UserConfig } from 'vite'
import { VitePluginUniResolvedOptions } from '..'
interface ProjectFeatures {}
interface PagesFeatures {
pages: boolean
tabBar: boolean
topWindow: boolean
leftWindow: boolean
rightWindow: boolean
pullDownRefresh: boolean
}
interface ManifestFeatures {
wx: boolean
wxs: boolean
promise: boolean
longpress: boolean
routerMode: '"hash"' | '"history"'
}
function resolveProjectFeature(inputDir: string, { command }: ConfigEnv) {
const features: ProjectFeatures = {}
if (command === 'build') {
}
return features
}
function resolvePagesFeature(
inputDir: string,
{ command }: ConfigEnv
): PagesFeatures {
const features: PagesFeatures = {
pages: true, // 是否多页面
tabBar: true, // 是否启用tabBar
topWindow: false, // 是否启用topWindow
leftWindow: false, // 是否启用leftWindow
rightWindow: false, // 是否启用rightWindow
pullDownRefresh: false, // 是否启用下拉刷新
}
const {
tabBar,
pages,
topWindow,
leftWindow,
rightWindow,
globalStyle,
} = parse(fs.readFileSync(path.join(inputDir, 'pages.json'), 'utf8'))
if (pages && pages.length === 1) {
features.pages = false
}
if (!(tabBar && tabBar.list && tabBar.list.length)) {
features.tabBar = false
}
if (topWindow && topWindow.path) {
features.topWindow = true
}
if (leftWindow && leftWindow.path) {
features.leftWindow = true
}
if (rightWindow && rightWindow.path) {
features.rightWindow = true
}
if (globalStyle && globalStyle.enablePullDownRefresh) {
features.pullDownRefresh = true
} else {
if (
pages.find(
(page: { style: { enablePullDownRefresh: any } }) =>
page.style && page.style.enablePullDownRefresh
)
) {
features.pullDownRefresh = true
}
}
return features
}
function resolveManifestFeature(inputDir: string): ManifestFeatures {
const features: ManifestFeatures = {
wx: true, // 是否启用小程序的组件实例 API,如:selectComponent 等(uni-core/src/service/plugin/appConfig)
wxs: true, // 是否启用 wxs 支持,如:getComponentDescriptor 等(uni-core/src/view/plugin/appConfig)
promise: false, // 是否启用旧版本的 promise 支持(即返回[err,res]的格式)
longpress: true, // 是否启用longpress
routerMode: '"hash"', // 启用的 router 类型(uni-h5/src/framework/plugin/router)
}
const manifest = parse(
fs.readFileSync(path.join(inputDir, 'manifest.json'), 'utf8')
)
if (
manifest.h5 &&
manifest.h5.router &&
manifest.h5.router.mode === 'history'
) {
features.routerMode = '"history"'
}
// TODO manifest.json features
return features
}
import { getFeatures } from '../utils'
export function createDefine(
{ inputDir }: VitePluginUniResolvedOptions,
options: VitePluginUniResolvedOptions,
env: ConfigEnv
): UserConfig['define'] {
const {
wx,
wxs,
pages,
tabBar,
promise,
longpress,
routerMode,
topWindow,
leftWindow,
rightWindow,
pullDownRefresh,
} = Object.assign(
resolveManifestFeature(inputDir),
resolvePagesFeature(inputDir, env),
resolveProjectFeature(inputDir, env)
)
return {
__UNI_FEATURE_WX__: wx,
__UNI_FEATURE_WXS__: wxs,
__UNI_FEATURE_PROMISE__: promise,
__UNI_FEATURE_LONGPRESS__: longpress,
__UNI_FEATURE_ROUTER_MODE__: routerMode,
__UNI_FEATURE_PAGES__: pages,
__UNI_FEATURE_TABBAR__: tabBar,
__UNI_FEATURE_TOPWINDOW__: topWindow,
__UNI_FEATURE_LEFTWINDOW__: leftWindow,
__UNI_FEATURE_RIGHTWINDOW__: rightWindow,
__UNI_FEATURE_RESPONSIVE__: topWindow || leftWindow || rightWindow,
__UNI_FEATURE_PULL_DOWN_REFRESH__: pullDownRefresh,
}
return getFeatures(options, env.command)
}
......@@ -10,6 +10,6 @@ export function createConfigResolved(options: VitePluginUniResolvedOptions) {
options.inputDir = path.resolve(config.root, 'src')
options.assetsDir = config.build.assetsDir
resolvePlugins(config.command, config.plugins as Plugin[], options)
resolvePlugins(config, options)
}) as Plugin['configResolved']
}
......@@ -13,7 +13,7 @@ export function uniAppVuePlugin(options: VitePluginUniResolvedOptions): Plugin {
//App.vue main request
if (filename === appVuePath && !query.vue) {
return {
code: `<template><VUniApp ref="app"/></template><style src="@dcloudio/uni-h5/style/base.css"/>${code}`,
code: `<template><VUniApp/></template>${code}`,
map: this.getCombinedSourcemap(),
}
}
......
......@@ -57,10 +57,11 @@ const uniInjectPluginOptions: Partial<InjectOptions> = {
}
export function resolvePlugins(
command: ResolvedConfig['command'],
plugins: Plugin[],
config: ResolvedConfig,
options: VitePluginUniResolvedOptions
) {
const command = config.command
const plugins = config.plugins as Plugin[]
addPlugin(
plugins,
uniPrePlugin(Object.assign(uniPrePluginOptions, options)),
......@@ -69,7 +70,7 @@ export function resolvePlugins(
)
addPlugin(plugins, uniAppVuePlugin(options), 1, 'pre')
addPlugin(plugins, uniMainJsPlugin(options), 1, 'pre')
addPlugin(plugins, uniPagesJsonPlugin(options), 1, 'pre')
addPlugin(plugins, uniPagesJsonPlugin(config, options), 1, 'pre')
addPlugin(plugins, uniManifestJsonPlugin(options), 1, 'pre')
addPlugin(
......
import fs from 'fs'
import path from 'path'
import slash from 'slash'
import { Plugin } from 'vite'
import { Plugin, ResolvedConfig } from 'vite'
import { parse } from 'jsonc-parser'
import { hasOwn, camelize, capitalize, isPlainObject } from '@vue/shared'
import { parseJson } from '@dcloudio/uni-cli-shared'
import { camelize, capitalize } from '@vue/shared'
import { VitePluginUniResolvedOptions } from '../..'
import { FEATURE_DEFINES, normalizePagesJson } from '../../utils'
const pkg = require('@dcloudio/vite-plugin-uni/package.json')
const PAGES_JSON_JS = 'pages.json.js'
export function uniPagesJsonPlugin(
config: ResolvedConfig,
options: VitePluginUniResolvedOptions
): Plugin {
const pagesJsonPath = slash(path.join(options.inputDir, 'pages.json'))
......@@ -27,7 +28,7 @@ export function uniPagesJsonPlugin(
return {
code:
(options.command === 'serve' ? registerGlobalCode : '') +
parsePagesJson(code, options),
parsePagesJson(code, config, options),
map: { mappings: '' },
}
}
......@@ -48,20 +49,23 @@ interface PageRouteOptions {
function parsePagesJson(
jsonStr: string,
config: ResolvedConfig,
options: VitePluginUniResolvedOptions
) {
const pagesJson = formatPagesJson(jsonStr)
const pagesJson = normalizePagesJson(jsonStr, options.platform)
const definePagesCode = generatePagesDefineCode(pagesJson)
const uniRoutesCode = generateRoutes(pagesJson)
const uniConfigCode = generateConfig(pagesJson, options)
const manifestJsonPath = slash(
path.resolve(options.inputDir, 'manifest.json.js')
)
const cssCode = generateCssCode(config)
return `
import { defineAsyncComponent, resolveComponent, createVNode, withCtx, openBlock, createBlock } from 'vue'
import { PageComponent, AsyncLoadingComponent, AsyncErrorComponent } from '@dcloudio/uni-h5'
import { appid, debug, networkTimeout, router, async, sdkConfigs, qqMapKey, nvue } from '${manifestJsonPath}'
${cssCode}
${uniConfigCode}
${definePagesCode}
${uniRoutesCode}
......@@ -83,126 +87,24 @@ window.UniViewJSBridge = UniViewJSBridge
window.UniServiceJSBridge = UniServiceJSBridge
`
function formatPages(pagesJson: Record<string, any>, jsonStr: string) {
if (!Array.isArray(pagesJson.pages)) {
pagesJson.pages = []
console.error(`[vite] Error: pages.json->pages parse failed.\n`, jsonStr)
} else if (!pagesJson.pages.length) {
console.error(
`[vite] Error: pages.json->pages must contain at least 1 page.\n`,
jsonStr
)
}
}
function removePlatformStyle(globalStyle: Record<string, any>) {
delete globalStyle['app-plus']
delete globalStyle['h5']
Object.keys(globalStyle).forEach((name) => {
if (name.startsWith('mp-') || name.startsWith('quickapp')) {
delete globalStyle[name]
}
})
return globalStyle
}
const navigationBarMaps = {
navigationBarBackgroundColor: 'backgroundColor',
navigationBarTextStyle: 'textStyle',
navigationBarTitleText: 'titleText',
navigationStyle: 'style',
titleImage: 'titleImage',
titlePenetrate: 'titlePenetrate',
}
function normalizeNavigationBar(
pageStyle: Record<string, any>
): UniApp.PageNavigationBar {
const navigationBar = Object.create(null) as UniApp.PageNavigationBar
Object.keys(navigationBarMaps).forEach((name) => {
if (hasOwn(pageStyle, name)) {
// @ts-ignore
navigationBar[navigationBarMaps[name]] = pageStyle[name]
delete pageStyle[name]
}
})
if (
pageStyle.navigationBarShadow &&
pageStyle.navigationBarShadow.colorType
) {
navigationBar.shadowColorType = pageStyle.navigationBarShadow.colorType
delete pageStyle.navigationBarShadow
}
const { titleNView } = pageStyle
if (isPlainObject(titleNView)) {
Object.assign(navigationBar, titleNView)
}
return navigationBar
}
function normalizePageStyle(pageStyle: Record<string, any>) {
pageStyle.navigationBar = normalizeNavigationBar(pageStyle)
return pageStyle
}
function formatPageStyle(pageStyle?: Record<string, any>) {
if (pageStyle) {
const appGlobalStyle = pageStyle['app-plus']
if (appGlobalStyle) {
Object.assign(pageStyle, appGlobalStyle)
}
const h5GlobalStyle = pageStyle['h5']
if (h5GlobalStyle) {
Object.assign(pageStyle, h5GlobalStyle)
}
return normalizePageStyle(removePlatformStyle(pageStyle))
}
return {}
}
function formatSubpackages(subpackages?: UniApp.PagesJsonSubpackagesOptions[]) {
const pages: UniApp.PagesJsonPageOptions[] = []
if (Array.isArray(subpackages)) {
subpackages.forEach(({ root, pages: subPages }) => {
if (root && subPages.length) {
subPages.forEach((subPage: { path: string }) => {
subPage.path = slash(path.join(root, subPage.path))
pages.push(subPage)
})
}
})
}
return pages
function normalizePageIdentifier(path: string) {
return capitalize(camelize(path.replace(/\//g, '-')))
}
function formatPagesJson(jsonStr: string) {
let pagesJson: UniApp.PagesJson = {
pages: [],
function generateCssCode(config: ResolvedConfig) {
const define = config.define! as FEATURE_DEFINES
const cssFiles = ['@dcloudio/uni-h5/style/base.css']
if (define.__UNI_FEATURE_PAGES__) {
cssFiles.push('@dcloudio/uni-h5/style/layout.css')
}
// preprocess
try {
pagesJson = parseJson(jsonStr, true)
} catch (e) {
console.error(`[vite] Error: pages.json parse failed.\n`, jsonStr, e)
if (define.__UNI_FEATURE_NVUE__) {
cssFiles.push('@dcloudio/uni-h5/style/nvue.css')
}
// pages
formatPages(pagesJson, jsonStr)
// subpackages
pagesJson.pages.push(
...formatSubpackages(pagesJson.subPackages || pagesJson.subpackages)
)
// globalStyle
formatPageStyle(pagesJson.globalStyle)
return pagesJson
}
function formatPageIdentifier(path: string) {
return capitalize(camelize(path.replace(/\//g, '-')))
return cssFiles.map((file) => `import '${file}'`).join('\n')
}
function generatePageDefineCode(pageOptions: UniApp.PagesJsonPageOptions) {
return `const ${formatPageIdentifier(
return `const ${normalizePageIdentifier(
pageOptions.path
)} = defineAsyncComponent({
loader: () => import('./${pageOptions.path}.vue?mpType=page'),
......@@ -220,12 +122,12 @@ function generatePagesDefineCode(pagesJson: UniApp.PagesJson) {
.join('\n')
}
function formatPagesRoute(pagesJson: UniApp.PagesJson): PageRouteOptions[] {
function normalizePagesRoute(pagesJson: UniApp.PagesJson): PageRouteOptions[] {
const firstPagePath = pagesJson.pages[0].path
const tabBarList = (pagesJson.tabBar && pagesJson.tabBar.list) || []
return pagesJson.pages.map((pageOptions) => {
const path = pageOptions.path
const name = formatPageIdentifier(path)
const name = normalizePageIdentifier(path)
const isEntry = firstPagePath === path ? true : undefined
const tabBarIndex = tabBarList.findIndex(
(tabBarPage: { pagePath: string }) => tabBarPage.pagePath === path
......@@ -241,7 +143,7 @@ function formatPagesRoute(pagesJson: UniApp.PagesJson): PageRouteOptions[] {
tabBarIndex,
windowTop,
},
formatPageStyle(pageOptions.style)
pageOptions.style
)
return {
......@@ -271,7 +173,7 @@ function generatePagesRoute(pagesRouteOptions: PageRouteOptions[]) {
function generateRoutes(pagesJson: UniApp.PagesJson) {
return `window.__uniRoutes=[${[
`{ path: '/${pagesJson.pages[0].path}', redirect: '/' }`,
...generatePagesRoute(formatPagesRoute(pagesJson)),
...generatePagesRoute(normalizePagesRoute(pagesJson)),
].join(',')}]`
}
......
import path from 'path'
import debug from 'debug'
import { Plugin } from 'vite'
import slash from 'slash'
import { ModuleGraph, Plugin } from 'vite'
import { VitePluginUniResolvedOptions } from '..'
import { getFeatures } from '../utils'
const debugHmr = debug('uni:hmr')
async function invalidate(file: string, moduleGraph: ModuleGraph) {
const mod = await moduleGraph.getModuleById(slash(file))
if (mod) {
debugHmr('invalidate', mod.id)
moduleGraph.invalidateModule(mod)
}
}
export function createHandleHotUpdate(
_options: VitePluginUniResolvedOptions
options: VitePluginUniResolvedOptions
): Plugin['handleHotUpdate'] {
return function ({ file, server }) {
return async function ({ file, server }) {
// TODO 目前简单处理,当pages.json,manifest.json发生变化,就直接刷新,理想情况下,应该区分变化的内容,仅必要时做整页面刷新
if (file.endsWith('pages.json') || file.endsWith('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: {},
})
// 更新define
Object.assign(
server.config.define!,
getFeatures(options, server.config.command)
)
debugHmr('define', server.config.define)
// 当pages.json,manifest.json发生变化时,作废pages.json.js缓存
await invalidate(
path.resolve(options.inputDir, 'pages.json.js'),
server.moduleGraph
)
if (isManifestJson) {
await invalidate(
path.resolve(options.inputDir, 'manifest.json.js'),
server.moduleGraph
)
}
return []
}
}
......
......@@ -17,6 +17,7 @@ export interface VitePluginUniResolvedOptions extends VitePluginUniOptions {
root: string
base: string
command: ResolvedConfig['command']
platform: UniApp.PLATFORM
inputDir: string
assetsDir: string
devServer?: ViteDevServer
......@@ -42,6 +43,7 @@ export default function uniPlugin(
assetsDir: 'assets',
inputDir,
command: 'serve',
platform: 'h5',
}
initEnv(options)
return {
......
import fs from 'fs'
import path from 'path'
import { ConfigEnv } from 'vite'
import { parse } from 'jsonc-parser'
import { VitePluginUniResolvedOptions } from '..'
import { normalizePagesJson } from './pagesJson'
interface ProjectFeatures {}
interface PagesFeatures {
nvue: boolean
pages: boolean
tabBar: boolean
topWindow: boolean
leftWindow: boolean
rightWindow: boolean
pullDownRefresh: boolean
}
interface ManifestFeatures {
wx: boolean
wxs: boolean
promise: boolean
longpress: boolean
routerMode: '"hash"' | '"history"'
}
function resolveProjectFeature(
options: VitePluginUniResolvedOptions,
command: ConfigEnv['command']
) {
const features: ProjectFeatures = {}
if (command === 'build') {
}
return features
}
function resolvePagesFeature(
options: VitePluginUniResolvedOptions,
command: ConfigEnv['command']
): PagesFeatures {
const features: PagesFeatures = {
nvue: true, // 是否启用nvue
pages: true, // 是否多页面
tabBar: true, // 是否启用tabBar
topWindow: false, // 是否启用topWindow
leftWindow: false, // 是否启用leftWindow
rightWindow: false, // 是否启用rightWindow
pullDownRefresh: false, // 是否启用下拉刷新
}
const {
tabBar,
pages,
topWindow,
leftWindow,
rightWindow,
globalStyle,
} = normalizePagesJson(
fs.readFileSync(path.join(options.inputDir, 'pages.json'), 'utf8'),
options.platform
)
if (pages && pages.length === 1) {
features.pages = false
}
if (!(tabBar && tabBar.list && tabBar.list.length)) {
features.tabBar = false
}
if (topWindow && topWindow.path) {
features.topWindow = true
}
if (leftWindow && leftWindow.path) {
features.leftWindow = true
}
if (rightWindow && rightWindow.path) {
features.rightWindow = true
}
if (globalStyle && globalStyle.enablePullDownRefresh) {
features.pullDownRefresh = true
} else {
if (pages.find((page) => page.style && page.style.enablePullDownRefresh)) {
features.pullDownRefresh = true
}
}
if (command === 'build') {
if (
!pages.find((page) =>
fs.existsSync(path.resolve(options.inputDir, page.path, '.nvue'))
)
) {
features.nvue = false
}
}
return features
}
function resolveManifestFeature(
options: VitePluginUniResolvedOptions
): ManifestFeatures {
const features: ManifestFeatures = {
wx: true, // 是否启用小程序的组件实例 API,如:selectComponent 等(uni-core/src/service/plugin/appConfig)
wxs: true, // 是否启用 wxs 支持,如:getComponentDescriptor 等(uni-core/src/view/plugin/appConfig)
promise: false, // 是否启用旧版本的 promise 支持(即返回[err,res]的格式)
longpress: true, // 是否启用longpress
routerMode: '"hash"', // 启用的 router 类型(uni-h5/src/framework/plugin/router)
}
const manifest = parse(
fs.readFileSync(path.join(options.inputDir, 'manifest.json'), 'utf8')
)
if (
manifest.h5 &&
manifest.h5.router &&
manifest.h5.router.mode === 'history'
) {
features.routerMode = '"history"'
}
// TODO manifest.json features
return features
}
export type FEATURE_DEFINES = ReturnType<typeof getFeatures>
export function getFeatures(
options: VitePluginUniResolvedOptions,
command: ConfigEnv['command']
) {
const {
wx,
wxs,
nvue,
pages,
tabBar,
promise,
longpress,
routerMode,
topWindow,
leftWindow,
rightWindow,
pullDownRefresh,
} = Object.assign(
resolveManifestFeature(options),
resolvePagesFeature(options, command),
resolveProjectFeature(options, command)
)
return {
__UNI_FEATURE_WX__: wx,
__UNI_FEATURE_WXS__: wxs,
__UNI_FEATURE_NVUE__: nvue,
__UNI_FEATURE_PROMISE__: promise,
__UNI_FEATURE_LONGPRESS__: longpress,
__UNI_FEATURE_ROUTER_MODE__: routerMode,
__UNI_FEATURE_PAGES__: pages,
__UNI_FEATURE_TABBAR__: tabBar,
__UNI_FEATURE_TOPWINDOW__: topWindow,
__UNI_FEATURE_LEFTWINDOW__: leftWindow,
__UNI_FEATURE_RIGHTWINDOW__: rightWindow,
__UNI_FEATURE_RESPONSIVE__: topWindow || leftWindow || rightWindow,
__UNI_FEATURE_PULL_DOWN_REFRESH__: pullDownRefresh,
}
}
export * from './define'
export * from './pagesJson'
import path from 'path'
import slash from 'slash'
import { hasOwn, isPlainObject } from '@vue/shared'
import { parseJson } from '@dcloudio/uni-cli-shared'
export function normalizePagesJson(jsonStr: string, platform: UniApp.PLATFORM) {
let pagesJson: UniApp.PagesJson = {
pages: [],
}
// preprocess
try {
pagesJson = parseJson(jsonStr, true)
} catch (e) {
console.error(`[vite] Error: pages.json parse failed.\n`, jsonStr, e)
}
// pages
validatePages(pagesJson, jsonStr)
// subpackages
pagesJson.pages.push(
...normalizeSubpackages(pagesJson.subPackages || pagesJson.subpackages)
)
// pageStyle
normalizePages(pagesJson.pages, platform)
// globalStyle
pagesJson.globalStyle = normalizePageStyle(pagesJson.globalStyle!, platform)
return pagesJson
}
function validatePages(pagesJson: Record<string, any>, jsonStr: string) {
if (!Array.isArray(pagesJson.pages)) {
pagesJson.pages = []
console.error(`[uni-app] Error: pages.json->pages parse failed.\n`, jsonStr)
} else if (!pagesJson.pages.length) {
console.error(
`[uni-app] Error: pages.json->pages must contain at least 1 page.\n`,
jsonStr
)
}
}
function normalizePages(
pages: UniApp.PagesJsonPageOptions[],
platform: UniApp.PLATFORM
) {
pages.forEach((page) => {
page.style = normalizePageStyle(page.style!, platform)
})
return pages
}
function normalizeSubpackages(
subpackages?: UniApp.PagesJsonSubpackagesOptions[]
) {
const pages: UniApp.PagesJsonPageOptions[] = []
if (Array.isArray(subpackages)) {
subpackages.forEach(({ root, pages: subPages }) => {
if (root && subPages.length) {
subPages.forEach((subPage: { path: string }) => {
subPage.path = slash(path.join(root, subPage.path))
pages.push(subPage)
})
}
})
}
return pages
}
function normalizePageStyle(
pageStyle: Record<string, any>,
platform: UniApp.PLATFORM
) {
if (pageStyle) {
if (platform === 'h5') {
Object.assign(pageStyle, pageStyle['app-plus'] || {})
}
Object.assign(pageStyle, pageStyle[platform] || {})
if (['h5', 'app-plus'].includes(platform)) {
pageStyle.navigationBar = normalizeNavigationBar(pageStyle)
}
return removePlatformStyle(pageStyle)
}
return { navigationBar: {} }
}
const navigationBarMaps = {
navigationBarBackgroundColor: 'backgroundColor',
navigationBarTextStyle: 'textStyle',
navigationBarTitleText: 'titleText',
navigationStyle: 'style',
titleImage: 'titleImage',
titlePenetrate: 'titlePenetrate',
}
function normalizeNavigationBar(
pageStyle: Record<string, any>
): UniApp.PageNavigationBar {
const navigationBar = Object.create(null) as UniApp.PageNavigationBar
Object.keys(navigationBarMaps).forEach((name) => {
if (hasOwn(pageStyle, name)) {
// @ts-ignore
navigationBar[navigationBarMaps[name]] = pageStyle[name]
delete pageStyle[name]
}
})
if (
pageStyle.navigationBarShadow &&
pageStyle.navigationBarShadow.colorType
) {
navigationBar.shadowColorType = pageStyle.navigationBarShadow.colorType
delete pageStyle.navigationBarShadow
}
const { titleNView } = pageStyle
if (isPlainObject(titleNView)) {
Object.assign(navigationBar, titleNView)
}
return navigationBar
}
const platforms = ['h5', 'app-plus', 'mp-', 'quickapp']
function removePlatformStyle(pageStyle: Record<string, any>) {
Object.keys(pageStyle).forEach((name) => {
if (platforms.find((prefix) => name.startsWith(prefix))) {
delete pageStyle[name]
}
})
return pageStyle
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册