build.js 8.6 KB
Newer Older
fxy060608's avatar
init v3  
fxy060608 已提交
1
const path = require('path')
2
const webpack = require('webpack')
fxy060608's avatar
init v3  
fxy060608 已提交
3

fxy060608's avatar
fxy060608 已提交
4
const {
fxy060608's avatar
fxy060608 已提交
5
  runByHBuilderX,
6
  isInHBuilderX,
fxy060608's avatar
fxy060608 已提交
7 8 9
  parseJson,
  parsePagesJson,
  parseManifestJson
fxy060608's avatar
fxy060608 已提交
10 11
} = require('@dcloudio/uni-cli-shared')

d-u-a's avatar
d-u-a 已提交
12 13
const uniI18n = require('@dcloudio/uni-cli-i18n')

fxy060608's avatar
fxy060608 已提交
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
const defaults = {
  clean: true,
  target: 'app',
  'unsafe-inline': true
}

const modifyConfig = (config, fn) => {
  if (Array.isArray(config)) {
    config.forEach(c => fn(c))
  } else {
    fn(config)
  }
}

module.exports = (api, options) => {
  api.registerCommand('uni-build', {
    description: 'build for production',
    usage: 'vue-cli-service uni-build [options]',
    options: {
fxy060608's avatar
fxy060608 已提交
33
      '--watch': 'watch for changes',
fxy060608's avatar
fxy060608 已提交
34 35
      '--minimize': 'Tell webpack to minimize the bundle using the TerserPlugin.',
      '--auto-host': 'specify automator host',
fxy060608's avatar
fxy060608 已提交
36
      '--auto-port': 'specify automator port',
37
      '--subpackage': 'specify subpackage',
38
      '--plugin': 'specify mp plugin',
D
DCloud_LXH 已提交
39 40
      '--manifest': 'build manifest.json',
      '--sourcemap': 'generate sourcemap'
fxy060608's avatar
fxy060608 已提交
41 42 43 44 45 46 47 48
    }
  }, async (args) => {
    for (const key in defaults) {
      if (args[key] == null) {
        args[key] = defaults[key]
      }
    }

fxy060608's avatar
fxy060608 已提交
49 50 51 52
    if (args.manifest && process.env.UNI_PLATFORM === 'app-plus') {
      return buildManifestJson()
    }

fxy060608's avatar
fxy060608 已提交
53
    const platforms = ['mp-weixin', 'mp-qq', 'mp-jd', 'mp-baidu', 'mp-alipay', 'mp-toutiao', 'mp-lark']
fxy060608's avatar
fxy060608 已提交
54
    if (args.subpackage && platforms.includes(process.env.UNI_PLATFORM)) {
fxy060608's avatar
fxy060608 已提交
55 56 57
      process.env.UNI_SUBPACKGE = args.subpackage
    }

58
    const mpPluginPlatforms = ['mp-weixin', 'mp-alipay']
59
    if (args.plugin) {
60
      if (mpPluginPlatforms.includes(process.env.UNI_PLATFORM)) {
61 62 63
        process.env.UNI_MP_PLUGIN = args.plugin
        analysisPluginDir()
      } else {
D
DCloud_LXH 已提交
64
        console.log()
65
        console.error(uniI18n.__('pluginUni.compileToMpPluginOnlySupportPlatform'))
D
DCloud_LXH 已提交
66
        console.log()
67 68
        process.exit(0)
      }
69 70
    }

fxy060608's avatar
fxy060608 已提交
71
    require('./util').initAutomator(args)
fxy060608's avatar
fxy060608 已提交
72

fxy060608's avatar
fxy060608 已提交
73 74 75 76
    args.entry = args.entry || args._[0]

    process.env.VUE_CLI_BUILD_TARGET = args.target

fxy060608's avatar
fxy060608 已提交
77
    if (args.sourcemap) process.env.SOURCEMAP = args.sourcemap
D
DCloud_LXH 已提交
78

fxy060608's avatar
fxy060608 已提交
79 80 81 82 83 84
    await build(args, api, options)

    delete process.env.VUE_CLI_BUILD_TARGET
  })
}

