152 lines
4.9 KiB
JavaScript
152 lines
4.9 KiB
JavaScript
import { dirname, relative, resolve } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
import process from 'node:process'
|
|
import { existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs'
|
|
|
|
import { createFilter, normalizePath } from 'vite'
|
|
|
|
import { transformNvuePage, transformPage } from './page.js'
|
|
import { rebuildUpApp, registerUpApp } from './root.js'
|
|
import { loadPagesJson, normalizePlatformPath, toArray } from './utils.js'
|
|
|
|
const rootLibPath = normalizePath(dirname(fileURLToPath(import.meta.url)))
|
|
|
|
export default function UniUpRoot(options = {}) {
|
|
const rootOptions = {
|
|
enabledVirtualHost: false,
|
|
enabledGlobalRef: false,
|
|
rootFileName: 'App.up',
|
|
autoCreateRootFile: true,
|
|
excludePages: [],
|
|
...options,
|
|
}
|
|
const rootFileName = String(rootOptions.rootFileName || 'App.up').replace(/\.vue$/i, '')
|
|
|
|
const detectProjectRoot = () => {
|
|
const cwd = normalizePath(process.env.INIT_CWD || process.cwd())
|
|
const envInputDir = process.env.UNI_INPUT_DIR ? normalizePath(process.env.UNI_INPUT_DIR) : ''
|
|
const cliRootPath = normalizePath(resolve(cwd, 'src'))
|
|
const hbuilderRootPath = cwd
|
|
|
|
const isPageRoot = (path) => existsSync(resolve(path, 'pages.json'))
|
|
|
|
if (envInputDir && isPageRoot(envInputDir)) {
|
|
const projectType = envInputDir.endsWith('/src') ? 'cli' : 'hbuilder'
|
|
return { rootPath: envInputDir, projectType }
|
|
}
|
|
|
|
if (isPageRoot(cliRootPath)) {
|
|
return { rootPath: cliRootPath, projectType: 'cli' }
|
|
}
|
|
|
|
if (isPageRoot(hbuilderRootPath)) {
|
|
return { rootPath: hbuilderRootPath, projectType: 'hbuilder' }
|
|
}
|
|
|
|
return {
|
|
rootPath: envInputDir || cliRootPath,
|
|
projectType: envInputDir && !envInputDir.endsWith('/src') ? 'hbuilder' : 'cli',
|
|
}
|
|
}
|
|
|
|
const projectInfo = detectProjectRoot()
|
|
const rootPath = normalizePath(projectInfo.rootPath)
|
|
const appUpPath = normalizePath(resolve(rootPath, `${rootFileName}.vue`))
|
|
const rootToastHostPath = normalizePath(resolve(rootLibPath, 'root-toast-host.vue'))
|
|
const nvueRootPath = normalizePath(resolve(rootPath, 'uni_modules/uview-plus/libs/root/nvue-root.vue'))
|
|
const themeRuntimePath = normalizePath(resolve(rootPath, 'uni_modules/uview-plus/libs/theme/runtime.js'))
|
|
const pagesPath = normalizePath(resolve(rootPath, 'pages.json'))
|
|
const excludedPaths = toArray(rootOptions.excludePages)
|
|
.filter(Boolean)
|
|
.map(path => normalizePath(resolve(rootPath, path)))
|
|
|
|
const mainFiles = [
|
|
normalizePath(resolve(rootPath, 'main.ts')),
|
|
normalizePath(resolve(rootPath, 'main.js')),
|
|
]
|
|
|
|
const getRelativeImportPath = (fromFile, toFile) => {
|
|
let importPath = normalizePath(relative(dirname(fromFile), toFile))
|
|
if (!importPath.startsWith('.')) {
|
|
importPath = `./${importPath}`
|
|
}
|
|
return importPath
|
|
}
|
|
|
|
let pagesJson = []
|
|
let pagesJsonMtimeMs = 0
|
|
let hasPlatformPlugin = false
|
|
|
|
const ensureRootFile = () => {
|
|
if (!rootOptions.autoCreateRootFile) return
|
|
if (existsSync(appUpPath)) return
|
|
|
|
const defaultRootSfc = `<template>
|
|
\t<UpRootView />
|
|
</template>
|
|
`
|
|
|
|
mkdirSync(dirname(appUpPath), { recursive: true })
|
|
writeFileSync(appUpPath, defaultRootSfc, 'utf-8')
|
|
}
|
|
|
|
const refreshPagesJson = () => {
|
|
if (!existsSync(pagesPath)) return
|
|
const mtimeMs = statSync(pagesPath).mtimeMs
|
|
if (mtimeMs === pagesJsonMtimeMs && pagesJson.length) return
|
|
pagesJson = loadPagesJson(pagesPath, rootPath)
|
|
pagesJsonMtimeMs = mtimeMs
|
|
}
|
|
|
|
return {
|
|
name: 'vite-plugin-uni-up-root',
|
|
enforce: 'pre',
|
|
configResolved({ plugins }) {
|
|
hasPlatformPlugin = plugins.some(v => v.name === 'vite-plugin-uni-platform')
|
|
},
|
|
buildStart() {
|
|
ensureRootFile()
|
|
refreshPagesJson()
|
|
},
|
|
async transform(code, id) {
|
|
let ms = null
|
|
const isSfcBlock = id.includes('?')
|
|
const cleanId = normalizePath(id.split('?')[0])
|
|
|
|
const filterMain = createFilter(mainFiles)
|
|
if (filterMain(cleanId)) {
|
|
ms = await registerUpApp(code, rootFileName, getRelativeImportPath(cleanId, rootToastHostPath))
|
|
}
|
|
|
|
const filterUpRoot = createFilter(appUpPath)
|
|
if (filterUpRoot(cleanId)) {
|
|
ms = await rebuildUpApp(code, rootOptions.enabledVirtualHost)
|
|
}
|
|
|
|
refreshPagesJson()
|
|
const pageId = hasPlatformPlugin ? normalizePlatformPath(cleanId) : cleanId
|
|
const filterPage = createFilter(pagesJson, excludedPaths)
|
|
if (!isSfcBlock && filterPage(pageId)) {
|
|
if (cleanId.endsWith('.nvue')) {
|
|
ms = await transformNvuePage(
|
|
code,
|
|
getRelativeImportPath(cleanId, nvueRootPath),
|
|
getRelativeImportPath(cleanId, themeRuntimePath),
|
|
rootOptions.enabledGlobalRef
|
|
)
|
|
} else {
|
|
ms = await transformPage(code, rootOptions.enabledGlobalRef)
|
|
}
|
|
}
|
|
|
|
if (ms) {
|
|
return {
|
|
code: ms.toString(),
|
|
map: ms.generateMap({ hires: true }),
|
|
}
|
|
}
|
|
return null
|
|
},
|
|
}
|
|
}
|