pagesJson.ts 6.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
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 31
            registerGlobalCode +
            (options.command === 'serve' ? registerDevServerGlobalCode : '') +
fxy060608's avatar
fxy060608 已提交
32
            parsePagesJson(code, config, options),
fxy060608's avatar
fxy060608 已提交
33 34 35 36 37 38 39 40 41 42
          map: { mappings: '' },
        }
      }
    },
    load(id) {
      if (id.endsWith(PAGES_JSON_JS)) {
        return JSON.stringify(parse(fs.readFileSync(pagesJsonPath, 'utf8')))
      }
    },
  }
43
}
fxy060608's avatar
fxy060608 已提交
44 45 46 47

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

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

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

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

fxy060608's avatar
fxy060608 已提交
83 84 85 86 87
const registerGlobalCode = `import {upx2px} from '@dcloudio/uni-h5'
window.rpx2px = upx2px
`

const registerDevServerGlobalCode = `import {uni,getCurrentPages,getApp,UniServiceJSBridge,UniViewJSBridge} from '@dcloudio/uni-h5'
88 89
window.getApp = getApp
window.getCurrentPages = getCurrentPages
fxy060608's avatar
fxy060608 已提交
90
window.uni = uni
91 92 93
window.UniViewJSBridge = UniViewJSBridge
window.UniServiceJSBridge = UniServiceJSBridge
`
94