fxy060608's avatar
init v3  
fxy060608 已提交
85
function getWebpackConfig (api, args, options) {
fxy060608's avatar
fxy060608 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
  const validateWebpackConfig = require('@vue/cli-service/lib/util/validateWebpackConfig')
  // resolve raw webpack config
  const webpackConfig = require('@vue/cli-service/lib/commands/build/resolveAppConfig')(api, args, options)

  // check for common config errors
  validateWebpackConfig(webpackConfig, api, options, args.target)

  if (args.watch) {
    modifyConfig(webpackConfig, config => {
      config.watch = true
    })
  }

  if (args.minimize && process.env.NODE_ENV !== 'production') {
    modifyConfig(webpackConfig, config => {
      config.optimization.minimize = true
102
      if (webpack.version[0] <= 4) {
fxy060608's avatar
fxy060608 已提交
103
      config.optimization.namedModules = false
104
      }
fxy060608's avatar
fxy060608 已提交
105 106 107
    })
  } else {
    modifyConfig(webpackConfig, config => {
fxy060608's avatar
fxy060608 已提交
108 109 110
      if (!config.optimization) {
        config.optimization = {}
      }
111
      if (webpack.version[0] <= 4) {
fxy060608's avatar
fxy060608 已提交
112
      config.optimization.namedModules = false
113
      }
fxy060608's avatar
fxy060608 已提交
114 115
    })
  }
fxy060608's avatar
init v3  
fxy060608 已提交
116 117 118 119 120 121 122 123 124 125
  return webpackConfig
}

function getWebpackConfigs (api, args, options) {
  if (!process.env.UNI_USING_V3) {
    return [getWebpackConfig(api, args, options)]
  }
  const pluginOptions = (options.pluginOptions || (options.pluginOptions = {}))
  pluginOptions['uni-app-plus'] = {
    service: true
fxy060608's avatar
fxy060608 已提交
126
  }
fxy060608's avatar
fxy060608 已提交
127
  options.publicPath = '/'
fxy060608's avatar
init v3  
fxy060608 已提交
128
  const serviceWebpackConfig = getWebpackConfig(api, args, options)
fxy060608's avatar
fxy060608 已提交
129 130
  delete pluginOptions['uni-app-plus'].service
  pluginOptions['uni-app-plus'].view = true
fxy060608's avatar
fxy060608 已提交
131
  options.publicPath = './'
fxy060608's avatar
init v3  
fxy060608 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
  const viewWebpackConfig = getWebpackConfig(api, args, options)
  return [serviceWebpackConfig, viewWebpackConfig]
}

async function build (args, api, options) {
  const fs = require('fs-extra')
  const chalk = require('chalk')

  const {
    log,
    done,
    logWithSpinner,
    stopSpinner
  } = require('@vue/cli-shared-utils')

  const runByAliIde = process.env.BUILD_ENV === 'ali-ide'

  log()

  if (!runByHBuilderX && !runByAliIde) {
fxy060608's avatar
fxy060608 已提交
152 153 154 155
    logWithSpinner(uniI18n.__('pluginUni.startCompileProjectToPlatform', {
      0: process.env.UNI_SUB_PLATFORM || process.env.UNI_PLATFORM,
      1: process.env.UNI_MP_PLUGIN ? uniI18n.__('plugin') : uniI18n.__('platform')
    }))
fxy060608's avatar
init v3  
fxy060608 已提交
156 157 158 159 160
  }

  const targetDir = api.resolve(options.outputDir)

  const webpackConfigs = getWebpackConfigs(api, args, options)
fxy060608's avatar
fxy060608 已提交
161 162 163 164 165 166 167 168 169 170 171

  if (process.env.NODE_ENV === 'production') {
    try {
      fs.emptyDir(path.resolve(process.env.UNI_CLI_CONTEXT, 'node_modules/.cache'))
    } catch (e) {}
  }

  if (args.clean || process.env.UNI_PLATFORM === 'app-plus') {
    await fs.emptyDir(targetDir)
  }

fxy060608's avatar
fxy060608 已提交
172
  if (process.env.UNI_USING_NATIVE || process.env.UNI_USING_V3_NATIVE) {
fxy060608's avatar
fxy060608 已提交
173 174 175
    webpackConfigs.length = 0
  }

fxy060608's avatar
fxy060608 已提交
176 177 178 179 180
  if (
    process.env.UNI_USING_NATIVE ||
    process.env.UNI_USING_V3_NATIVE ||
    (process.UNI_NVUE_ENTRY && Object.keys(process.UNI_NVUE_ENTRY).length)
  ) {
fxy060608's avatar
fxy060608 已提交
181 182
    webpackConfigs.push(require('@dcloudio/vue-cli-plugin-hbuilderx/build/webpack.nvue.conf.js')(process
      .UNI_NVUE_ENTRY))
fxy060608's avatar
fxy060608 已提交
183 184 185 186
  }

  return new Promise((resolve, reject) => {
    webpack(webpackConfigs, (err, stats) => {
fxy060608's avatar
fxy060608 已提交
187
      if (!runByHBuilderX && !runByAliIde) {
fxy060608's avatar
fxy060608 已提交
188 189 190 191 192 193 194 195
        stopSpinner(false)
      }
      if (err) {
        return reject(err)
      }

      if (stats.hasErrors()) {
        /* eslint-disable prefer-promise-reject-errors */
fxy060608's avatar
fxy060608 已提交
196
        return reject('Build failed with errors.')
fxy060608's avatar
fxy060608 已提交
197 198
      }

fxy060608's avatar
fxy060608 已提交
199 200
      if (!args.silent && (process.env.UNI_PLATFORM !== 'app-plus' || process.env
        .UNI_AUTOMATOR_WS_ENDPOINT)) {
fxy060608's avatar
fxy060608 已提交
201 202 203 204 205 206 207 208
        const targetDirShort = path.relative(
          api.service.context,
          process.env.UNI_OUTPUT_DIR
        )

        if (!args.watch) {
          const dirMsg = runByHBuilderX ? ''
            : `The ${chalk.cyan(targetDirShort)} directory is ready to be deployed.`
fxy060608's avatar
fxy060608 已提交
209 210 211 212 213 214
          done(`Build complete. ${dirMsg}`)

          if (process.env.UNI_PLATFORM === 'h5' && !isInHBuilderX) {
            console.log()
            console.log('欢迎将H5站部署到uniCloud前端网页托管平台,高速、免费、安全、省心,详见:')
            console.log('https://uniapp.dcloud.io/uniCloud/hosting')
d-u-a's avatar
d-u-a 已提交
215
          }
fxy060608's avatar
fxy060608 已提交
216
        } else {
fxy060608's avatar
fxy060608 已提交
217 218
          const dirMsg = runByHBuilderX ? ''
            : `The ${chalk.cyan(targetDirShort)} directory is ready. `
fxy060608's avatar
fxy060608 已提交
219 220 221 222 223 224 225 226 227 228
          done(`Build complete. ${dirMsg}Watching for changes...`)
        }
      }

      resolve()
    })
  })
}

