Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 

152 řádky
4.9 KiB

  1. import { dirname, relative, resolve } from 'node:path'
  2. import { fileURLToPath } from 'node:url'
  3. import process from 'node:process'
  4. import { existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs'
  5. import { createFilter, normalizePath } from 'vite'
  6. import { transformNvuePage, transformPage } from './page.js'
  7. import { rebuildUpApp, registerUpApp } from './root.js'
  8. import { loadPagesJson, normalizePlatformPath, toArray } from './utils.js'
  9. const rootLibPath = normalizePath(dirname(fileURLToPath(import.meta.url)))
  10. export default function UniUpRoot(options = {}) {
  11. const rootOptions = {
  12. enabledVirtualHost: false,
  13. enabledGlobalRef: false,
  14. rootFileName: 'App.up',
  15. autoCreateRootFile: true,
  16. excludePages: [],
  17. ...options,
  18. }
  19. const rootFileName = String(rootOptions.rootFileName || 'App.up').replace(/\.vue$/i, '')
  20. const detectProjectRoot = () => {
  21. const cwd = normalizePath(process.env.INIT_CWD || process.cwd())
  22. const envInputDir = process.env.UNI_INPUT_DIR ? normalizePath(process.env.UNI_INPUT_DIR) : ''
  23. const cliRootPath = normalizePath(resolve(cwd, 'src'))
  24. const hbuilderRootPath = cwd
  25. const isPageRoot = (path) => existsSync(resolve(path, 'pages.json'))
  26. if (envInputDir && isPageRoot(envInputDir)) {
  27. const projectType = envInputDir.endsWith('/src') ? 'cli' : 'hbuilder'
  28. return { rootPath: envInputDir, projectType }
  29. }
  30. if (isPageRoot(cliRootPath)) {
  31. return { rootPath: cliRootPath, projectType: 'cli' }
  32. }
  33. if (isPageRoot(hbuilderRootPath)) {
  34. return { rootPath: hbuilderRootPath, projectType: 'hbuilder' }
  35. }
  36. return {
  37. rootPath: envInputDir || cliRootPath,
  38. projectType: envInputDir && !envInputDir.endsWith('/src') ? 'hbuilder' : 'cli',
  39. }
  40. }
  41. const projectInfo = detectProjectRoot()
  42. const rootPath = normalizePath(projectInfo.rootPath)
  43. const appUpPath = normalizePath(resolve(rootPath, `${rootFileName}.vue`))
  44. const rootToastHostPath = normalizePath(resolve(rootLibPath, 'root-toast-host.vue'))
  45. const nvueRootPath = normalizePath(resolve(rootPath, 'uni_modules/uview-plus/libs/root/nvue-root.vue'))
  46. const themeRuntimePath = normalizePath(resolve(rootPath, 'uni_modules/uview-plus/libs/theme/runtime.js'))
  47. const pagesPath = normalizePath(resolve(rootPath, 'pages.json'))
  48. const excludedPaths = toArray(rootOptions.excludePages)
  49. .filter(Boolean)
  50. .map(path => normalizePath(resolve(rootPath, path)))
  51. const mainFiles = [
  52. normalizePath(resolve(rootPath, 'main.ts')),
  53. normalizePath(resolve(rootPath, 'main.js')),
  54. ]
  55. const getRelativeImportPath = (fromFile, toFile) => {
  56. let importPath = normalizePath(relative(dirname(fromFile), toFile))
  57. if (!importPath.startsWith('.')) {
  58. importPath = `./${importPath}`
  59. }
  60. return importPath
  61. }
  62. let pagesJson = []
  63. let pagesJsonMtimeMs = 0
  64. let hasPlatformPlugin = false
  65. const ensureRootFile = () => {
  66. if (!rootOptions.autoCreateRootFile) return
  67. if (existsSync(appUpPath)) return
  68. const defaultRootSfc = `<template>
  69. \t<UpRootView />
  70. </template>
  71. `
  72. mkdirSync(dirname(appUpPath), { recursive: true })
  73. writeFileSync(appUpPath, defaultRootSfc, 'utf-8')
  74. }
  75. const refreshPagesJson = () => {
  76. if (!existsSync(pagesPath)) return
  77. const mtimeMs = statSync(pagesPath).mtimeMs
  78. if (mtimeMs === pagesJsonMtimeMs && pagesJson.length) return
  79. pagesJson = loadPagesJson(pagesPath, rootPath)
  80. pagesJsonMtimeMs = mtimeMs
  81. }
  82. return {
  83. name: 'vite-plugin-uni-up-root',
  84. enforce: 'pre',
  85. configResolved({ plugins }) {
  86. hasPlatformPlugin = plugins.some(v => v.name === 'vite-plugin-uni-platform')
  87. },
  88. buildStart() {
  89. ensureRootFile()
  90. refreshPagesJson()
  91. },
  92. async transform(code, id) {
  93. let ms = null
  94. const isSfcBlock = id.includes('?')
  95. const cleanId = normalizePath(id.split('?')[0])
  96. const filterMain = createFilter(mainFiles)
  97. if (filterMain(cleanId)) {
  98. ms = await registerUpApp(code, rootFileName, getRelativeImportPath(cleanId, rootToastHostPath))
  99. }
  100. const filterUpRoot = createFilter(appUpPath)
  101. if (filterUpRoot(cleanId)) {
  102. ms = await rebuildUpApp(code, rootOptions.enabledVirtualHost)
  103. }
  104. refreshPagesJson()
  105. const pageId = hasPlatformPlugin ? normalizePlatformPath(cleanId) : cleanId
  106. const filterPage = createFilter(pagesJson, excludedPaths)
  107. if (!isSfcBlock && filterPage(pageId)) {
  108. if (cleanId.endsWith('.nvue')) {
  109. ms = await transformNvuePage(
  110. code,
  111. getRelativeImportPath(cleanId, nvueRootPath),
  112. getRelativeImportPath(cleanId, themeRuntimePath),
  113. rootOptions.enabledGlobalRef
  114. )
  115. } else {
  116. ms = await transformPage(code, rootOptions.enabledGlobalRef)
  117. }
  118. }
  119. if (ms) {
  120. return {
  121. code: ms.toString(),
  122. map: ms.generateMap({ hires: true }),
  123. }
  124. }
  125. return null
  126. },
  127. }
  128. }