pagesJson.ts 7.4 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 5
import { parse } from 'jsonc-parser'
import { Plugin } from 'vite'
fxy060608's avatar
fxy060608 已提交
6
import { camelize, capitalize } from '@vue/shared'
fxy060608's avatar
fxy060608 已提交
7
import { parseJson } from '@dcloudio/uni-cli-shared'
fxy060608's avatar
fxy060608 已提交
8
import { VitePluginUniResolvedOptions } from '../..'
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 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
const PAGES_JSON_JS = 'pages.json.js'

export function uniPagesJsonPlugin(
  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:
            (options.devServer ? registerGlobalCode : '') +
            parsePagesJson(code, options),
          map: { mappings: '' },
        }
      }
    },
    load(id) {
      if (id.endsWith(PAGES_JSON_JS)) {
        return JSON.stringify(parse(fs.readFileSync(pagesJsonPath, 'utf8')))
      }
    },
  }
41
}
fxy060608's avatar
fxy060608 已提交
42 43 44 45 46 47

interface PageRouteOptions {
  name: string
  path: string
  props: Record<string, any>
  meta: {
48 49 50 51
    isQuit: boolean | undefined
    isEntry: boolean | undefined
    isTabBar: boolean | undefined
    tabBarIndex: number
fxy060608's avatar
fxy060608 已提交
52
    windowTop: number
53 54 55
    topWindow: boolean | undefined
    leftWindow: boolean | undefined
    rightWindow: boolean | undefined
fxy060608's avatar
fxy060608 已提交
56 57 58
  }
}

fxy060608's avatar
fxy060608 已提交
59 60 61 62
function parsePagesJson(
  jsonStr: string,
  options: VitePluginUniResolvedOptions
) {
63 64
  const pagesJson = formatPagesJson(jsonStr)
  const definePagesCode = generatePagesDefineCode(pagesJson)
fxy060608's avatar
fxy060608 已提交
65 66 67 68 69
  const uniRoutesCode = generateRoutes(pagesJson)
  const uniConfigCode = generateConfig(pagesJson, options)
  const manifestJsonPath = slash(
    path.resolve(options.inputDir, 'manifest.json.js')
  )
fxy060608's avatar
fxy060608 已提交
70

71
  return `
72
import { defineAsyncComponent, resolveComponent, createVNode, withCtx, openBlock, createBlock } from 'vue'
fxy060608's avatar
fxy060608 已提交
73 74 75
import { PageComponent, AsyncLoadingComponent, AsyncErrorComponent } from '@dcloudio/uni-h5'
import { appid, debug, networkTimeout, router, async, sdkConfigs, qqMapKey, nvue } from '${manifestJsonPath}'
${uniConfigCode}
76
${definePagesCode}
fxy060608's avatar
fxy060608 已提交
77
${uniRoutesCode}
78
`
79 80 81
}

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

fxy060608's avatar
fxy060608 已提交
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
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']
104
  Object.keys(globalStyle).forEach((name) => {
fxy060608's avatar
fxy060608 已提交
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
    if (name.startsWith('mp-') || name.startsWith('quickapp')) {
      delete globalStyle[name]
    }
  })
  return globalStyle
}

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 removePlatformStyle(pageStyle)
  }
}