module.exports.defaultModes = {
fxy060608's avatar
fxy060608 已提交
229
  'uni-build': process.env.NODE_ENV
230
}
231 232 233 234 235

/**
 * 编译到微信小程序插件 文件校验
 */
function analysisPluginDir () {
D
DCloud_LXH 已提交
236 237
  const fs = require('fs-extra')

238 239 240
  // plugin.json 是否存在
  const pluginJsonName = 'plugin.json'
  const pluginJsonPath = path.resolve(process.env.UNI_INPUT_DIR, pluginJsonName)
D
DCloud_LXH 已提交
241 242

  if (!fs.pathExistsSync(pluginJsonPath)) {
D
DCloud_LXH 已提交
243
    console.log()
fxy060608's avatar
fxy060608 已提交
244 245 246
    console.error(uniI18n.__('pluginUni.fileNoExistsCheckAfterRetry', {
      0: pluginJsonName
    }))
D
DCloud_LXH 已提交
247
    console.log()
248 249 250
    process.exit(0)
  }

251
  const pluginJson = parseJson(fs.readFileSync(pluginJsonPath, 'utf-8'), true)
252

D
DCloud_LXH 已提交
253
  // main 入口文件是否存在
254 255 256 257
  if (pluginJson.main) {
    process.env.UNI_MP_PLUGIN_MAIN = pluginJson.main
    const UNI_MP_PLUGIN_MAIN = process.env.UNI_MP_PLUGIN_MAIN
    const mainFilePath = path.resolve(process.env.UNI_INPUT_DIR, UNI_MP_PLUGIN_MAIN)
Q
qiang 已提交
258

259 260 261 262 263 264 265 266
    if (UNI_MP_PLUGIN_MAIN && !fs.pathExistsSync(mainFilePath)) {
      console.log()
      console.error(uniI18n.__('pluginUni.entryDileNoExistsCheckAfterRetry', {
        0: UNI_MP_PLUGIN_MAIN
      }))
      console.log()
      process.exit(0)
    }
267 268
  }
}
fxy060608's avatar
fxy060608 已提交
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292

function buildManifestJson () {
  const fs = require('fs-extra')
  const inputDir = process.env.UNI_INPUT_DIR
  const outputDir = process.env.UNI_OUTPUT_DIR
  const pagesJsonPath = path.resolve(inputDir, 'pages.json')
  const manifestJsonPath = path.resolve(inputDir, 'manifest.json')

  const pagesJson = parsePagesJson(fs.readFileSync(pagesJsonPath, 'utf8'))
  const manifestJson = parseManifestJson(fs.readFileSync(manifestJsonPath, 'utf8'))

  const res = require('@dcloudio/webpack-uni-pages-loader/lib/platforms/app-plus/index.js')(pagesJson,
    manifestJson,
    false)
  if (res && res[0]) {
    fs.outputFileSync(
      path.resolve(outputDir, 'manifest.json'),
      res[0].content
    )
  }
  const {
    done
  } = require('@vue/cli-shared-utils')
  done('Build complete.')
石小磊 已提交
293
}