fxy060608's avatar
fxy060608 已提交
95 96
function normalizePageIdentifier(path: string) {
  return capitalize(camelize(path.replace(/\//g, '-')))
fxy060608's avatar
fxy060608 已提交
97 98
}

fxy060608's avatar
fxy060608 已提交
99 100
function generateCssCode(config: ResolvedConfig) {
  const define = config.define! as FEATURE_DEFINES
fxy060608's avatar
fxy060608 已提交
101
  const cssFiles = ['@dcloudio/uni-h5/style/framework/base.css']
fxy060608's avatar
fxy060608 已提交
102
  if (define.__UNI_FEATURE_PAGES__) {
fxy060608's avatar
fxy060608 已提交
103
    cssFiles.push('@dcloudio/uni-h5/style/framework/layout.css')
fxy060608's avatar
fxy060608 已提交
104
  }
fxy060608's avatar
fxy060608 已提交
105
  if (define.__UNI_FEATURE_NAVIGATIONBAR__) {
fxy060608's avatar
fxy060608 已提交
106
    cssFiles.push('@dcloudio/uni-h5/style/framework/pageHead.css')
fxy060608's avatar
fxy060608 已提交
107
  }
fxy060608's avatar
fxy060608 已提交
108
  if (define.__UNI_FEATURE_TABBAR__) {
fxy060608's avatar
fxy060608 已提交
109
    cssFiles.push('@dcloudio/uni-h5/style/framework/tabBar.css')
fxy060608's avatar
fxy060608 已提交
110
  }
fxy060608's avatar
fxy060608 已提交
111
  if (define.__UNI_FEATURE_NVUE__) {
fxy060608's avatar
fxy060608 已提交
112
    cssFiles.push('@dcloudio/uni-h5/style/framework/nvue.css')
fxy060608's avatar
fxy060608 已提交
113
  }
fxy060608's avatar
fxy060608 已提交
114
  if (define.__UNI_FEATURE_PULL_DOWN_REFRESH__) {
fxy060608's avatar
fxy060608 已提交
115
    cssFiles.push('@dcloudio/uni-h5/style/framework/pageRefresh.css')
fxy060608's avatar
fxy060608 已提交
116
  }
fxy060608's avatar
fxy060608 已提交
117
  if (define.__UNI_FEATURE_NAVIGATIONBAR_SEARCHINPUT__) {
fxy060608's avatar
fxy060608 已提交
118
    cssFiles.push('@dcloudio/uni-components/style/input.css')
fxy060608's avatar
fxy060608 已提交
119
  }
fxy060608's avatar
fxy060608 已提交
120
  return cssFiles.map((file) => `import '${file}'`).join('\n')
fxy060608's avatar
fxy060608 已提交
121 122
}

fxy060608's avatar
fxy060608 已提交
123
function generatePageDefineCode(pageOptions: UniApp.PagesJsonPageOptions) {
fxy060608's avatar
fxy060608 已提交
124
  return `const ${normalizePageIdentifier(
fxy060608's avatar
fxy060608 已提交
125
    pageOptions.path
fxy060608's avatar
fxy060608 已提交
126
  )} = defineAsyncComponent({
fxy060608's avatar
fxy060608 已提交
127
 loader: () => import('./${pageOptions.path}.vue?mpType=page'),
fxy060608's avatar
fxy060608 已提交
128 129 130 131 132 133
 loadingComponent: AsyncLoadingComponent,
 errorComponent: AsyncErrorComponent,
 delay: async.delay,
 timeout: async.timeout,
 suspensible: async.suspensible
})`
fxy060608's avatar
fxy060608 已提交
134 135
}

fxy060608's avatar
fxy060608 已提交
136 137
function generatePagesDefineCode(pagesJson: UniApp.PagesJson) {
  return pagesJson.pages
138
    .map((pageOptions) => generatePageDefineCode(pageOptions))
fxy060608's avatar
fxy060608 已提交
139 140 141
    .join('\n')
}

fxy060608's avatar
fxy060608 已提交
142
function normalizePagesRoute(pagesJson: UniApp.PagesJson): PageRouteOptions[] {
fxy060608's avatar
fxy060608 已提交
143 144
  const firstPagePath = pagesJson.pages[0].path
  const tabBarList = (pagesJson.tabBar && pagesJson.tabBar.list) || []
fxy060608's avatar
fxy060608 已提交
145
  return pagesJson.pages.map((pageOptions) => {
fxy060608's avatar
fxy060608 已提交
146
    const path = pageOptions.path
fxy060608's avatar
fxy060608 已提交
147
    const name = normalizePageIdentifier(path)
148
    const isEntry = firstPagePath === path ? true : undefined
fxy060608's avatar
fxy060608 已提交
149 150 151
    const tabBarIndex = tabBarList.findIndex(
      (tabBarPage: { pagePath: string }) => tabBarPage.pagePath === path
    )
152
    const isTabBar = tabBarIndex !== -1 ? true : undefined
fxy060608's avatar
fxy060608 已提交
153 154

    let windowTop = 0
fxy060608's avatar
fxy060608 已提交
155 156
    const meta = Object.assign(
      {
fxy060608's avatar
fxy060608 已提交
157
        route: pageOptions.path,
fxy060608's avatar
fxy060608 已提交
158 159 160 161 162 163
        isQuit: isEntry || isTabBar ? true : undefined,
        isEntry,
        isTabBar,
        tabBarIndex,
        windowTop,
      },
fxy060608's avatar
fxy060608 已提交
164
      pageOptions.style
fxy060608's avatar
fxy060608 已提交
165
    )
fxy060608's avatar
fxy060608 已提交
166 167 168
    return {
      name,
      path: pageOptions.path,
169
      meta,
fxy060608's avatar
fxy060608 已提交
170 171 172 173
    }
  })
}

fxy060608's avatar
fxy060608 已提交
174
function generatePageRoute({ name, path, meta }: PageRouteOptions) {
fxy060608's avatar
fxy060608 已提交
175 176
  const { isEntry } = meta
  const alias = isEntry ? `\n  alias:'/${path}',` : ''
fxy060608's avatar
fxy060608 已提交
177
  return `{
fxy060608's avatar
fxy060608 已提交
178
  path:'/${isEntry ? '' : path}',${alias}
179 180
  component:{
    render() {
fxy060608's avatar
fxy060608 已提交
181
      return (openBlock(), createBlock(PageComponent, null, {page: withCtx(() => [createVNode(${name})]), _: 1 /* STABLE */}))
182 183 184 185
    }
  },
  meta: ${JSON.stringify(meta)}
}`
fxy060608's avatar
fxy060608 已提交
186 187 188
}

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

fxy060608's avatar
fxy060608 已提交
192
function generateRoutes(pagesJson: UniApp.PagesJson) {
fxy060608's avatar
fxy060608 已提交
193
  return `window.__uniRoutes=[${[
fxy060608's avatar
fxy060608 已提交
194
    ...generatePagesRoute(normalizePagesRoute(pagesJson)),
fxy060608's avatar
fxy060608 已提交
195
  ].join(',')}]`
fxy060608's avatar
fxy060608 已提交
196 197
}

fxy060608's avatar
fxy060608 已提交
198 199 200 201
function generateConfig(
  pagesJson: Record<string, any>,
  options: VitePluginUniResolvedOptions
) {
fxy060608's avatar
fxy060608 已提交
202 203 204
  delete pagesJson.pages
  delete pagesJson.subPackages
  delete pagesJson.subpackages
fxy060608's avatar
fxy060608 已提交
205 206
  pagesJson.compilerVersion = pkg['uni-app'].compilerVersion
  return (
fxy060608's avatar
fxy060608 已提交
207
    (options.command === 'serve'
fxy060608's avatar
fxy060608 已提交
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
      ? ''
      : `window['____'+appid+'____']=true
delete window['____'+appid+'____']
`) +
    `window.__uniConfig=Object.assign(${JSON.stringify(pagesJson)},{
  async,
  debug,
  networkTimeout,
  sdkConfigs,
  qqMapKey,
  nvue,
  router
})
`
  )
fxy060608's avatar
fxy060608 已提交
223
}