diff --git a/packages/taro-cli/src/__tests__/cli.spec.ts b/packages/taro-cli/src/__tests__/cli.spec.ts index e6899b1a1795..5b7d01c8ec6f 100644 --- a/packages/taro-cli/src/__tests__/cli.spec.ts +++ b/packages/taro-cli/src/__tests__/cli.spec.ts @@ -92,17 +92,6 @@ describe('inspect', () => { }) describe('init', () => { - const baseOpts = { - appPath: APP_PATH, - projectName: undefined, - typescript: undefined, - templateSource: undefined, - clone: false, - template: undefined, - css: undefined, - isHelp: false - } - it('should make configs', () => { const projectName = 'temp' const templateSource = 'https://url' @@ -113,14 +102,23 @@ describe('inspect', () => { const ins = MockedKernel.mock.instances[0] expect(ins.run).toHaveBeenCalledWith({ name: 'init', - opts: Object.assign({}, baseOpts, { - projectName, - typescript: true, - templateSource, - clone: true, - template, - css - }) + opts: { + _: [ + 'init', + 'temp' + ], + options: { + appPath: APP_PATH, + projectName, + typescript: true, + templateSource, + description: undefined, + clone: true, + template, + css + }, + isHelp: false + } }) }) @@ -131,7 +129,22 @@ describe('inspect', () => { const ins = MockedKernel.mock.instances[0] expect(ins.run).toHaveBeenCalledWith({ name: 'init', - opts: Object.assign({}, baseOpts, { projectName }) + opts: { + _: [ + 'init' + ], + options: { + appPath: APP_PATH, + projectName, + typescript: undefined, + templateSource: undefined, + description: undefined, + clone: false, + template: undefined, + css: undefined + }, + isHelp: false + } }) }) }) diff --git a/packages/taro-cli/src/cli.ts b/packages/taro-cli/src/cli.ts index 28b732def6d7..8fde5fc76e30 100644 --- a/packages/taro-cli/src/cli.ts +++ b/packages/taro-cli/src/cli.ts @@ -1,9 +1,7 @@ +import * as fs from 'fs-extra' import * as path from 'path' - import * as minimist from 'minimist' import { Kernel } from '@tarojs/service' - -import init from './commands/init' import customCommand from './commands/customCommand' import { getPkgVersion } from './util' @@ -36,23 +34,85 @@ export default class CLI { const _ = args._ const command = _[0] if (command) { + const appPath = this.appPath + const presetsPath = path.resolve(__dirname, 'presets') + const commandsPath = path.resolve(presetsPath, 'commands') + const platformsPath = path.resolve(presetsPath, 'platforms') + const filesPath = path.resolve(presetsPath, 'files') + const commandPlugins = fs.readdirSync(commandsPath) + const targetPlugin = `${command}.js` + + // 设置环境变量 + process.env.NODE_ENV ||= args.env || (args.watch ? 'development' : 'production') + const kernel = new Kernel({ - appPath: this.appPath, - presets: [ - path.resolve(__dirname, '.', 'presets', 'index.js') - ] + appPath, + presets: [], + plugins: [] }) + kernel.optsPlugins ||= [] + + // 针对不同的内置命令注册对应的命令插件 + if (commandPlugins.includes(targetPlugin)) { + kernel.optsPlugins.push(path.resolve(commandsPath, targetPlugin)) + } + switch (command) { case 'build': { let plugin let platform = args.type const { publicPath, bundleOutput, sourcemapOutput, sourceMapUrl, sourcemapSourcesRoot, assetsDest } = args + + // 针对不同的内置平台注册对应的端平台插件 + switch (platform) { + case 'weapp': + case 'alipay': + case 'swan': + case 'tt': + case 'qq': + case 'jd': + kernel.optsPlugins = [ + ...kernel.optsPlugins, + `@tarojs/plugin-platform-${platform}`, + path.resolve(filesPath, 'writeFileToDist.js'), + path.resolve(filesPath, 'generateProjectConfig.js'), + path.resolve(filesPath, 'generateFrameworkInfo.js') + ] + break + default: { + // h5, rn + const platformPlugins = fs.readdirSync(platformsPath) + const targetPlugin = `${platform}.js` + if (platformPlugins.includes(targetPlugin)) { + kernel.optsPlugins.push(path.resolve(platformsPath, targetPlugin)) + } + break + } + } + + // 根据 framework 启用插件 + const framework = kernel.config?.initialConfig.framework + switch (framework) { + case 'vue': + kernel.optsPlugins.push('@tarojs/plugin-framework-vue2') + break + case 'vue3': + kernel.optsPlugins.push('@tarojs/plugin-framework-vue3') + break + default: + kernel.optsPlugins.push('@tarojs/plugin-framework-react') + break + } + + // 编译小程序插件 if (typeof args.plugin === 'string') { plugin = args.plugin platform = 'plugin' + kernel.optsPlugins.push(path.resolve(platformsPath, 'plugin.js')) } - customCommand('build', kernel, { - _: args._, + + customCommand(command, kernel, { + _, platform, plugin, isWatch: Boolean(args.watch), @@ -73,17 +133,17 @@ export default class CLI { break } case 'init': { - const projectName = _[1] || args.name - init(kernel, { - appPath: this.appPath, - projectName, + customCommand(command, kernel, { + _, + appPath, + projectName: _[1] || args.name, description: args.description, typescript: args.typescript, templateSource: args['template-source'], clone: !!args.clone, template: args.template, css: args.css, - isHelp: args.h + h: args.h }) break } diff --git a/packages/taro-cli/src/commands/customCommand.ts b/packages/taro-cli/src/commands/customCommand.ts index f9d9fab9f80e..bf94f3d143ae 100644 --- a/packages/taro-cli/src/commands/customCommand.ts +++ b/packages/taro-cli/src/commands/customCommand.ts @@ -15,7 +15,6 @@ export default function customCommand ( }) // 设置环境变量 - process.env.NODE_ENV = process.env.NODE_ENV || options.env || (options.isWatch ? 'development' : 'production') if (options.platform) { process.env.TARO_ENV = options.platform } diff --git a/packages/taro-cli/src/commands/init.ts b/packages/taro-cli/src/commands/init.ts deleted file mode 100644 index 37f6cac00289..000000000000 --- a/packages/taro-cli/src/commands/init.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Kernel } from '@tarojs/service' - -export default function init (kernel: Kernel, { - appPath, - projectName, - description, - typescript, - templateSource, - clone, - template, - css, - isHelp -}: { - appPath: string, - projectName?: string, - description?: string - typescript?: boolean, - templateSource?: string, - clone?: boolean, - template?: string, - css?: string, - isHelp?: boolean -}) { - kernel.run({ - name: 'init', - opts: { - appPath, - projectName, - description, - typescript, - templateSource, - clone, - template, - css, - isHelp - } - }) -} diff --git a/packages/taro-cli/src/presets/commands/init.ts b/packages/taro-cli/src/presets/commands/init.ts index b0958870b9f9..165276c7cb8a 100644 --- a/packages/taro-cli/src/presets/commands/init.ts +++ b/packages/taro-cli/src/presets/commands/init.ts @@ -13,10 +13,11 @@ export default (ctx: IPluginContext) => { '--css [css]': 'CSS预处理器(sass/less/stylus/none)', '-h, --help': 'output usage information' }, - async fn () { + async fn (opts) { // init project const { appPath } = ctx.paths - const { projectName, templateSource, clone, template, description, typescript, css } = ctx.runOpts + const { options } = opts + const { projectName, templateSource, clone, template, description, typescript, css } = options const Project = require('../../create/project').default const project = new Project({ projectName, diff --git a/packages/taro-cli/src/presets/index.ts b/packages/taro-cli/src/presets/index.ts deleted file mode 100644 index 5fe1fb697971..000000000000 --- a/packages/taro-cli/src/presets/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -import * as path from 'path' - -export default () => { - return { - plugins: [ - // platforms - path.resolve(__dirname, 'platforms', 'h5.js'), - path.resolve(__dirname, 'platforms', 'rn.js'), - path.resolve(__dirname, 'platforms', 'plugin.js'), - ['@tarojs/plugin-platform-weapp', { backup: require.resolve('@tarojs/plugin-platform-weapp') }], - ['@tarojs/plugin-platform-alipay', { backup: require.resolve('@tarojs/plugin-platform-alipay') }], - ['@tarojs/plugin-platform-swan', { backup: require.resolve('@tarojs/plugin-platform-swan') }], - ['@tarojs/plugin-platform-tt', { backup: require.resolve('@tarojs/plugin-platform-tt') }], - ['@tarojs/plugin-platform-qq', { backup: require.resolve('@tarojs/plugin-platform-qq') }], - ['@tarojs/plugin-platform-jd', { backup: require.resolve('@tarojs/plugin-platform-jd') }], - - // commands - path.resolve(__dirname, 'commands', 'build.js'), - path.resolve(__dirname, 'commands', 'init.js'), - path.resolve(__dirname, 'commands', 'config.js'), - path.resolve(__dirname, 'commands', 'create.js'), - path.resolve(__dirname, 'commands', 'info.js'), - path.resolve(__dirname, 'commands', 'doctor.js'), - path.resolve(__dirname, 'commands', 'convert.js'), - path.resolve(__dirname, 'commands', 'update.js'), - path.resolve(__dirname, 'commands', 'inspect.js'), - path.resolve(__dirname, 'commands', 'help.js'), - - // files - path.resolve(__dirname, 'files', 'writeFileToDist.js'), - path.resolve(__dirname, 'files', 'generateProjectConfig.js'), - path.resolve(__dirname, 'files', 'generateFrameworkInfo.js'), - - // frameworks - ['@tarojs/plugin-framework-react', { backup: require.resolve('@tarojs/plugin-framework-react') }], - ['@tarojs/plugin-framework-vue2', { backup: require.resolve('@tarojs/plugin-framework-vue2') }], - ['@tarojs/plugin-framework-vue3', { backup: require.resolve('@tarojs/plugin-framework-vue3') }] - ] - } -} diff --git a/packages/taro-helper/src/index.ts b/packages/taro-helper/src/index.ts index 6d037e14c054..ed9cd9abc762 100644 --- a/packages/taro-helper/src/index.ts +++ b/packages/taro-helper/src/index.ts @@ -1,7 +1,6 @@ import * as fs from 'fs-extra' import * as chalk from 'chalk' import * as chokidar from 'chokidar' -import createDebug from 'debug' import * as constants from './constants' import * as utils from './utils' @@ -17,7 +16,7 @@ export const helper = { fs, chalk, chokidar, - createDebug + createDebug: id => require('debug')(id) } export default helper diff --git a/packages/taro-helper/src/npm.ts b/packages/taro-helper/src/npm.ts index 8ee540c405c1..38fe321b6063 100644 --- a/packages/taro-helper/src/npm.ts +++ b/packages/taro-helper/src/npm.ts @@ -1,5 +1,3 @@ -import * as resolvePath from 'resolve' -import * as spawn from 'cross-spawn' import * as chalk from 'chalk' import * as Util from './utils' @@ -23,6 +21,7 @@ const defaultInstallOptions: IInstallOptions = { export const taroPluginPrefix = '@tarojs/plugin-' export function resolveNpm (pluginName: string, root): Promise { + const resolvePath = require('resolve') if (!npmCached[pluginName]) { return new Promise((resolve, reject) => { resolvePath(`${pluginName}`, { basedir: root }, (err, res) => { @@ -38,6 +37,7 @@ export function resolveNpm (pluginName: string, root): Promise { } export function resolveNpmSync (pluginName: string, root): string { + const resolvePath = require('resolve') try { if (!npmCached[pluginName]) { const res = resolvePath.sync(pluginName, { basedir: root }) @@ -101,6 +101,7 @@ export function installNpmPkg (pkgList: string[] | string, options: IInstallOpti args.push('--save') } } + const spawn = require('cross-spawn') const output = spawn.sync(installer, args, { stdio: ['ignore', 'pipe', 'inherit'] }) diff --git a/packages/taro-helper/src/utils.ts b/packages/taro-helper/src/utils.ts index d76a87d58f7d..8ce2ec330525 100644 --- a/packages/taro-helper/src/utils.ts +++ b/packages/taro-helper/src/utils.ts @@ -1,16 +1,9 @@ import * as fs from 'fs-extra' import * as path from 'path' import * as os from 'os' -import { Transform } from 'stream' import * as child_process from 'child_process' -import * as parser from '@babel/parser' -import traverse from '@babel/traverse' - import * as chalk from 'chalk' -import * as findWorkspaceRoot from 'find-yarn-workspace-root' import { isPlainObject, camelCase, mergeWith, flatMap } from 'lodash' -import * as yauzl from 'yauzl' - import { processTypeEnum, processTypeMap, @@ -123,6 +116,7 @@ export function printLog (type: processTypeEnum, tag: string, filePath?: string) } export function recursiveFindNodeModules (filePath: string, lastFindPath?: string): string { + const findWorkspaceRoot = require('find-yarn-workspace-root') if (lastFindPath && (normalizePath(filePath) === normalizePath(lastFindPath))) { return filePath } @@ -393,6 +387,9 @@ export const applyArrayedVisitors = obj => { } export function unzip (zipPath) { + const Transform = require('stream').Transform + const yauzl = require('yauzl') + return new Promise((resolve, reject) => { yauzl.open(zipPath, { lazyEntries: true }, (err, zipfile) => { if (err || !zipfile) throw err @@ -495,6 +492,8 @@ export function removeHeadSlash (str: string) { } function analyzeImport (filePath: string): string[] { + const parser = require('@babel/parser') + const traverse = require('@babel/traverse').default const code = fs.readFileSync(filePath).toString() let importPaths: string[] = [] filePath = path.dirname(filePath) diff --git a/packages/taro-mini-runner/src/prerender/prerender.ts b/packages/taro-mini-runner/src/prerender/prerender.ts index 7431087259a2..28048b21febc 100644 --- a/packages/taro-mini-runner/src/prerender/prerender.ts +++ b/packages/taro-mini-runner/src/prerender/prerender.ts @@ -1,21 +1,15 @@ -import { Shortcuts, noop, isString, isObject, isFunction } from '@tarojs/shared' - -import { NodeVM } from 'vm2' -import { omitBy } from 'lodash' import * as webpack from 'webpack' import * as fs from 'fs' import { join } from 'path' -import { IBuildConfig } from '../utils/types' +import { Shortcuts, noop, isString, isObject, isFunction } from '@tarojs/shared' import { printPrerenderSuccess, printPrerenderFail } from '../utils/logHelper' +import type { NodeVM } from 'vm2' import type { IAdapter } from '@tarojs/shared/dist/template' +import type { IBuildConfig } from '../utils/types' type Attributes = Record -const { JSDOM } = require('jsdom') -const wx = require('miniprogram-simulate/src/api') -const micromatch = require('micromatch') - function unquote (str: string) { const car = str.charAt(0) const end = str.length - 1 @@ -76,6 +70,7 @@ export function validatePrerenderPages (pages: string[], config?: PrerenderConfi const { include = [], exclude = [], match } = config if (match) { + const micromatch = require('micromatch') pageConfigs = micromatch(pages, match) .filter((p: string) => !p.includes('.config')) .map((p: string) => ({ path: p, params: {} })) @@ -117,13 +112,14 @@ export class Prerender { private adapter: IAdapter public constructor (buildConfig: IBuildConfig, webpackConfig: webpack.Configuration, stat: webpack.Stats, adapter) { + const VM = require('vm2').NodeVM this.buildConfig = buildConfig this.outputPath = webpackConfig.output!.path! this.globalObject = webpackConfig.output!.globalObject! this.prerenderConfig = buildConfig.prerender! this.stat = stat.toJson() this.adapter = adapter - this.vm = new NodeVM({ + this.vm = new VM({ console: this.prerenderConfig.console ? 'inherit' : 'off', require: { external: true, @@ -174,6 +170,8 @@ export class Prerender { } private buildSandbox () { + const { JSDOM } = require('jsdom') + const wx = require('miniprogram-simulate/src/api') const Page = (config: unknown) => config const App = (config: unknown) => config const dom = new JSDOM() @@ -225,6 +223,7 @@ export class Prerender { const id = data.uid || data.sid const children = data[Shortcuts.Childnodes] ?? [] + const omitBy = require('lodash').omitBy const attrs = omitBy(data, (_, key) => { const internal = [Shortcuts.NodeName, Shortcuts.Childnodes, Shortcuts.Class, Shortcuts.Style, Shortcuts.Text, 'uid', 'sid'] return internal.includes(key) || key.startsWith('data-') diff --git a/packages/taro-service/src/Kernel.ts b/packages/taro-service/src/Kernel.ts index 8b4107c2d158..c5741ad93440 100644 --- a/packages/taro-service/src/Kernel.ts +++ b/packages/taro-service/src/Kernel.ts @@ -10,7 +10,6 @@ import { createDebug } from '@tarojs/helper' import * as helper from '@tarojs/helper' -import * as joi from '@hapi/joi' import { IPreset, @@ -58,7 +57,7 @@ export default class Kernel extends EventEmitter { constructor (options: IKernelOptions) { super() - this.debugger = createDebug('Taro:Kernel') + this.debugger = process.env.DEBUG === 'Taro:Kernel' ? createDebug('Taro:Kernel') : function () {} this.appPath = options.appPath || process.cwd() this.optsPresets = options.presets this.optsPlugins = options.plugins @@ -67,14 +66,8 @@ export default class Kernel extends EventEmitter { this.commands = new Map() this.platforms = new Map() this.initHelper() - } - - async init () { - this.debugger('init') this.initConfig() this.initPaths() - this.initPresetsAndPlugins() - await this.applyPlugins('onReady') } initConfig () { @@ -167,6 +160,7 @@ export default class Kernel extends EventEmitter { if (typeof pluginCtx.optsSchema !== 'function') { return } + const joi = require('@hapi/joi') const schema = pluginCtx.optsSchema(joi) if (!joi.isSchema(schema)) { throw new Error(`插件${pluginCtx.id}中设置参数检查 schema 有误,请检查!`) @@ -243,6 +237,9 @@ export default class Kernel extends EventEmitter { throw new Error('调用失败,未传入正确的名称!') } const hooks = this.hooks.get(name) || [] + if (!hooks.length) { + return await initialVal + } const waterfall = new AsyncSeriesWaterfallHook(['arg']) if (hooks.length) { const resArr: any[] = [] @@ -306,24 +303,33 @@ export default class Kernel extends EventEmitter { this.debugger('command:runOpts') this.debugger(`command:runOpts:${JSON.stringify(opts, null, 2)}`) this.setRunOpts(opts) - await this.init() + + this.debugger('initPresetsAndPlugins') + this.initPresetsAndPlugins() + + await this.applyPlugins('onReady') + this.debugger('command:onStart') await this.applyPlugins('onStart') + if (!this.commands.has(name)) { throw new Error(`${name} 命令不存在`) } + if (opts?.isHelp) { return this.runHelp(name) } + if (opts?.options?.platform) { opts.config = this.runWithPlatform(opts.options.platform) + await this.applyPlugins({ + name: 'modifyRunnerOpts', + opts: { + opts: opts?.config + } + }) } - await this.applyPlugins({ - name: 'modifyRunnerOpts', - opts: { - opts: opts?.config - } - }) + await this.applyPlugins({ name, opts