pagesJson.ts 5.8 KB
Newer Older
1
import fs from 'fs'
fxy060608's avatar
fxy060608 已提交
2 3
import path from 'path'
import slash from 'slash'
fxy060608's avatar
fxy060608 已提交
4
import { Plugin, ResolvedConfig } from 'vite'
fxy060608's avatar
fxy060608 已提交
5
import { parse } from 'jsonc-parser'
fxy060608's avatar
fxy060608 已提交
6
import { camelize, capitalize } from '@vue/shared'
fxy060608's avatar
fxy060608 已提交
7
import { VitePluginUniResolvedOptions } from '../..'
fxy060608's avatar
fxy060608 已提交
8
import { FEATURE_DEFINES, normalizePagesJson } from '../../utils'
9

fxy060608's avatar
fxy060608 已提交
10
const pkg = require('@dcloudio/vite-plugin-uni/package.json')
fxy060608's avatar
fxy060608 已提交
11

fxy060608's avatar
fxy060608 已提交
12 13 14
const PAGES_JSON_JS = 'pages.json.js'

export function uniPagesJsonPlugin(
fxy060608's avatar
fxy060608 已提交
15
  config: ResolvedConfig,
fxy060608's avatar
fxy060608 已提交
16 17 18 19 20 21 22 23 24 25 26 27 28 29
  options: VitePluginUniResolvedOptions
): Plugin {
  const pagesJsonPath = slash(path.join(options.inputDir, 'pages.json'))
  return {
    name: 'vite:uni-pages-json',
    resolveId(id) {
      if (id.endsWith(PAGES_JSON_JS)) {
        return pagesJsonPath + '.js'
      }
    },
    transform(code, id) {
      if (id.endsWith(PAGES_JSON_JS)) {
        return {
          code:
fxy060608's avatar
fxy060608 已提交
30
            (options.command === 'serve' ? registerGlobalCode : '') +
fxy060608's avatar
fxy060608 已提交
31
            parsePagesJson(code, config, options),
fxy060608's avatar
fxy060608 已提交
32 33 34 35 36 37 38 39 40 41
          map: { mappings: '' },
        }
      }
    },
    load(id) {
      if (id.endsWith(PAGES_JSON_JS)) {
        return JSON.stringify(parse(fs.readFileSync(pagesJsonPath, 'utf8')))
      }
    },
  }
42
}
fxy060608's avatar
fxy060608 已提交
43 44 45 46

interface PageRouteOptions {
  name: string
  path: string
fxy060608's avatar
fxy060608 已提交
47
  meta: Partial<UniApp.PageRouteMeta>
fxy060608's avatar
fxy060608 已提交
48 49
}

fxy060608's avatar
fxy060608 已提交
50 51
function parsePagesJson(
  jsonStr: string,
fxy060608's avatar
fxy060608 已提交
52
  config: ResolvedConfig,
fxy060608's avatar
fxy060608 已提交
53 54
  options: VitePluginUniResolvedOptions
) {
fxy060608's avatar
fxy060608 已提交
55
  const pagesJson = normalizePagesJson(jsonStr, options.platform)
56
  const definePagesCode = generatePagesDefineCode(pagesJson)
fxy060608's avatar
fxy060608 已提交
57 58 59 60 61
  const uniRoutesCode = generateRoutes(pagesJson)
  const uniConfigCode = generateConfig(pagesJson, options)
  const manifestJsonPath = slash(
    path.resolve(options.inputDir, 'manifest.json.js')
  )
fxy060608's avatar
fxy060608 已提交
62
  const cssCode = generateCssCode(config)
fxy060608's avatar
fxy060608 已提交
63

64
  return `
65
import { defineAsyncComponent, resolveComponent, createVNode, withCtx, openBlock, createBlock } from 'vue'
fxy060608's avatar
fxy060608 已提交
66 67
import { PageComponent, AsyncLoadingComponent, AsyncErrorComponent } from '@dcloudio/uni-h5'
import { appid, debug, networkTimeout, router, async, sdkConfigs, qqMapKey, nvue } from '${manifestJsonPath}'
fxy060608's avatar
fxy060608 已提交
68
${cssCode}
fxy060608's avatar
fxy060608 已提交
69
${uniConfigCode}
70
${definePagesCode}
fxy060608's avatar
fxy060608 已提交
71
${uniRoutesCode}
fxy060608's avatar
fxy060608 已提交
72
${options.command === 'serve' ? hmrCode : ''}
73
`
74 75
}

fxy060608's avatar
fxy060608 已提交
76 77 78 79 80 81
const hmrCode = `if(import.meta.hot){
  import.meta.hot.on('invalidate', (data) => {
      import.meta.hot.invalidate()
  })
}`

82
const registerGlobalCode = `import {uni,getCurrentPages,getApp,UniServiceJSBridge,UniViewJSBridge} from '@dcloudio/uni-h5'
83 84 85 86 87 88
window.getApp = getApp
window.getCurrentPages = getCurrentPages
window.uni = window.__GLOBAL__ = uni
window.UniViewJSBridge = UniViewJSBridge
window.UniServiceJSBridge = UniServiceJSBridge
`
89

