build.ts 4.1 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1
import fs from 'fs'
fxy060608's avatar
fxy060608 已提交
2
import path from 'path'
fxy060608's avatar
fxy060608 已提交
3
import debug from 'debug'
fxy060608's avatar
fxy060608 已提交
4 5
import { UserConfig } from 'vite'

fxy060608's avatar
fxy060608 已提交
6
import {
fxy060608's avatar
fxy060608 已提交
7
  emptyDir,
fxy060608's avatar
fxy060608 已提交
8
  EXTNAME_JS_RE,
fxy060608's avatar
fxy060608 已提交
9
  normalizePath,
fxy060608's avatar
fxy060608 已提交
10 11
  hasJsonFile,
  removeExt,
fxy060608's avatar
fxy060608 已提交
12
  resolveMainPathOnce,
13
  normalizeMiniProgramFilename,
fxy060608's avatar
fxy060608 已提交
14
  isCSSRequest,
fxy060608's avatar
fxy060608 已提交
15
} from '@dcloudio/uni-cli-shared'
fxy060608's avatar
fxy060608 已提交
16
import { GetManualChunk, GetModuleInfo, Plugin, PreRenderedChunk } from 'rollup'
fxy060608's avatar
fxy060608 已提交
17 18 19 20 21
import {
  isUniComponentUrl,
  isUniPageUrl,
  parseVirtualComponentPath,
  parseVirtualPagePath,
fxy060608's avatar
fxy060608 已提交
22
} from '../plugins/entry'
fxy060608's avatar
fxy060608 已提交
23

fxy060608's avatar
fxy060608 已提交
24 25
const debugChunk = debug('vite:uni:chunk')

fxy060608's avatar
fxy060608 已提交
26
export function buildOptions(): UserConfig['build'] {
fxy060608's avatar
fxy060608 已提交
27
  const inputDir = process.env.UNI_INPUT_DIR
fxy060608's avatar
fxy060608 已提交
28 29 30 31 32
  const outputDir = process.env.UNI_OUTPUT_DIR
  // 开始编译时,清空输出目录
  if (fs.existsSync(outputDir)) {
    emptyDir(outputDir)
  }
fxy060608's avatar
fxy060608 已提交
33 34
  return {
    // sourcemap: 'inline', // TODO
fxy060608's avatar
fxy060608 已提交
35
    // target: ['chrome53'], // 由小程序自己启用 es6 编译
fxy060608's avatar
fxy060608 已提交
36
    emptyOutDir: false, // 不清空输出目录,否则会影响自定义的一些文件输出,比如wxml
fxy060608's avatar
fxy060608 已提交
37 38 39 40
    lib: {
      entry: resolveMainPathOnce(inputDir),
      formats: ['cjs'],
    },
fxy060608's avatar
fxy060608 已提交
41 42
    rollupOptions: {
      output: {
fxy060608's avatar
fxy060608 已提交
43 44
        entryFileNames: 'app.js',
        manualChunks: createMoveToVendorChunkFn(),
fxy060608's avatar
fxy060608 已提交
45
        chunkFileNames: createChunkFileNames(inputDir),
fxy060608's avatar
fxy060608 已提交
46
        assetFileNames: '[name][extname]',
fxy060608's avatar
fxy060608 已提交
47
        plugins: [dynamicImportPolyfill()],
fxy060608's avatar
fxy060608 已提交
48 49 50 51
      },
    },
  }
}
fxy060608's avatar
fxy060608 已提交
52

fxy060608's avatar
fxy060608 已提交
53
function isVueJs(id: string) {
fxy060608's avatar
fxy060608 已提交
54
  return id.includes('plugin-vue:export-helper')
fxy060608's avatar
fxy060608 已提交
55 56 57 58
}

const chunkFileNameBlackList = ['main', 'pages.json', 'manifest.json']

fxy060608's avatar
fxy060608 已提交
59 60
function createMoveToVendorChunkFn(): GetManualChunk {
  const cache = new Map<string, boolean>()
fxy060608's avatar
fxy060608 已提交
61
  const inputDir = normalizePath(process.env.UNI_INPUT_DIR)
fxy060608's avatar
fxy060608 已提交
62
  return (id, { getModuleInfo }) => {
fxy060608's avatar
fxy060608 已提交
63
    id = normalizePath(id)
fxy060608's avatar
fxy060608 已提交
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
    const filename = id.split('?')[0]
    // 处理项目内的js,ts文件
    if (EXTNAME_JS_RE.test(filename)) {
      if (filename.startsWith(inputDir)) {
        const chunkFileName = removeExt(
          normalizePath(path.relative(inputDir, filename))
        )
        if (
          !chunkFileNameBlackList.includes(chunkFileName) &&
          !hasJsonFile(chunkFileName) // 无同名的page,component
        ) {
          debugChunk(chunkFileName, id)
          return chunkFileName
        }
        return
      }
      // 非项目内的 js 资源,均打包到 vendor
      debugChunk('common/vendor', id)
      return 'common/vendor'
    }
fxy060608's avatar
fxy060608 已提交
84
    if (
fxy060608's avatar
fxy060608 已提交
85 86 87 88
      isVueJs(id) ||
      (id.includes('node_modules') &&
        !isCSSRequest(id) &&
        staticImportedByEntry(id, getModuleInfo, cache))
fxy060608's avatar
fxy060608 已提交
89
    ) {
fxy060608's avatar
fxy060608 已提交
90 91 92
      debugChunk('common/vendor', id)
      return 'common/vendor'
    }
fxy060608's avatar
fxy060608 已提交
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
  }
}

function staticImportedByEntry(
  id: string,
  getModuleInfo: GetModuleInfo,
  cache: Map<string, boolean>,
  importStack: string[] = []
): boolean {
  if (cache.has(id)) {
    return cache.get(id) as boolean
  }
  if (importStack.includes(id)) {
    // circular deps!
    cache.set(id, false)
    return false
  }
  const mod = getModuleInfo(id)
  if (!mod) {
    cache.set(id, false)
    return false
  }

  if (mod.isEntry) {
    cache.set(id, true)
    return true
  }
  const someImporterIs = mod.importers.some((importer) =>
    staticImportedByEntry(
      importer,
      getModuleInfo,
      cache,
      importStack.concat(id)
    )
  )
  cache.set(id, someImporterIs)
  return someImporterIs
}
fxy060608's avatar
fxy060608 已提交
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

function createChunkFileNames(
  inputDir: string
): (chunkInfo: PreRenderedChunk) => string {
  return function chunkFileNames(chunk) {
    if (chunk.isDynamicEntry && chunk.facadeModuleId) {
      let id = chunk.facadeModuleId
      if (isUniPageUrl(id)) {
        id = path.resolve(process.env.UNI_INPUT_DIR, parseVirtualPagePath(id))
      } else if (isUniComponentUrl(id)) {
        id = path.resolve(
          process.env.UNI_INPUT_DIR,
          parseVirtualComponentPath(id)
        )
      }
      return removeExt(normalizeMiniProgramFilename(id, inputDir)) + '.js'
    }
    return '[name].js'
  }
}

function dynamicImportPolyfill(): Plugin {
  return {
    name: 'dynamic-import-polyfill',
    renderDynamicImport() {
      return {
        left: '(',
        right: ')',
      }
    },
  }
}