从uni-app源码解析其入口文件设置

4,540 阅读2分钟

uni-app官方文档中指出默认项目入口是main.js

image.png 但是在实际项目中,项目入口在src/main.ts,具体是如何指定的呢?

已知,uni-app的构建指令是vue-cli-service uni-buildvue-cli-service默认会执行package.json中配置的所有vue-cli-plugin插件,uni-app项目配置了vue-cli-plugin-uni插件,当构建项目时,会执行该插件。

vue-cli-plugin-uni源码包中,分别为不同平台指定了Vue配置。其中,

  • 移动端:node_modules/@dcloudio/vue-cli-plugin-uni/lib/app-plus/index.js
  • h5:node_modules/@dcloudio/vue-cli-plugin-uni/lib/h5/index.js
  • 小程序:node_modules/@dcloudio/vue-cli-plugin-uni/lib/mp/index.js

vue-cli-plugin-uni的入口文件中,根据执行vue-cli-service指令时传递的环境变量,选择性加载指定平台的Vue配置,再结合webpack配置提供给webpack

// node_modules/@dcloudio/vue-cli-plugin-uni/index.js
  ...
  const type = ['app-plus', 'h5'].includes(process.env.UNI_PLATFORM)
    ? process.env.UNI_PLATFORM
    : 'mp'

  const platformOptions = require('./lib/' + type)

  let vueConfig = platformOptions.vueConfig
  ...
  Object.assign(options, { // TODO 考虑非 HBuilderX 运行时,可以支持自定义输出目录
    outputDir: process.env.UNI_OUTPUT_TMP_DIR || process.env.UNI_OUTPUT_DIR,
    assetsDir
  }, vueConfig) // 注意,此处目前是覆盖关系,后续考虑改为webpack merge逻辑

  require('./lib/options')(options)

  api.configureWebpack(require('./lib/configure-webpack')(platformOptions, manifestPlatformOptions, options, api))
  api.chainWebpack(require('./lib/chain-webpack')(platformOptions, options, api))
  ...

此处只介绍小程序项目的配置,具体配置如下:

//node_modules/@dcloudio/vue-cli-plugin-uni/lib/mp/index.js
...
module.exports = {
    ...
    webpackConfig (webpackConfig, vueOptions, api) {
        ...
        return {
            mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
            entry () {
                return process.UNI_ENTRY
            },
            ...
            module: {
                rules: [{
                  test: path.resolve(process.env.UNI_INPUT_DIR, getMainEntry()),
                  use: [...]
                    },
                    ...
                ]
            },
        }
    }
}

项目入口由环境变量UNI_ENTRY指定,其是根据页面配置得出,默认页面配置文件为项目工作目录/pages.jsonUNI_ENTRY的具体设置如下:

//node_modules/@dcloudio/uni-cli-shared/lib/pages.js
...
process.UNI_ENTRY = {
    'common/main': path.resolve(process.env.UNI_INPUT_DIR, getMainEntry())
}
...
// pages
pagesJson.pages.forEach(page => {
    process.UNI_ENTRY[page.path] = getMainJsPath(page.path)
})
// subPackages
if (Array.isArray(pagesJson.subPackages) && pagesJson.subPackages.length) {
    pagesJson.subPackages.forEach(({
      root,
      pages
    }) => {
        Array.isArray(pages) && pages.forEach(page => {
            if (root) {
                const pagePath = normalizePath(path.join(root, page.path))
                process.UNI_ENTRY[pagePath] = getMainJsPath(pagePath)
                process.UNI_SUB_PACKAGES_ROOT[pagePath] = root
            }
        })
    })
}

项目工作目录由环境变量UNI_INPUT_DIR指定,默认是src,其设置如下

// node_modules/@dcloudio/vue-cli-plugin-uni/lib/env.js
...
const defaultInputDir = 'src'
if (process.env.UNI_INPUT_DIR && process.env.UNI_INPUT_DIR.indexOf('./') === 0) {
  process.env.UNI_INPUT_DIR = path.resolve(process.cwd(), process.env.UNI_INPUT_DIR)
}
process.env.UNI_INPUT_DIR = process.env.UNI_INPUT_DIR || path.resolve(process.cwd(), defaultInputDir)
...

getMainEntry方法的具体实现如下:

//node_modules/@dcloudio/uni-cli-shared/lib/pages.js

function getMainEntry () {
    if (!mainEntry) {
        mainEntry = fs.existsSync(path.resolve(process.env.UNI_INPUT_DIR, 'main.ts')) ? 'main.ts' : 'main.js'
    }
    return mainEntry
}

所以在未指定入口的情况下,uni-app默认指定src/main.tssrc/main.js为项目入口