fxy060608's avatar
fxy060608 已提交
90 91
function normalizePageIdentifier(path: string) {
  return capitalize(camelize(path.replace(/\//g, '-')))
fxy060608's avatar
fxy060608 已提交
92 93
}

fxy060608's avatar
fxy060608 已提交
94 95 96 97 98
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')
fxy060608's avatar
fxy060608 已提交
99
  }
fxy060608's avatar
fxy060608 已提交
100 101
  if (define.__UNI_FEATURE_NVUE__) {
    cssFiles.push('@dcloudio/uni-h5/style/nvue.css')
fxy060608's avatar
fxy060608 已提交
102
  }
fxy060608's avatar
fxy060608 已提交
103
  return cssFiles.map((file) => `import '${file}'`).join('\n')
fxy060608's avatar
fxy060608 已提交
104 105
}

fxy060608's avatar
fxy060608 已提交
106
function generatePageDefineCode(pageOptions: UniApp.PagesJsonPageOptions) {
fxy060608's avatar
fxy060608 已提交
107
  return `const ${normalizePageIdentifier(
fxy060608's avatar
fxy060608 已提交
108
    pageOptions.path
fxy060608's avatar
fxy060608 已提交
109
  )} = defineAsyncComponent({
fxy060608's avatar
fxy060608 已提交
110
 loader: () => import('./${pageOptions.path}.vue?mpType=page'),
fxy060608's avatar
fxy060608 已提交
111 112 113 114 115 116
 loadingComponent: AsyncLoadingComponent,
 errorComponent: AsyncErrorComponent,
 delay: async.delay,
 timeout: async.timeout,
 suspensible: async.suspensible
})`
fxy060608's avatar
fxy060608 已提交
117 118
}

fxy060608's avatar
fxy060608 已提交
119 120
function generatePagesDefineCode(pagesJson: UniApp.PagesJson) {
  return pagesJson.pages
121
    .map((pageOptions) => generatePageDefineCode(pageOptions))
fxy060608's avatar
fxy060608 已提交
122 123 124
    .join('\n')
}

fxy060608's avatar
fxy060608 已提交
125
function normalizePagesRoute(pagesJson: UniApp.PagesJson): PageRouteOptions[] {
fxy060608's avatar
fxy060608 已提交
126 127
  const firstPagePath = pagesJson.pages[0].path
  const tabBarList = (pagesJson.tabBar && pagesJson.tabBar.list) || []
fxy060608's avatar
fxy060608 已提交
128
  return pagesJson.pages.map((pageOptions) => {
fxy060608's avatar
fxy060608 已提交
129
    const path = pageOptions.path
fxy060608's avatar
fxy060608 已提交
130
    const name = normalizePageIdentifier(path)
131
    const isEntry = firstPagePath === path ? true : undefined
fxy060608's avatar
fxy060608 已提交
132 133 134
    const tabBarIndex = tabBarList.findIndex(
      (tabBarPage: { pagePath: string }) => tabBarPage.pagePath === path
    )
135
    const isTabBar = tabBarIndex !== -1 ? true : undefined
fxy060608's avatar
fxy060608 已提交
136 137

    let windowTop = 0
fxy060608's avatar
fxy060608 已提交
138 139 140 141 142 143 144 145
    const meta = Object.assign(
      {
        isQuit: isEntry || isTabBar ? true : undefined,
        isEntry,
        isTabBar,
        tabBarIndex,
        windowTop,
      },
fxy060608's avatar
fxy060608 已提交
146
      pageOptions.style
fxy060608's avatar
fxy060608 已提交
147 148
    )

fxy060608's avatar
fxy060608 已提交
149 150 151
    return {
      name,
      path: pageOptions.path,
152
      meta,
fxy060608's avatar
fxy060608 已提交
153 154 155 156
    }
  })
}

fxy060608's avatar
fxy060608 已提交
157
function generatePageRoute({ name, path, meta }: PageRouteOptions) {
fxy060608's avatar
fxy060608 已提交
158
  return `{
159 160 161
  path:'/${meta.isEntry ? '' : path}',
  component:{
    render() {
fxy060608's avatar
fxy060608 已提交
162
      return (openBlock(), createBlock(PageComponent, null, {page: withCtx(() => [createVNode(${name})]), _: 1 /* STABLE */}))
163 164 165 166
    }
  },
  meta: ${JSON.stringify(meta)}
}`
fxy060608's avatar
fxy060608 已提交
167 168 169
}

function generatePagesRoute(pagesRouteOptions: PageRouteOptions[]) {
170
  return pagesRouteOptions.map((pageOptions) => generatePageRoute(pageOptions))
fxy060608's avatar
fxy060608 已提交
171 172
}

fxy060608's avatar
fxy060608 已提交
173
function generateRoutes(pagesJson: UniApp.PagesJson) {
fxy060608's avatar
fxy060608 已提交
174
  return `window.__uniRoutes=[${[
fxy060608's avatar
fxy060608 已提交
175
    `{ path: '/${pagesJson.pages[0].path}', redirect: '/' }`,
fxy060608's avatar
fxy060608 已提交
176
    ...generatePagesRoute(normalizePagesRoute(pagesJson)),
fxy060608's avatar
fxy060608 已提交
177
  ].join(',')}]`
fxy060608's avatar
fxy060608 已提交
178 179
}

fxy060608's avatar
fxy060608 已提交
180 181 182 183
function generateConfig(
  pagesJson: Record<string, any>,
  options: VitePluginUniResolvedOptions
) {
fxy060608's avatar
fxy060608 已提交
184 185 186
  delete pagesJson.pages
  delete pagesJson.subPackages
  delete pagesJson.subpackages
fxy060608's avatar
fxy060608 已提交
187 188
  pagesJson.compilerVersion = pkg['uni-app'].compilerVersion
  return (
fxy060608's avatar
fxy060608 已提交
189
    (options.command === 'serve'
fxy060608's avatar
fxy060608 已提交
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
      ? ''
      : `window['____'+appid+'____']=true
delete window['____'+appid+'____']
`) +
    `window.__uniConfig=Object.assign(${JSON.stringify(pagesJson)},{
  async,
  debug,
  networkTimeout,
  sdkConfigs,
  qqMapKey,
  nvue,
  router
})
`
  )
fxy060608's avatar
fxy060608 已提交
205
}