1 | import { dotenvParse, fs, patchEnv } from '@tarojs/helper'
|
2 | import { Config, Kernel } from '@tarojs/service'
|
3 | import * as minimist from 'minimist'
|
4 | import * as path from 'path'
|
5 |
|
6 | import customCommand from './commands/customCommand'
|
7 | import { getPkgVersion } from './util'
|
8 |
|
9 | const DISABLE_GLOBAL_CONFIG_COMMANDS = ['build', 'global-config', 'doctor', 'update', 'config']
|
10 | const DEFAULT_FRAMEWORK = 'react'
|
11 |
|
12 | export default class CLI {
|
13 | appPath: string
|
14 | constructor (appPath) {
|
15 | this.appPath = appPath || process.cwd()
|
16 | }
|
17 |
|
18 | run () {
|
19 | return this.parseArgs()
|
20 | }
|
21 |
|
22 | async parseArgs () {
|
23 | const args = minimist(process.argv.slice(2), {
|
24 | alias: {
|
25 | version: ['v'],
|
26 | help: ['h'],
|
27 | port: ['p'],
|
28 | resetCache: ['reset-cache'],
|
29 | publicPath: ['public-path'],
|
30 | bundleOutput: ['bundle-output'],
|
31 | sourcemapOutput: ['sourcemap-output'],
|
32 | sourceMapUrl: ['sourcemap-use-absolute-path'],
|
33 | sourcemapSourcesRoot: ['sourcemap-sources-root'],
|
34 | assetsDest: ['assets-dest'],
|
35 | envPrefix: ['env-prefix'],
|
36 | },
|
37 | boolean: ['version', 'help', 'disable-global-config'],
|
38 | default: {
|
39 | build: true,
|
40 | },
|
41 | })
|
42 | const _ = args._
|
43 | const command = _[0]
|
44 | if (command) {
|
45 | const appPath = this.appPath
|
46 | const presetsPath = path.resolve(__dirname, 'presets')
|
47 | const commandsPath = path.resolve(presetsPath, 'commands')
|
48 | const platformsPath = path.resolve(presetsPath, 'platforms')
|
49 | const commandPlugins = fs.readdirSync(commandsPath)
|
50 | const targetPlugin = `${command}.js`
|
51 |
|
52 |
|
53 | process.env.NODE_ENV ||= args.env
|
54 | if (process.env.NODE_ENV === 'undefined' && (command === 'build' || command === 'inspect')) {
|
55 | process.env.NODE_ENV = (args.watch ? 'development' : 'production')
|
56 | }
|
57 | args.type ||= args.t
|
58 | if (args.type) {
|
59 | process.env.TARO_ENV = args.type
|
60 | }
|
61 | if (typeof args.plugin === 'string') {
|
62 | process.env.TARO_ENV = 'plugin'
|
63 | }
|
64 | const mode = args.mode || process.env.NODE_ENV
|
65 |
|
66 | const expandEnv = dotenvParse(appPath, args.envPrefix, mode)
|
67 |
|
68 | const disableGlobalConfig = !!(args['disable-global-config'] || DISABLE_GLOBAL_CONFIG_COMMANDS.includes(command))
|
69 |
|
70 | const configEnv = {
|
71 | mode,
|
72 | command,
|
73 | }
|
74 | const config = new Config({
|
75 | appPath: this.appPath,
|
76 | disableGlobalConfig: disableGlobalConfig
|
77 | })
|
78 | await config.init(configEnv)
|
79 |
|
80 | const kernel = new Kernel({
|
81 | appPath,
|
82 | presets: [
|
83 | path.resolve(__dirname, '.', 'presets', 'index.js')
|
84 | ],
|
85 | config,
|
86 | plugins: []
|
87 | })
|
88 | kernel.optsPlugins ||= []
|
89 |
|
90 |
|
91 | const initialConfig = kernel.config?.initialConfig
|
92 | if (initialConfig) {
|
93 | initialConfig.env = patchEnv(initialConfig, expandEnv)
|
94 | }
|
95 | if (command === 'doctor') {
|
96 | kernel.optsPlugins.push('@tarojs/plugin-doctor')
|
97 | } else if (commandPlugins.includes(targetPlugin)) {
|
98 |
|
99 | kernel.optsPlugins.push(path.resolve(commandsPath, targetPlugin))
|
100 | }
|
101 |
|
102 |
|
103 | kernel.cliCommandsPath = commandsPath
|
104 | kernel.cliCommands = commandPlugins
|
105 | .filter(commandFileName => /^[\w-]+(\.[\w-]+)*\.js$/.test(commandFileName))
|
106 | .map(fileName => fileName.replace(/\.js$/, ''))
|
107 |
|
108 | switch (command) {
|
109 | case 'inspect':
|
110 | case 'build': {
|
111 | let plugin
|
112 | let platform = args.type
|
113 | const { publicPath, bundleOutput, sourcemapOutput, sourceMapUrl, sourcemapSourcesRoot, assetsDest } = args
|
114 |
|
115 |
|
116 | switch (platform) {
|
117 | case 'weapp':
|
118 | case 'alipay':
|
119 | case 'swan':
|
120 | case 'tt':
|
121 | case 'qq':
|
122 | case 'jd':
|
123 | case 'h5':
|
124 | case 'harmony-hybrid':
|
125 | kernel.optsPlugins.push(`@tarojs/plugin-platform-${platform}`)
|
126 | break
|
127 | default: {
|
128 |
|
129 | const platformPlugins = fs.readdirSync(platformsPath)
|
130 | const targetPlugin = `${platform}.js`
|
131 | if (platformPlugins.includes(targetPlugin)) {
|
132 | kernel.optsPlugins.push(path.resolve(platformsPath, targetPlugin))
|
133 | }
|
134 | break
|
135 | }
|
136 | }
|
137 |
|
138 |
|
139 | const framework = kernel.config?.initialConfig.framework || DEFAULT_FRAMEWORK
|
140 | const frameworkMap = {
|
141 | vue: '@tarojs/plugin-framework-vue2',
|
142 | vue3: '@tarojs/plugin-framework-vue3',
|
143 | react: '@tarojs/plugin-framework-react',
|
144 | preact: '@tarojs/plugin-framework-react',
|
145 | nerv: '@tarojs/plugin-framework-react',
|
146 | }
|
147 | if (frameworkMap[framework]) {
|
148 | kernel.optsPlugins.push(frameworkMap[framework])
|
149 | }
|
150 |
|
151 |
|
152 | if (typeof args.plugin === 'string') {
|
153 | plugin = args.plugin
|
154 | platform = 'plugin'
|
155 | kernel.optsPlugins.push(path.resolve(platformsPath, 'plugin.js'))
|
156 | if (plugin === 'weapp' || plugin === 'alipay' || plugin === 'jd') {
|
157 | kernel.optsPlugins.push(`@tarojs/plugin-platform-${plugin}`)
|
158 | }
|
159 | }
|
160 |
|
161 |
|
162 | if (command === 'inspect') {
|
163 | customCommand(command, kernel, args)
|
164 | break
|
165 | }
|
166 |
|
167 | customCommand(command, kernel, {
|
168 | _,
|
169 | platform,
|
170 | plugin,
|
171 | isWatch: Boolean(args.watch),
|
172 |
|
173 | isBuildNativeComp: _[1] === 'native-components',
|
174 |
|
175 | newBlended: Boolean(args['new-blended']),
|
176 |
|
177 | withoutBuild: !args.build,
|
178 | port: args.port,
|
179 | env: args.env,
|
180 | deviceType: args.platform,
|
181 | resetCache: !!args.resetCache,
|
182 | publicPath,
|
183 | bundleOutput,
|
184 | sourcemapOutput,
|
185 | sourceMapUrl,
|
186 | sourcemapSourcesRoot,
|
187 | assetsDest,
|
188 | qr: !!args.qr,
|
189 | blended: Boolean(args.blended),
|
190 | h: args.h
|
191 | })
|
192 | break
|
193 | }
|
194 | case 'init': {
|
195 | customCommand(command, kernel, {
|
196 | _,
|
197 | appPath,
|
198 | projectName: _[1] || args.name,
|
199 | description: args.description,
|
200 | typescript: args.typescript,
|
201 | framework: args.framework,
|
202 | compiler: args.compiler,
|
203 | npm: args.npm,
|
204 | templateSource: args['template-source'],
|
205 | clone: !!args.clone,
|
206 | template: args.template,
|
207 | css: args.css,
|
208 | h: args.h
|
209 | })
|
210 | break
|
211 | }
|
212 | default:
|
213 | customCommand(command, kernel, args)
|
214 | break
|
215 | }
|
216 | } else {
|
217 | if (args.h) {
|
218 | console.log('Usage: taro <command> [options]')
|
219 | console.log()
|
220 | console.log('Options:')
|
221 | console.log(' -v, --version output the version number')
|
222 | console.log(' -h, --help output usage information')
|
223 | console.log()
|
224 | console.log('Commands:')
|
225 | console.log(' init [projectName] Init a project with default templete')
|
226 | console.log(' config <cmd> Taro config')
|
227 | console.log(' create Create page for project')
|
228 | console.log(' build Build a project with options')
|
229 | console.log(' update Update packages of taro')
|
230 | console.log(' info Diagnostics Taro env info')
|
231 | console.log(' doctor Diagnose taro project')
|
232 | console.log(' inspect Inspect the webpack config')
|
233 | console.log(' help [cmd] display help for [cmd]')
|
234 | } else if (args.v) {
|
235 | console.log(getPkgVersion())
|
236 | }
|
237 | }
|
238 | }
|
239 | }
|