1 | import * as path from 'path'
|
2 | import * as fs from 'fs-extra'
|
3 | import { SyncHook, Hook } from 'tapable'
|
4 | import * as _ from 'lodash'
|
5 | import chalk from 'chalk'
|
6 | import { IProjectConfig, ICommonPlugin } from '@tarojs/taro/types/compile'
|
7 |
|
8 | import { BUILD_TYPES, PROJECT_CONFIG } from './util/constants'
|
9 | import { IBuildOptions } from './util/types'
|
10 | import { emptyDirectory } from './util'
|
11 | import CONFIG from './config'
|
12 |
|
13 | interface IBuilderHooks {
|
14 | beforeBuild: Hook,
|
15 | afterBuild: Hook
|
16 | }
|
17 |
|
18 | export default class Builder {
|
19 | hooks: IBuilderHooks
|
20 | appPath: string
|
21 | config: IProjectConfig
|
22 |
|
23 | constructor (appPath: string) {
|
24 | this.hooks = {
|
25 | beforeBuild: new SyncHook(['config']),
|
26 | afterBuild: new SyncHook(['builder'])
|
27 | }
|
28 |
|
29 | this.appPath = appPath
|
30 | this.init()
|
31 | }
|
32 |
|
33 | init () {
|
34 | this.resolveConfig()
|
35 | this.applyPlugins()
|
36 | }
|
37 |
|
38 | resolveConfig () {
|
39 | this.config = require(path.join(this.appPath, PROJECT_CONFIG))(_.merge)
|
40 | }
|
41 |
|
42 | applyPlugins () {
|
43 | const plugins = this.config.plugins || []
|
44 | if (plugins.length) {
|
45 | plugins.forEach((plugin: ICommonPlugin) => {
|
46 | plugin.apply(this)
|
47 | })
|
48 | }
|
49 | }
|
50 |
|
51 | emptyFirst ({watch, type}) {
|
52 | const outputPath = path.join(this.appPath, `${this.config.outputRoot || CONFIG.OUTPUT_DIR}`)
|
53 | if (!fs.existsSync(outputPath)) {
|
54 | fs.ensureDirSync(outputPath)
|
55 | } else if (type !== BUILD_TYPES.H5 && (type !== BUILD_TYPES.QUICKAPP || !watch)) {
|
56 | emptyDirectory(outputPath)
|
57 | }
|
58 | }
|
59 |
|
60 | build (buildOptions: IBuildOptions) {
|
61 | this.hooks.beforeBuild.call(this.config)
|
62 | const {type, watch, platform, port, uiIndex} = buildOptions
|
63 | this.emptyFirst({type, watch})
|
64 | switch (type) {
|
65 | case BUILD_TYPES.H5:
|
66 | this.buildForH5(this.appPath, {watch, port})
|
67 | break
|
68 | case BUILD_TYPES.WEAPP:
|
69 | case BUILD_TYPES.SWAN:
|
70 | case BUILD_TYPES.ALIPAY:
|
71 | case BUILD_TYPES.TT:
|
72 | case BUILD_TYPES.QUICKAPP:
|
73 | case BUILD_TYPES.QQ:
|
74 | case BUILD_TYPES.JD:
|
75 | this.buildForMini(this.appPath, buildOptions)
|
76 | break
|
77 | case BUILD_TYPES.RN:
|
78 | this.buildForRN(this.appPath, {watch, port})
|
79 | break
|
80 | case BUILD_TYPES.UI:
|
81 | this.buildForUILibrary(this.appPath, {watch, uiIndex})
|
82 | break
|
83 | case BUILD_TYPES.PLUGIN:
|
84 | this.buildForPlugin(this.appPath, {
|
85 | watch,
|
86 | platform
|
87 | })
|
88 | break
|
89 | default:
|
90 | console.log(
|
91 | chalk.red('输入类型错误,目前只支持 weapp/swan/alipay/tt/qq/h5/quickapp/rn 八端类型'))
|
92 | }
|
93 | }
|
94 |
|
95 | buildForH5 (appPath: string, buildOptions: IBuildOptions) {
|
96 | require('./h5').build(appPath, buildOptions)
|
97 | }
|
98 |
|
99 | buildForMini (appPath: string, buildOptions: IBuildOptions) {
|
100 | require('./mini').build(appPath, buildOptions, null, this)
|
101 | }
|
102 |
|
103 | buildForRN (appPath: string, {watch, port}) {
|
104 | require('./rn').build(appPath, {watch, port})
|
105 | }
|
106 |
|
107 | buildForUILibrary (appPath: string, {watch, uiIndex}) {
|
108 | require('./ui/index').build(appPath, {watch, uiIndex})
|
109 | }
|
110 |
|
111 | buildForPlugin (appPath: string, {watch, platform}) {
|
112 | const typeMap = {
|
113 | [BUILD_TYPES.WEAPP]: '微信',
|
114 | [BUILD_TYPES.ALIPAY]: '支付宝'
|
115 | }
|
116 | if (platform !== BUILD_TYPES.WEAPP && platform !== BUILD_TYPES.ALIPAY) {
|
117 | console.log(chalk.red('目前插件编译仅支持 微信/支付宝 小程序!'))
|
118 | return
|
119 | }
|
120 | console.log(chalk.green(`开始编译${typeMap[platform]}小程序插件`))
|
121 | require('./plugin').build(appPath, {watch, platform}, this)
|
122 | }
|
123 | }
|