提交 7cc0bc56 编写于 作者: fxy060608's avatar fxy060608

wip(app): nvue

上级 e20aa854
......@@ -68,6 +68,7 @@ declare namespace UniApp {
autoclose: boolean
}
onReady: (fn: Function) => void
serviceReady: boolean
}
interface UniRoute {
......
......@@ -6,7 +6,7 @@
"output": {
"name": "serviceContext",
"format": "iife",
"banner": "export function createServiceContext(Vue,weex, plus,instanceContext){\nconst setTimeout = instanceContext.setTimeout;\nconst clearTimeout = instanceContext.clearTimeout;\nconst setInterval = instanceContext.setInterval;\nconst clearInterval = instanceContext.clearInterval;\nconst __uniConfig = instanceContext.__uniConfig;\nconst __uniRoutes = instanceContext.__uniRoutes;\n",
"banner": "export function createServiceContext(weex, plus, instanceContext){\nconst Vue = instanceContext.Vue;\nlet setTimeout = instanceContext.setTimeout;\nlet clearTimeout = instanceContext.clearTimeout;\nlet setInterval = instanceContext.setInterval;\nlet clearInterval = instanceContext.clearInterval;\nconst __uniConfig = instanceContext.__uniConfig;\nconst __uniRoutes = instanceContext.__uniRoutes;\n",
"footer": "const uni = serviceContext.uni;\nconst getApp = serviceContext.getApp;\nconst getCurrentPages = serviceContext.getCurrentPages;\nconst UniServiceJSBridge = serviceContext.UniServiceJSBridge;\nreturn serviceContext;\n}",
"globals": {
"vue": "Vue"
......@@ -26,7 +26,10 @@
"__UNI_FEATURE_I18N_ZH_HANS__": "true",
"__UNI_FEATURE_I18N_ZH_HANT__": "true"
},
"external": ["vue"]
"external": ["vue"],
"replaceAfterBundled": {
"__VUE__": "vue"
}
},
{
"input": {
......
export function createServiceContext(Vue,weex, plus,instanceContext){
const setTimeout = instanceContext.setTimeout;
const clearTimeout = instanceContext.clearTimeout;
const setInterval = instanceContext.setInterval;
const clearInterval = instanceContext.clearInterval;
export function createServiceContext(weex, plus, instanceContext){
const Vue = instanceContext.Vue;
let setTimeout = instanceContext.setTimeout;
let clearTimeout = instanceContext.clearTimeout;
let setInterval = instanceContext.setInterval;
let clearInterval = instanceContext.clearInterval;
const __uniConfig = instanceContext.__uniConfig;
const __uniRoutes = instanceContext.__uniRoutes;
......@@ -1867,8 +1868,12 @@ var serviceContext = (function (vue) {
return;
}
// 兼容 nvue
const hooks = (vm._$weex ? vm.$options : vm.$)[name]
;
{
if (vm.__call_hook) {
return vm.__call_hook(name, args);
}
}
const hooks = vm.$[name];
return hooks && invokeArrayFns(hooks, args);
}
......@@ -9511,6 +9516,9 @@ var serviceContext = (function (vue) {
let lastStatusBarStyle;
let oldSetStatusBarStyle = plus.navigator.setStatusBarStyle;
function restoreOldSetStatusBarStyle(setStatusBarStyle) {
oldSetStatusBarStyle = setStatusBarStyle;
}
function newSetStatusBarStyle(style) {
lastStatusBarStyle = style;
oldSetStatusBarStyle(style);
......@@ -9694,7 +9702,8 @@ var serviceContext = (function (vue) {
function initWebview(webview, path, query, routeMeta) {
// 首页或非 nvue 页面
if (webview.id === '1' || !routeMeta.isNVue) {
initWebviewStyle(webview, path, query, routeMeta);
// path 必须参数为空,因为首页已经在 manifest.json 中设置了 uniNView,不能再次设置,否则会二次加载
initWebviewStyle(webview, '', query, routeMeta);
}
initWebviewEvent(webview);
}
......@@ -10103,6 +10112,36 @@ var serviceContext = (function (vue) {
};
}
function restoreGlobal(newVue, newWeex, newPlus, newSetTimeout, newClearTimeout, newSetInterval, newClearInterval) {
// 确保部分全局变量 是 app-service 中的
// 若首页 nvue 初始化比 app-service 快,导致框架处于该 nvue 环境下
// plus 如果不用 app-service,资源路径会出问题
// 若首页 nvue 被销毁,如 redirectTo 或 reLaunch,则这些全局功能会损坏
// 设置 vue3
// @ts-ignore 最终vue会被替换为vue
vue = newVue;
if (plus !== newPlus) {
if ((process.env.NODE_ENV !== 'production')) {
console.log(`[restoreGlobal][${Date.now()}]`);
}
weex = newWeex;
// @ts-ignore
plus = newPlus;
restoreOldSetStatusBarStyle(plus.navigator.setStatusBarStyle);
plus.navigator.setStatusBarStyle = newSetStatusBarStyle;
/* eslint-disable no-window-assign */
// @ts-ignore
setTimeout = newSetTimeout;
// @ts-ignore
clearTimeout = newClearTimeout;
// @ts-ignore
setInterval = newSetInterval;
// @ts-ignore
clearInterval = newClearInterval;
}
__uniConfig.serviceReady = true;
}
const EventType = {
load: 'load',
close: 'close',
......@@ -10947,6 +10986,8 @@ var serviceContext = (function (vue) {
return {
$: {},
onNVuePageCreated(vm, curNVuePage) {
vm.$ = {}; // 补充一个 nvue 的 $ 对象,模拟 vue3 的,不然有部分地方访问了 $
vm.$getAppWebview = () => webview;
// 替换真实的 nvue 的 vm
initPageVm(vm, pageInstance);
const pages = getAllPages();
......@@ -11361,6 +11402,7 @@ var serviceContext = (function (vue) {
shareWithSystem: shareWithSystem,
requestPayment: requestPayment,
__vuePlugin: index$1,
restoreGlobal: restoreGlobal,
createRewardedVideoAd: createRewardedVideoAd,
createFullScreenVideoAd: createFullScreenVideoAd,
createInterstitialAd: createInterstitialAd,
......
......@@ -56,6 +56,7 @@ export * from './plugin/registerRuntime'
export * from './plugin/share'
export * from './plugin/requestPayment'
export * from './plugin/vuePlugin'
export * from './plugin/restoreGlobal'
export * from './ad/rewardedVideoAd'
export * from './ad/fullScreenVideoAd'
......
import {
newSetStatusBarStyle,
restoreOldSetStatusBarStyle,
} from '../../statusBar'
export function restoreGlobal(
newVue: unknown,
newWeex: unknown,
newPlus: unknown,
newSetTimeout: unknown,
newClearTimeout: unknown,
newSetInterval: unknown,
newClearInterval: unknown
) {
// 确保部分全局变量 是 app-service 中的
// 若首页 nvue 初始化比 app-service 快,导致框架处于该 nvue 环境下
// plus 如果不用 app-service,资源路径会出问题
// 若首页 nvue 被销毁,如 redirectTo 或 reLaunch,则这些全局功能会损坏
// 设置 vue3
// @ts-ignore 最终__VUE__会被替换为vue
__VUE__ = newVue
if (plus !== newPlus) {
if (__DEV__) {
console.log(`[restoreGlobal][${Date.now()}]`)
}
weex = newWeex
// @ts-ignore
plus = newPlus
restoreOldSetStatusBarStyle(plus.navigator.setStatusBarStyle)
plus.navigator.setStatusBarStyle = newSetStatusBarStyle
/* eslint-disable no-global-assign */
// @ts-ignore
setTimeout = newSetTimeout
// @ts-ignore
clearTimeout = newClearTimeout
// @ts-ignore
setInterval = newSetInterval
// @ts-ignore
clearInterval = newClearInterval
}
__uniConfig.serviceReady = true
}
......@@ -163,6 +163,8 @@ function createNVueVm(
return {
$: {}, // navigateBack 时,invokeHook 会调用 $
onNVuePageCreated(vm: ComponentPublicInstance, curNVuePage: unknown) {
;(vm as any).$ = {} // 补充一个 nvue 的 $ 对象,模拟 vue3 的,不然有部分地方访问了 $
vm.$getAppWebview = () => webview
// 替换真实的 nvue 的 vm
initPageVm(vm, pageInstance)
const pages = getAllPages()
......
......@@ -10,7 +10,8 @@ export function initWebview(
) {
// 首页或非 nvue 页面
if (webview.id === '1' || !routeMeta.isNVue) {
initWebviewStyle(webview, path, query, routeMeta)
// path 必须参数为空,因为首页已经在 manifest.json 中设置了 uniNView,不能再次设置,否则会二次加载
initWebviewStyle(webview, '', query, routeMeta)
}
initSubNVues(webview, path, routeMeta)
initWebviewEvent(webview)
......
......@@ -23,7 +23,6 @@ export function parseWebviewStyle(
routeMeta[name as keyof UniApp.PageRouteMeta]
}
})
initNVue(webviewStyle, routeMeta, path)
initPopGesture(webviewStyle, routeMeta)
initBackgroundColor(webviewStyle, routeMeta)
......
......@@ -19,7 +19,6 @@ export function normalizeAppManifestJson(
initAppStatusbar(initDefaultManifestJson(), pagesJson),
userManifestJson
)
initArguments(manifestJson, pagesJson)
initPlus(manifestJson, pagesJson)
initNVue(manifestJson, pagesJson)
......@@ -27,8 +26,12 @@ export function normalizeAppManifestJson(
initSplashscreen(manifestJson, userManifestJson)
initConfusion(manifestJson)
initUniApp(manifestJson)
initLaunchwebview(manifestJson, pagesJson) // 依赖 initArguments 先执行
initTabBar(manifestJson, pagesJson) // 依赖 initLaunchwebview 先执行
// 依赖 initArguments 先执行
initTabBar(
initLaunchwebview(manifestJson, pagesJson),
manifestJson,
pagesJson
)
return manifestJson
}
......
......@@ -13,8 +13,6 @@ export function initLaunchwebview(
}
} catch (e) {}
}
// 标记入口页,方便后边的 initTabBar 使用
process.env.UNI_ENTRY_PAGE_PATH = entryPagePath
manifestJson.plus.useragent.value = 'uni-app'
extend(manifestJson.plus.launchwebview, {
......@@ -26,8 +24,8 @@ export function initLaunchwebview(
const entryPage = pagesJson.pages.find((p) => p.path === entryPagePath)
if (entryPage?.style.isNVue) {
manifestJson.plus.launchwebview.uniNView = { path: entryPagePath + '.js' }
manifestJson.plus.launchwebview.id = '2'
} else {
manifestJson.launch_path = '__uniappview.html'
}
return entryPagePath
}
......@@ -3,6 +3,7 @@ import { SELECTED_COLOR, TABBAR_HEIGHT } from '@dcloudio/uni-shared'
const TABBAR_WHITE = 'rgba(255,255,255,0.4)'
const TABBAR_BLACK = 'rgba(0,0,0,0.4)'
export function initTabBar(
entryPagePath: string,
manifestJson: Record<string, any>,
pagesJson: UniApp.PagesJson
) {
......@@ -23,9 +24,7 @@ export function initTabBar(
tabBar.height = `${parseFloat(tabBar.height!) || TABBAR_HEIGHT}px`
// 首页是 tabBar 页面
const item = tabBar.list.find(
(page) => page.pagePath === process.env.UNI_ENTRY_PAGE_PATH
)
const item = tabBar.list.find((page) => page.pagePath === entryPagePath)
if (item) {
;(tabBar as any).child = ['lauchwebview']
;(tabBar as any).selected = tabBar.list.indexOf(item)
......
......@@ -12,8 +12,9 @@ if (typeof Promise !== 'undefined' && !Promise.prototype.finally) {
}
`
export const restoreGlobalCode = `
import * as vue from 'vue'
if(uni.restoreGlobal){
uni.restoreGlobal(weex,plus,setTimeout,clearTimeout,setInterval,clearInterval)
uni.restoreGlobal(vue,weex,plus,setTimeout,clearTimeout,setInterval,clearInterval)
}
`
......
......@@ -31,11 +31,12 @@ export function invokeHook(
return
}
// 兼容 nvue
const hooks =
__PLATFORM__ === 'app'
? ((vm as any)._$weex ? vm.$options : vm.$)[name as string]
: vm.$[name as string]
if (__PLATFORM__ === 'app') {
if ((vm as any).__call_hook) {
return (vm as any).__call_hook(name, args)
}
}
const hooks = vm.$[name as string]
return hooks && invokeArrayFns(hooks, args)
}
......
......@@ -7,12 +7,13 @@ import { createServer, createSSRServer } from './server'
import { initEnv } from './utils'
export async function runDev(options: CliOptions & ServerOptions) {
extend(options, { watch: true, minify: false })
initEnv('dev', options)
try {
if (options.platform === 'h5') {
await (options.ssr ? createSSRServer(options) : createServer(options))
} else {
await build(extend(options, { watch: true }))
await build(options)
}
if (options.platform === 'app') {
await runNVue('dev')
......
import fs from 'fs-extra'
import path from 'path'
import { build as buildByVite, BuildOptions } from 'vite'
import { build as buildByVite, BuildOptions, InlineConfig } from 'vite'
import { CliOptions } from '.'
import { addConfigFile, cleanOptions } from './utils'
export async function build(options: CliOptions) {
await buildByVite(
addConfigFile({
root: process.env.VITE_ROOT_DIR,
logLevel: options.logLevel,
clearScreen: options.clearScreen,
build: cleanOptions(options) as BuildOptions,
})
addConfigFile(
initBuildOptions(options, cleanOptions(options) as BuildOptions)
)
)
}
......@@ -24,12 +21,7 @@ export async function buildSSR(options: CliOptions) {
ssrBuildClientOptions.outDir = process.env.UNI_OUTPUT_DIR
process.env.UNI_SSR_CLIENT = 'true'
await buildByVite(
addConfigFile({
root: process.env.VITE_ROOT_DIR,
logLevel: options.logLevel,
clearScreen: options.clearScreen,
build: ssrBuildClientOptions,
})
addConfigFile(initBuildOptions(options, ssrBuildClientOptions))
)
const ssrServerDir = path.resolve(outputDir, 'server')
process.env.UNI_OUTPUT_DIR = ssrServerDir
......@@ -54,12 +46,7 @@ export async function buildSSR(options: CliOptions) {
process.env.UNI_SSR_CLIENT = ''
process.env.UNI_SSR_SERVER = 'true'
await buildByVite(
addConfigFile({
root: process.env.VITE_ROOT_DIR,
logLevel: options.logLevel,
clearScreen: options.clearScreen,
build: ssrBuildServerOptions,
})
addConfigFile(initBuildOptions(options, ssrBuildServerOptions))
)
// copy ssr-manfiest.json to server
const assets = ['ssr-manifest.json', 'index.html']
......@@ -70,3 +57,16 @@ export async function buildSSR(options: CliOptions) {
}
})
}
function initBuildOptions(
options: CliOptions,
build: BuildOptions
): InlineConfig {
return {
root: process.env.VITE_ROOT_DIR,
logLevel: options.logLevel,
clearScreen: options.clearScreen,
mode: process.env.NODE_ENV,
build,
}
}
......@@ -75,14 +75,14 @@ export function initEnv(type: 'dev' | 'build', options: CliOptions) {
process.env.UNI_OUTPUT_DIR = (options as BuildOptions).outDir!
}
// tips
if (isInHBuilderX() && options.platform === 'app') {
return (
console.error(
`当前项目 Vue 版本为3,暂不支持编译至 App 端,近期将升级支持。`
),
process.exit(1)
)
}
// if (isInHBuilderX() && options.platform === 'app') {
// return (
// console.error(
// `当前项目 Vue 版本为3,暂不支持编译至 App 端,近期将升级支持。`
// ),
// process.exit(1)
// )
// }
if (process.env.UNI_PLATFORM === 'app') {
initNVueEnv()
}
......
......@@ -132,6 +132,27 @@ function createConfig(entryFile, output, buildOption) {
})
)
}
if (buildOption.replaceAfterBundled) {
const replacements = buildOption.replaceAfterBundled
plugins.push({
name: 'replace-after-bundled',
generateBundle(_options, bundles) {
Object.keys(bundles).forEach((name) => {
const bundle = bundles[name]
if (!bundle.code) {
return
}
Object.keys(replacements).forEach((replacement) => {
bundle.code = bundle.code.replace(
new RegExp(replacement, 'g'),
replacements[replacement]
)
})
})
},
})
}
return {
input: resolve(entryFile),
external,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册