fxy060608's avatar
fxy060608 已提交
126 127
function formatSubpackages(subpackages?: UniApp.PagesJsonSubpackagesOptions[]) {
  const pages: UniApp.PagesJsonPageOptions[] = []
fxy060608's avatar
fxy060608 已提交
128 129 130 131 132 133 134 135 136 137 138 139 140 141
  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 formatPagesJson(jsonStr: string) {
fxy060608's avatar
fxy060608 已提交
142
  let pagesJson: UniApp.PagesJson = {
143
    pages: [],
fxy060608's avatar
fxy060608 已提交
144
  }
145
  // preprocess
fxy060608's avatar
fxy060608 已提交
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
  try {
    pagesJson = parseJson(jsonStr, true)
  } catch (e) {
    console.error(`[vite] Error: pages.json parse failed.\n`, jsonStr, e)
  }
  // pages
  formatPages(pagesJson, jsonStr)
  // subpackages
  pagesJson.pages.push(
    ...formatSubpackages(pagesJson.subPackages || pagesJson.subpackages)
  )
  // globalStyle
  formatPageStyle(pagesJson.globalStyle)
  return pagesJson
}

function formatPageIdentifier(path: string) {
fxy060608's avatar
fxy060608 已提交
163
  return capitalize(camelize(path.replace(/\//g, '-')))
fxy060608's avatar
fxy060608 已提交
164 165
}

fxy060608's avatar
fxy060608 已提交
166
function generatePageDefineCode(pageOptions: UniApp.PagesJsonPageOptions) {
fxy060608's avatar
fxy060608 已提交
167 168
  return `const ${formatPageIdentifier(
    pageOptions.path
fxy060608's avatar
fxy060608 已提交
169
  )} = defineAsyncComponent({
fxy060608's avatar
fxy060608 已提交
170
 loader: () => import('./${pageOptions.path}.vue?mpType=page'),
fxy060608's avatar
fxy060608 已提交
171 172 173 174 175 176
 loadingComponent: AsyncLoadingComponent,
 errorComponent: AsyncErrorComponent,
 delay: async.delay,
 timeout: async.timeout,
 suspensible: async.suspensible
})`
fxy060608's avatar
fxy060608 已提交
177 178
}

fxy060608's avatar
fxy060608 已提交
179 180
function generatePagesDefineCode(pagesJson: UniApp.PagesJson) {
  return pagesJson.pages
181
    .map((pageOptions) => generatePageDefineCode(pageOptions))
fxy060608's avatar
fxy060608 已提交
182 183 184
    .join('\n')
}

fxy060608's avatar
fxy060608 已提交
185
function formatPagesRoute(pagesJson: UniApp.PagesJson): PageRouteOptions[] {
fxy060608's avatar
fxy060608 已提交
186 187
  const firstPagePath = pagesJson.pages[0].path
  const tabBarList = (pagesJson.tabBar && pagesJson.tabBar.list) || []
fxy060608's avatar
fxy060608 已提交
188
  return pagesJson.pages.map((pageOptions) => {
fxy060608's avatar
fxy060608 已提交
189 190
    const path = pageOptions.path
    const name = formatPageIdentifier(path)
191
    const isEntry = firstPagePath === path ? true : undefined
fxy060608's avatar
fxy060608 已提交
192 193 194
    const tabBarIndex = tabBarList.findIndex(
      (tabBarPage: { pagePath: string }) => tabBarPage.pagePath === path
    )
195
    const isTabBar = tabBarIndex !== -1 ? true : undefined
fxy060608's avatar
fxy060608 已提交
196 197 198 199
    const props = formatPageStyle(pageOptions.style) || {}

    let windowTop = 0
    const meta = {
200
      isQuit: isEntry || isTabBar ? true : undefined,
fxy060608's avatar
fxy060608 已提交
201 202 203
      isEntry,
      isTabBar,
      tabBarIndex,
204 205 206
      windowTop,
      topWindow: props.topWindow,
      leftWindow: props.leftWindow,
207
      rightWindow: props.rightWindow,
fxy060608's avatar
fxy060608 已提交
208 209 210 211 212 213
    }
    Object.assign(props, meta)
    return {
      name,
      path: pageOptions.path,
      props,
214
      meta,
fxy060608's avatar
fxy060608 已提交
215 216 217 218 219 220
    }
  })
}

function generatePageRoute({ name, path, props, meta }: PageRouteOptions) {
  return `{
221 222 223 224 225 226 227 228 229 230
  path:'/${meta.isEntry ? '' : path}',
  component:{
    render() {
      return (openBlock(), createBlock(PageComponent, Object.assign({}, __uniConfig.globalStyle, ${JSON.stringify(
        props
      )}), {page: withCtx(() => [createVNode(${name})]), _: 1}, 16))
    }
  },
  meta: ${JSON.stringify(meta)}
}`
fxy060608's avatar
fxy060608 已提交
231 232 233
}

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

fxy060608's avatar
fxy060608 已提交
237
function generateRoutes(pagesJson: UniApp.PagesJson) {
fxy060608's avatar
fxy060608 已提交
238
  return `window.__uniRoutes=[${[
fxy060608's avatar
fxy060608 已提交
239
    `{ path: '/${pagesJson.pages[0].path}', redirect: '/' }`,
240
    ...generatePagesRoute(formatPagesRoute(pagesJson)),
fxy060608's avatar
fxy060608 已提交
241
  ].join(',')}]`
fxy060608's avatar
fxy060608 已提交
242 243
}

fxy060608's avatar
fxy060608 已提交
244 245 246 247
function generateConfig(
  pagesJson: Record<string, any>,
  options: VitePluginUniResolvedOptions
) {
fxy060608's avatar
fxy060608 已提交
248 249 250
  delete pagesJson.pages
  delete pagesJson.subPackages
  delete pagesJson.subpackages
fxy060608's avatar
fxy060608 已提交
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
  pagesJson.compilerVersion = pkg['uni-app'].compilerVersion
  return (
    (options.devServer
      ? ''
      : `window['____'+appid+'____']=true
delete window['____'+appid+'____']
`) +
    `window.__uniConfig=Object.assign(${JSON.stringify(pagesJson)},{
  async,
  debug,
  networkTimeout,
  sdkConfigs,
  qqMapKey,
  nvue,
  router
})
`
  )
fxy060608's avatar
fxy060608 已提交
269
}