From 518a96052658d4abb6718f668b0d7dd511b194e1 Mon Sep 17 00:00:00 2001 From: yuche Date: Mon, 17 Dec 2018 17:31:50 +0800 Subject: [PATCH 001/103] =?UTF-8?q?feat(transformer):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=BF=AB=E5=BA=94=E7=94=A8=E9=80=82=E9=85=8D=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/adapter.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/taro-transformer-wx/src/adapter.ts b/packages/taro-transformer-wx/src/adapter.ts index 97bd3340d207..f7e3f8349e44 100644 --- a/packages/taro-transformer-wx/src/adapter.ts +++ b/packages/taro-transformer-wx/src/adapter.ts @@ -61,6 +61,17 @@ const ttAdapter: Adapter = { type: Adapters.tt } +const quickappAdapter: Adapter = { + if: 'if', + else: 'else', + elseif: 'elif', + for: 'for', + forItem: 'for-item', + forIndex: 'for-index', + key: 'key', + type: Adapters.quickapp +} + export let Adapter: Adapter = weixinAdapter export function setAdapter (adapter: Adapters) { @@ -74,6 +85,9 @@ export function setAdapter (adapter: Adapters) { case Adapters.tt: Adapter = ttAdapter break + case Adapters.quickapp: + Adapter = quickappAdapter + break default: Adapter = weixinAdapter break From 11b1b1e4529187b9a4ae8c793df17f373e7b0ecb Mon Sep 17 00:00:00 2001 From: yuche Date: Mon, 17 Dec 2018 18:12:01 +0800 Subject: [PATCH 002/103] =?UTF-8?q?feat(transformer):=20=E6=94=B9=E5=8F=98?= =?UTF-8?q?=E5=BF=AB=E5=BA=94=E7=94=A8=E7=9A=84=E5=BE=AA=E7=8E=AF=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/jsx.ts | 28 +++++++------ packages/taro-transformer-wx/src/render.ts | 48 +++++++++++++++++----- 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/packages/taro-transformer-wx/src/jsx.ts b/packages/taro-transformer-wx/src/jsx.ts index 3574aaa78e21..00a40c8f7bdf 100644 --- a/packages/taro-transformer-wx/src/jsx.ts +++ b/packages/taro-transformer-wx/src/jsx.ts @@ -94,6 +94,20 @@ export function setJSXAttr ( } } +export function generateJSXAttr (ast: t.Node) { + return decodeUnicode( + generate(ast, { + quotes: 'single', + jsonCompatibleStrings: true + }) + .code + ) + .replace(/(this\.props\.)|(this\.state\.)/g, '') + .replace(/(props\.)|(state\.)/g, '') + .replace(/this\./g, '') + .replace(/ t.isLiteral(p)) } @@ -135,19 +149,7 @@ function parseJSXChildren ( if (t.isJSXElement(child.expression)) { return str + parseJSXElement(child.expression) } - return str + `{${ - decodeUnicode( - generate(child, { - quotes: 'single', - jsonCompatibleStrings: true - }) - .code - ) - .replace(/(this\.props\.)|(this\.state\.)/g, '') - .replace(/(props\.)|(state\.)/g, '') - .replace(/this\./g, '') - .replace(/ Date: Mon, 17 Dec 2018 19:42:53 +0800 Subject: [PATCH 003/103] =?UTF-8?q?feat(transformer):=20JSX=20=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2=E5=92=8C=20JSX=20=E8=A1=A8=E8=BE=BE=E5=BC=8F?= =?UTF-8?q?=E5=9C=A8=E5=BF=AB=E5=BA=94=E7=94=A8=E9=83=BD=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E7=94=A8=20Text=20=E5=8C=85=E8=A3=B9=E8=B5=B7=E6=9D=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/index.ts | 21 ++++++++++++++++++++- packages/taro-transformer-wx/src/jsx.ts | 2 +- packages/taro-transformer-wx/src/render.ts | 15 ++++++++++++++- packages/taro-transformer-wx/src/utils.ts | 11 +++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/packages/taro-transformer-wx/src/index.ts b/packages/taro-transformer-wx/src/index.ts index e9a00ef32a44..142ded937b65 100644 --- a/packages/taro-transformer-wx/src/index.ts +++ b/packages/taro-transformer-wx/src/index.ts @@ -4,7 +4,15 @@ import { prettyPrint } from 'html' import { transform as parse } from 'babel-core' import * as ts from 'typescript' import { Transformer } from './class' -import { setting, findFirstIdentifierFromMemberExpression, isContainJSXElement, codeFrameError, isArrayMapCallExpression, getSuperClassCode } from './utils' +import { + setting, + findFirstIdentifierFromMemberExpression, + isContainJSXElement, + codeFrameError, + isArrayMapCallExpression, + replaceJSXTextWithTextComponent, + getSuperClassCode +} from './utils' import * as t from 'babel-types' import { DEFAULT_Component_SET, INTERNAL_SAFE_GET, TARO_PACKAGE_NAME, REDUX_PACKAGE_NAME, MOBX_PACKAGE_NAME, IMAGE_COMPONENTS, INTERNAL_INLINE_STYLE, THIRD_PARTY_COMPONENTS, INTERNAL_GET_ORIGNAL, setLoopOriginal, GEL_ELEMENT_BY_ID, lessThanSignPlacehold } from './constant' import { Adapters, setAdapter, Adapter } from './adapter' @@ -176,6 +184,17 @@ export default function transform (options: Options): TransformResult { let renderMethod!: NodePath let isImportTaro = false traverse(ast, { + JSXText (path) { + if (Adapter.type !== Adapters.quickapp) { + return + } + const value = path.node.value + if (!value.trim()) { + return + } + + replaceJSXTextWithTextComponent(path) + }, TemplateLiteral (path) { const nodes: t.Expression[] = [] const { quasis, expressions } = path.node diff --git a/packages/taro-transformer-wx/src/jsx.ts b/packages/taro-transformer-wx/src/jsx.ts index 00a40c8f7bdf..9e5c772d28e4 100644 --- a/packages/taro-transformer-wx/src/jsx.ts +++ b/packages/taro-transformer-wx/src/jsx.ts @@ -149,7 +149,7 @@ function parseJSXChildren ( if (t.isJSXElement(child.expression)) { return str + parseJSXElement(child.expression) } - return str + generateJSXAttr(child) + return str + `{${generateJSXAttr(child)}}` } return str }, '') diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts index 8aeb094fecec..a300c3e4f52e 100644 --- a/packages/taro-transformer-wx/src/render.ts +++ b/packages/taro-transformer-wx/src/render.ts @@ -23,7 +23,8 @@ import { isContainJSXElement, getSlotName, getSuperClassCode, - isContainStopPropagation + isContainStopPropagation, + replaceJSXTextWithTextComponent } from './utils' import { difference, get as safeGet, cloneDeep } from 'lodash' import { @@ -1157,6 +1158,9 @@ export class RenderParser { renderBody.traverse(this.loopComponentVisitor) this.handleLoopComponents() renderBody.traverse(this.visitors) + if (Adapter.type === Adapters.quickapp) { + renderBody.traverse(this.quickappVistor) + } this.setOutputTemplate() this.checkDuplicateName() this.removeJSXStatement() @@ -1168,6 +1172,15 @@ export class RenderParser { this.setLoopRefFlag() } + private quickappVistor: Visitor = { + JSXExpressionContainer (path) { + if (path.parentPath.isJSXAttribute() || isContainJSXElement(path)) { + return + } + replaceJSXTextWithTextComponent(path) + } + } + checkDuplicateData () { this.initState.forEach((stateName) => { if (this.templates.has(stateName)) { diff --git a/packages/taro-transformer-wx/src/utils.ts b/packages/taro-transformer-wx/src/utils.ts index 06e583ec2a08..ab945d04d5aa 100644 --- a/packages/taro-transformer-wx/src/utils.ts +++ b/packages/taro-transformer-wx/src/utils.ts @@ -11,6 +11,17 @@ import { Adapter } from './adapter' import { transformOptions } from './options' const template = require('babel-template') +export function replaceJSXTextWithTextComponent (path: NodePath) { + const parent = path.findParent(p => p.isJSXElement()) + if (parent && parent.isJSXElement() && t.isJSXIdentifier(parent.node.openingElement.name) && parent.node.openingElement.name.name !== 'Text') { + path.replaceWith(t.jSXElement( + t.jSXOpeningElement(t.jSXIdentifier('Text'), []), + t.jSXClosingElement(t.jSXIdentifier('Text')), + [path.isJSXText() ? t.jSXText(path.node.value) : path.node] + )) + } +} + export const incrementId = () => { let id = 0 return () => id++ From 581d0ec1d55ae4ff1157ee6ebb6eaa3a91eac6e4 Mon Sep 17 00:00:00 2001 From: Alan Zhang Date: Mon, 29 Oct 2018 11:40:48 +0800 Subject: [PATCH 004/103] =?UTF-8?q?feat(doctor):=20=E5=A2=9E=E5=8A=A0=20do?= =?UTF-8?q?ctor=20=E5=AD=90=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/eslint-config-taro/rules/jsx.js | 4 + packages/taro-cli/bin/taro | 1 + packages/taro-cli/bin/taro-build | 2 +- packages/taro-cli/bin/taro-doctor | 65 ++++++++++ packages/taro-cli/package.json | 9 ++ packages/taro-cli/src/doctor/configSchema.js | 103 ++++++++++++++++ .../taro-cli/src/doctor/configValidator.js | 33 +++++ .../taro-cli/src/doctor/eslintValidator.js | 26 ++++ packages/taro-cli/src/doctor/index.js | 8 ++ packages/taro-cli/src/doctor/joi2desc.js | 113 ++++++++++++++++++ .../taro-cli/src/doctor/packageValidator.js | 59 +++++++++ .../taro-cli/src/doctor/recommandValidator.js | 70 +++++++++++ .../taro-cli/src/doctor/validatorEslintrc.js | 9 ++ 13 files changed, 501 insertions(+), 1 deletion(-) create mode 100755 packages/taro-cli/bin/taro-doctor create mode 100644 packages/taro-cli/src/doctor/configSchema.js create mode 100644 packages/taro-cli/src/doctor/configValidator.js create mode 100644 packages/taro-cli/src/doctor/eslintValidator.js create mode 100644 packages/taro-cli/src/doctor/index.js create mode 100644 packages/taro-cli/src/doctor/joi2desc.js create mode 100644 packages/taro-cli/src/doctor/packageValidator.js create mode 100644 packages/taro-cli/src/doctor/recommandValidator.js create mode 100644 packages/taro-cli/src/doctor/validatorEslintrc.js diff --git a/packages/eslint-config-taro/rules/jsx.js b/packages/eslint-config-taro/rules/jsx.js index 1250cbe45364..8bdbc1e05e8f 100644 --- a/packages/eslint-config-taro/rules/jsx.js +++ b/packages/eslint-config-taro/rules/jsx.js @@ -226,10 +226,14 @@ module.exports = { // beforeSelfClosing: 'always', // afterOpening: 'never' // }], + 'react/jsx-tag-spacing': ['error', { beforeSelfClosing: 'always' }], // Enforce spaces before the closing bracket of self-closing JSX elements // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-tag-spacing.md 'react/jsx-tag-spacing': ["error", { "beforeSelfClosing": "always" }], + // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-space-before-closing.md + // Deprecated in favor of jsx-tag-spacing + // 'react/jsx-space-before-closing': ['error', 'always'], // // Prevent usage of Array index in keys // // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-array-index-key.md diff --git a/packages/taro-cli/bin/taro b/packages/taro-cli/bin/taro index 8fd4125daa72..e4117d5ee517 100755 --- a/packages/taro-cli/bin/taro +++ b/packages/taro-cli/bin/taro @@ -21,4 +21,5 @@ program .command('update', 'Update packages of taro') .command('convert', 'Convert weapp to taro') .command('info', 'Diagnostics Taro env info') + .command('doctor', 'Diagnose taro project') .parse(process.argv) diff --git a/packages/taro-cli/bin/taro-build b/packages/taro-cli/bin/taro-build index fe42b1f749a1..124553abd985 100755 --- a/packages/taro-cli/bin/taro-build +++ b/packages/taro-cli/bin/taro-build @@ -18,7 +18,7 @@ program const args = program.args const { type, watch, ui } = program -let { env } = program +let { env } = program env = process.env.NODE_ENV || env diff --git a/packages/taro-cli/bin/taro-doctor b/packages/taro-cli/bin/taro-doctor new file mode 100755 index 000000000000..771a7d6e0293 --- /dev/null +++ b/packages/taro-cli/bin/taro-doctor @@ -0,0 +1,65 @@ +#!/usr/bin/env node + +const path = require('path') +const program = require('commander') +const _ = require('lodash/fp') +const ora = require('ora') +const chalk = require('chalk') +const fs = require('fs-extra') +const { PROJECT_CONFIG } = require('../src/util') +const PROJECT_CONF_PATH = path.join(process.cwd(), PROJECT_CONFIG) + +if (!fs.existsSync(PROJECT_CONF_PATH)) { + console.log(chalk.red(`找不到项目配置文件${PROJECT_CONFIG},请确定当前目录是Taro项目根目录!`)) + process.exit(1) +} + +const { validators } = require('../src/doctor') + +const NOTE_ALL_RIGHT = chalk.green('[✓] ') +const NOTE_VALID = chalk.yellow('[!] ') +const NOTE_INVALID = chalk.red('[✗] ') + +const titleChalk = chalk.hex('#aaa') +const lineChalk = chalk.hex('#fff') +const solutionChalk = chalk.hex('#999') + +function printReport (reports) { + _.forEach(report => { + console.log('\n' + titleChalk(report.desc)) + + if (report.raw) { + console.log(report.raw) + return + } + + if (_.getOr(0, 'lines.length', report) === 0) { + console.log(` ${NOTE_ALL_RIGHT}没有发现问题`) + return + } + + _.forEach(line => { + console.log( + ' ' + + (line.valid ? NOTE_VALID : NOTE_INVALID) + + lineChalk(line.desc) + ) + if (line.solution) { + console.log(' ' + solutionChalk(line.solution)) + } + }, report.lines) + }, reports) +} + +program + .option('-v --verbose', 'Print all message') + .parse(process.argv) + +async function diagnose () { + const spinner = ora('正在诊断项目...').start() + const reportsP = _.invokeMap(_.call, validators) + const reports = await Promise.all(reportsP) + spinner.succeed('诊断完成') + printReport(reports) +} +diagnose() diff --git a/packages/taro-cli/package.json b/packages/taro-cli/package.json index a4ea7841313a..c6bbdf283266 100644 --- a/packages/taro-cli/package.json +++ b/packages/taro-cli/package.json @@ -46,16 +46,25 @@ "css-to-react-native-transform": "^1.4.0", "ejs": "^2.6.1", "envinfo": "^6.0.1", + "babel-eslint": "^8.2.3", + "eslint": "^4.15.0", + "eslint-config-taro": "^1.1.4", + "eslint-plugin-taro": "^1.1.4", + "eslint-plugin-import": "^2.8.0", + "eslint-plugin-react": "^7.4.0", + "eslint-plugin-typescript": "^0.12.0", "fs-extra": "^5.0.0", "generic-names": "^2.0.1", "glob": "^7.1.2", "inquirer": "^5.2.0", + "joi": "^14.0.6", "klaw": "^2.1.1", "latest-version": "^4.0.0", "lodash": "^4.17.5", "mem-fs": "^1.1.3", "mem-fs-editor": "^4.0.0", "minimatch": "^3.0.4", + "npm-check": "^5.9.0", "ora": "^2.0.0", "postcss": "^6.0.22", "postcss-modules-extract-imports": "^1.1.0", diff --git a/packages/taro-cli/src/doctor/configSchema.js b/packages/taro-cli/src/doctor/configSchema.js new file mode 100644 index 000000000000..51441b227109 --- /dev/null +++ b/packages/taro-cli/src/doctor/configSchema.js @@ -0,0 +1,103 @@ +const Joi = require('joi'); + +const schema = Joi.object().keys({ + 'projectName': Joi.string().required(), + 'date': Joi.date(), + 'designWidth': Joi.number().integer(), + 'deviceRatio': Joi.object().pattern( + Joi.number(), Joi.number() + ), + 'sourceRoot': Joi.string().required(), + 'outputRoot': Joi.string().required(), + + // NOTE: 考虑是否增加第三方模块的配置检查 + 'plugins': Joi.object().pattern( + Joi.string(), Joi.object() + ), + + 'env': Joi.object().pattern( + Joi.string(), Joi.string() + ), + + 'defineConstants': Joi.object().pattern( + Joi.string(), Joi.string() + ), + + 'copy': Joi.object().keys({ + 'patterns': Joi.array().items(Joi.object().keys({ + 'from': Joi.string().required(), + 'to': Joi.string().required(), + 'ignore': Joi.string() + })), + + 'options': Joi.object().keys({ + 'ignore': Joi.array().items(Joi.string()) + }) + }), + + 'weapp': Joi.object().keys({ + 'compile': Joi.object().keys({ + 'exclude': Joi.array().items(Joi.string()) + }), + 'module': Joi.object() // 第三方配置 + }), + + 'h5': Joi.object().keys({ + 'devServer': Joi.object(), // 第三方配置 + 'publicPath': Joi.string(), + 'staticDirectory': Joi.string(), + 'chunkDirectory': Joi.string(), + 'webpackChain': Joi.func(), + + // DEPRECATED: https://nervjs.github.io/taro/docs/config-detail.html#deprecated-h5webpack + 'webpack': Joi.forbidden(), + + // https://webpack.js.org/configuration/resolve/#resolve-alias + 'alias': Joi.object().pattern( + Joi.string(), Joi.string().strict() + ), + + // https://webpack.js.org/configuration/entry-context/#entry + 'entry': Joi.alternatives( + Joi.string(), + Joi.array().items(Joi.alternatives( + Joi.string(), + Joi.object().pattern( + Joi.string(), + Joi.alternatives( + Joi.string(), + Joi.array().items(Joi.string()) + ) + ) + )), + Joi.func() + ), + 'enableSourceMap': Joi.bool(), + 'enableExtract': Joi.bool(), + 'cssLoaderOption': Joi.object(), // 第三方配置 + 'styleLoaderOption': Joi.object(), // 第三方配置 + 'sassLoaderOption': Joi.object(), // 第三方配置 + 'lessLoaderOption': Joi.object(), // 第三方配置 + 'stylusLoaderOption': Joi.object(), // 第三方配置 + 'mediaUrlLoaderOption': Joi.object(), // 第三方配置 + 'fontUrlLoaderOption': Joi.object(), // 第三方配置 + 'imageUrlLoaderOption': Joi.object(), // 第三方配置 + 'miniCssExtractPluginOption': Joi.object(), // 第三方配置 + + 'module': Joi.object().keys({ + 'postcss': Joi.object().keys({ + 'autoprefixer': Joi.object().keys({ + 'enable': Joi.bool(), + 'config': Joi.object() // 第三方配置 + }), + 'pxtransform': Joi.object().keys({ + 'enable': Joi.bool(), + 'config': Joi.object() + }), + 'plugins': Joi.array() // 第三方配置 + }) + }) + }) +}) + +module.exports = schema diff --git a/packages/taro-cli/src/doctor/configValidator.js b/packages/taro-cli/src/doctor/configValidator.js new file mode 100644 index 000000000000..41e6a402b5ea --- /dev/null +++ b/packages/taro-cli/src/doctor/configValidator.js @@ -0,0 +1,33 @@ +const configSchema = require('./configSchema') +const Joi = require('joi') +const _ = require('lodash/fp') +const path = require('path') +const joi2desc = require('./joi2desc') + +const { PROJECT_CONFIG } = require('../util') +const PROJECT_CONF_PATH = path.join(process.cwd(), PROJECT_CONFIG) +const PROJECT_CONF = require(PROJECT_CONF_PATH)(_.merge) + +function buildDesc (error) { + return error.path.join('.') + ' ' + joi2desc(error) +} + +function buildLine (error) { + return { + desc: buildDesc(error), + valid: false + } +} + +function buildReport (errors) { + const errorLines = _.compose(_.map(buildLine), _.get('details'))(errors) + return { + desc: `检查 Taro 配置 (${PROJECT_CONF_PATH})`, + lines: errorLines + } +} + +module.exports = async function () { + const { error } = Joi.validate(PROJECT_CONF, configSchema, { abortEarly: false }) + return buildReport(error) +} diff --git a/packages/taro-cli/src/doctor/eslintValidator.js b/packages/taro-cli/src/doctor/eslintValidator.js new file mode 100644 index 000000000000..c2b03be66cea --- /dev/null +++ b/packages/taro-cli/src/doctor/eslintValidator.js @@ -0,0 +1,26 @@ +const path = require('path') +const _ = require('lodash') +const { CLIEngine } = require('eslint') + +const { PROJECT_CONFIG } = require('../util') +const projectConfPath = path.join(process.cwd(), PROJECT_CONFIG) +const projectConf = require(projectConfPath)(_.merge) + +const ESLINT_CONFIG_PATH = path.join(__dirname, 'validatorEslintrc.js') + +module.exports = function () { + const eslintCli = new CLIEngine({ + cwd: process.cwd(), + useEslintrc: false, + configFile: ESLINT_CONFIG_PATH + }) + + const sourceFiles = path.join(process.cwd(), projectConf.sourceRoot, '**/*.{js,ts,jsx,tsx}') + const report = eslintCli.executeOnFiles([sourceFiles]) + const formatter = eslintCli.getFormatter() + + return { + desc: '检查 ESLint (以下为 ESLint 的输出)', + raw: formatter(report.results) + } +} diff --git a/packages/taro-cli/src/doctor/index.js b/packages/taro-cli/src/doctor/index.js new file mode 100644 index 000000000000..bab3d7b8109c --- /dev/null +++ b/packages/taro-cli/src/doctor/index.js @@ -0,0 +1,8 @@ +module.exports = { + validators: [ + require('./configValidator'), + require('./packageValidator'), + require('./recommandValidator'), + require('./eslintValidator') + ] +} diff --git a/packages/taro-cli/src/doctor/joi2desc.js b/packages/taro-cli/src/doctor/joi2desc.js new file mode 100644 index 000000000000..7f43c13af799 --- /dev/null +++ b/packages/taro-cli/src/doctor/joi2desc.js @@ -0,0 +1,113 @@ +const joi2desc = { + 'alternatives.base': '不符合任何一个可选项', + 'any.empty': '不允许为空', + 'any.required': '必须填写', + 'any.unknown': '', + 'array.base': '应该为数组类型', + 'any.allowOnly': '', + 'any.default': '', + 'any.invalid': '', + 'array.excludes': '', + 'array.excludesSingle': '', + 'array.includesRequiredBoth': '', + 'array.includesRequiredKnowns': '', + 'array.includesRequiredUnknowns': '', + 'array.includes': '', + 'array.includesSingle': '', + 'array.length': '', + 'array.max': '', + 'array.min': '', + 'array.orderedLength': '', + 'array.ref': '', + 'array.sparse': '', + 'array.unique': '', + 'binary.base': '', + 'binary.length': '', + 'binary.max': '', + 'binary.min': '', + 'boolean.base': '应该为布尔值', + 'date.base': '应该为一个日期', + 'date.greater': '', + 'date.isoDate': '', + 'date.less': '', + 'date.max': '', + 'date.min': '', + 'date.ref': '', + 'date.strict': '', + 'date.timestamp.javascript': '', + 'date.timestamp.unix': '', + 'function.arity': '', + 'function.base': '应该为一个函数', + 'function.class': '', + 'function.maxArity': '', + 'function.minArity': '', + 'function.ref': '', + 'lazy.base': '', + 'lazy.schema': '', + 'number.base': '应该为一个数字', + 'number.greater': '', + 'number.integer': '', + 'number.less': '', + 'number.max': '', + 'number.min': '', + 'number.multiple': '', + 'number.negative': '', + 'number.port': '', + 'number.positive': '', + 'number.precision': '', + 'number.ref': '', + 'number.unsafe': '', + 'object.allowUnknown': '', + 'object.and': '', + 'object.assert': '', + 'object.base': '应该为一个对象', + 'object.length': '', + 'object.max': '', + 'object.min': '', + 'object.missing': '', + 'object.nand': '', + 'object.rename.multiple': '', + 'object.rename.override': '', + 'object.rename.regex.multiple': '', + 'object.rename.regex.override': '', + 'object.schema': '', + 'object.type': '', + 'object.with': '', + 'object.without': '', + 'object.xor': '', + 'string.alphanum': '', + 'string.base64': '', + 'string.base': '应该为一个字符串', + 'string.creditCard': '', + 'string.dataUri': '', + 'string.email': '', + 'string.guid': '', + 'string.hexAlign': '', + 'string.hex': '', + 'string.hostname': '', + 'string.ipVersion': '', + 'string.ip': '', + 'string.isoDate': '', + 'string.length': '', + 'string.lowercase': '', + 'string.max': '', + 'string.min': '', + 'string.normalize': '', + 'string.ref': '', + 'string.regex.base': '', + 'string.regex.name': '', + 'string.regex.invert.base': '', + 'string.regex.invert.name': '', + 'string.token': '', + 'string.trim': '', + 'string.uppercase': '', + 'string.uri': '', + 'string.uriCustomScheme': '', + 'string.uriRelativeOnly': '', + 'symbol.base': '', + 'symbol.map': '' +} + +module.exports = function (error) { + return joi2desc[error.type] || error.message +} diff --git a/packages/taro-cli/src/doctor/packageValidator.js b/packages/taro-cli/src/doctor/packageValidator.js new file mode 100644 index 000000000000..5a9c7f4f5934 --- /dev/null +++ b/packages/taro-cli/src/doctor/packageValidator.js @@ -0,0 +1,59 @@ +const _ = require('lodash/fp') +const npmCheck = require('npm-check') +const cliPkg = require('../../package.json') + +const isTaroPkg = pkg => /^@tarojs\//.test(pkg.moduleName) +const isCliVersionNotMatch = _.compose(_.negate(_.equals(cliPkg.version)), _.get('installed')) +const isPkgInstalled = _.get('isInstalled') +const isPkgNotInstalled = _.negate(isPkgInstalled) + +async function checkPkgs () { + let errorLines = [] + const pkgs = await npmCheck() + .then(_.invoke('all')) + .then(_.get('packages')) + const taroPkgs = _.filter(isTaroPkg, pkgs) + + errorLines = _.concat(errorLines, pkgsNotInstalled(pkgs)) + errorLines = _.concat(errorLines, taroShouldUpdate(taroPkgs)) + errorLines = _.concat(errorLines, taroCliVersionNotMatch(taroPkgs)) + errorLines = _.compact(errorLines) + + return { + desc: '检查依赖', + lines: errorLines + } +} + +function taroCliVersionNotMatch (pkgs) { + const pkgsNotMatch = _.filter(pkg => isPkgInstalled(pkg) && isCliVersionNotMatch(pkg), pkgs) + const lines = _.map(pkg => Object({ + desc: `${pkg.moduleName} (${pkg.installed}) 与当前使用的 @tarojs/cli (${cliPkg.version}) 版本不一致, 请更新为统一的版本`, + valid: false + }), pkgsNotMatch) + return lines +} + +function taroShouldUpdate (pkgs) { + // 未安装的依赖的情况下查找更新没有意义 + const taroPkg = _.find(isPkgInstalled, pkgs) + if (!taroPkg || taroPkg.latest === taroPkg.installed) return [] + + return [{ + // 需要正确设置 next 版本以使 npm-check 在判定最新版本时将 rc 版本也算在内 + desc: `检测到最新稳定版本 Taro ${taroPkg.latest} , 当前 cli 版本 ${cliPkg.version}`, + valid: true, // 并非错误,仅提示即可 + solution: `前往 https://github.com/NervJS/taro/releases 了解详情` + }] +} + +function pkgsNotInstalled (pkgs) { + const uninstalledPkgs = _.filter(isPkgNotInstalled, pkgs) + const lines = _.map(pkg => Object({ + desc: `使用到的依赖 ${pkg.moduleName} 还没有安装`, + valid: false + }), uninstalledPkgs) + return lines +} + +module.exports = checkPkgs diff --git a/packages/taro-cli/src/doctor/recommandValidator.js b/packages/taro-cli/src/doctor/recommandValidator.js new file mode 100644 index 000000000000..d3e036ad4cd5 --- /dev/null +++ b/packages/taro-cli/src/doctor/recommandValidator.js @@ -0,0 +1,70 @@ +const _ = require('lodash/fp') +const fs = require('fs-extra') +const path = require('path') +const chalk = require('chalk') + +const PROJECT_PACKAGE_PATH = path.join(process.cwd(), 'package.json') +const PROJECT_FOLDER_FILES = fs.readdirSync('./') +const TEST_FRAMEWORKS = ['jest', 'mocha', 'ava', 'tape', 'jesmine', 'karma'] +const LINTERS = ['eslint', 'jslint', 'tslint', 'jshint'] +const README = ['readme', 'readme.md', 'readme.markdown'] +const GITIGNORE = ['.gitignore'] +const EDITORCONFIG = ['.editorconfig'] + +if (!fs.existsSync(PROJECT_PACKAGE_PATH)) { + console.log(chalk.red(`找不到${PROJECT_PACKAGE_PATH},请确定当前目录是Taro项目根目录!`)) + process.exit(1) +} +const projectPackage = require(PROJECT_PACKAGE_PATH) +const devDependencies = _.keysIn(_.get('devDependencies', projectPackage)) + +const inDevDependencies = dependencies => (_.intersectionBy(_.toLower, devDependencies, dependencies)).length > 0 +const hasRecommandTestFrameworks = inDevDependencies(TEST_FRAMEWORKS) +const hasRecommandLinters = inDevDependencies(LINTERS) + +const inProjectFolder = filenames => (_.intersectionBy(_.toLower, PROJECT_FOLDER_FILES, filenames)).length > 0 +const hasReadme = inProjectFolder(README) +const hasGitignore = inProjectFolder(GITIGNORE) +const hasEditorconfig = inProjectFolder(EDITORCONFIG) + +module.exports = async function () { + const errorLines = [] + + if (!hasRecommandTestFrameworks) { + errorLines.push({ + desc: '没有检查到常见的测试依赖(jest/mocha/ava/tape/jesmine/karma), 配置测试可以帮助提升项目质量', + valid: true, + solution: '可以参考 https://github.com/NervJS/taro-ui-sample 项目, 其中已经包含了完整的测试配置与范例' + }) + } + if (!hasRecommandLinters) { + errorLines.push({ + desc: '没有检查到常见的 linter (eslint/jslint/jshint/tslint), 配置 linter 可以帮助提升项目质量', + valid: true, + solution: 'Taro 还提供了定制的 ESLint 规则, 可以帮助开发者避免一些常见的问题. 使用 taro cli 创建新项目即可体验' + }) + } + if (!hasReadme) { + errorLines.push({ + desc: '没有检查到 Readme (readme/readme.md/readme.markdown), 编写 Readme 可以方便其他人了解项目', + valid: true + }) + } + if (!hasGitignore) { + errorLines.push({ + desc: '没有检查到 .gitignore 配置, 配置 .gitignore 以避免将敏感信息或不必要的内容提交到代码仓库', + valid: true + }) + } + if (!hasEditorconfig) { + errorLines.push({ + desc: '没有检查到 .editconfig 配置, 配置 editconfig 以统一项目成员编辑器的代码风格', + valid: true + }) + } + + return { + desc: '检查推荐内容', + lines: errorLines + } +} diff --git a/packages/taro-cli/src/doctor/validatorEslintrc.js b/packages/taro-cli/src/doctor/validatorEslintrc.js new file mode 100644 index 000000000000..521a005d3929 --- /dev/null +++ b/packages/taro-cli/src/doctor/validatorEslintrc.js @@ -0,0 +1,9 @@ +module.exports = { + 'extends': ['taro'], + 'rules': { + 'no-unused-vars': ['error', { 'varsIgnorePattern': 'Taro' }], + 'react/jsx-filename-extension': [1, { 'extensions': ['.js', '.jsx', '.tsx'] }] + }, + 'parser': 'babel-eslint', + 'plugins': ['typescript'] +} From 01477697e566d076b5e19fdf120ca9c1705eff29 Mon Sep 17 00:00:00 2001 From: yuche Date: Tue, 25 Dec 2018 17:14:29 +0800 Subject: [PATCH 005/103] =?UTF-8?q?refactor(transformer):=20=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E9=9C=80=E8=A6=81=E6=A0=87=E8=AE=B0=E5=BE=AA=E7=8E=AF?= =?UTF-8?q?=E7=9A=84=E5=8F=98=E9=87=8F=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/class.ts | 2 -- packages/taro-transformer-wx/src/render.ts | 19 ------------------- 2 files changed, 21 deletions(-) diff --git a/packages/taro-transformer-wx/src/class.ts b/packages/taro-transformer-wx/src/class.ts index 7e82839f071b..f273616fb481 100644 --- a/packages/taro-transformer-wx/src/class.ts +++ b/packages/taro-transformer-wx/src/class.ts @@ -121,7 +121,6 @@ class Transformer { private classPath: NodePath private customComponentNames = new Set() private usedState = new Set() - private loopStateName: Map, string> = new Map() private customComponentData: Array = [] private componentProperies: Set private sourcePath: string @@ -719,7 +718,6 @@ class Transformer { this.initState, this.jsxReferencedIdentifiers, this.usedState, - this.loopStateName, this.customComponentNames, this.customComponentData, this.componentProperies, diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts index a300c3e4f52e..4dee778d4e72 100644 --- a/packages/taro-transformer-wx/src/render.ts +++ b/packages/taro-transformer-wx/src/render.ts @@ -120,7 +120,6 @@ export class RenderParser { private referencedIdentifiers: Set private renderScope: Scope private usedState: Set - private loopStateName: Map, string> private customComponentData: Array private componentProperies: Set private loopRefs: Map @@ -1131,7 +1130,6 @@ export class RenderParser { initState: Set, referencedIdentifiers: Set, usedState: Set, - loopStateName: Map, string>, customComponentNames: Set, customComponentData: Array, componentProperies: Set, @@ -1141,7 +1139,6 @@ export class RenderParser { this.methods = methods this.initState = initState this.referencedIdentifiers = referencedIdentifiers - this.loopStateName = loopStateName this.usedState = usedState this.customComponentNames = customComponentNames this.customComponentData = customComponentData @@ -1435,22 +1432,6 @@ export class RenderParser { } else { body.push(returnStatement) const stateName = 'loopArray' + loopArrayId() - this.loopStateName.forEach((newName, callExpr) => { - if (callExpr === callee) { - const classBody = this.renderPath.parent as t.ClassBody - for (const property of classBody.body) { - if (t.isClassProperty(property) && property.key.name === '$dynamicComponents') { - const objects = property.value as t.ObjectExpression - for (const objProp of objects.properties) { - if (t.isObjectProperty(objProp) && t.isIdentifier(objProp.key, { name: newName })) { - const func = objProp.value as any - func.body.body[0] = buildConstVariableDeclaration('stateName', t.stringLiteral(stateName)) - } - } - } - } - } - }) // setJSXAttr(returned, Adapter.for, t.identifier(stateName)) this.addRefIdentifier(callee, t.identifier(stateName)) // this.referencedIdentifiers.add(t.identifier(stateName)) From 8e9f171317556bf4a6d7fb884f4d4f80fae870b9 Mon Sep 17 00:00:00 2001 From: yuche Date: Tue, 25 Dec 2018 21:25:31 +0800 Subject: [PATCH 006/103] =?UTF-8?q?refactor(transformer):=20=E6=AF=8F?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E5=8C=85=E5=90=AB=20JSX=20=E7=9A=84=E7=B1=BB?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E9=83=BD=E6=9C=89=E7=8B=AC=E7=AB=8B=E7=9A=84?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=92=8C=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/class.ts | 51 +++++++++++++++------- packages/taro-transformer-wx/src/render.ts | 12 ++--- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/packages/taro-transformer-wx/src/class.ts b/packages/taro-transformer-wx/src/class.ts index f273616fb481..7a1821c69986 100644 --- a/packages/taro-transformer-wx/src/class.ts +++ b/packages/taro-transformer-wx/src/class.ts @@ -112,16 +112,15 @@ class Transformer { componentProperies: [] } private methods: ClassMethodsMap = new Map() + private renderJSX: Map> = new Map() + private refIdMap: Map, Set> = new Map() private initState: Set = new Set() - private jsxReferencedIdentifiers = new Set() private customComponents: Map = new Map() private anonymousMethod: Map = new Map() - private renderMethod: null | NodePath = null private moduleNames: string[] private classPath: NodePath private customComponentNames = new Set() private usedState = new Set() - private customComponentData: Array = [] private componentProperies: Set private sourcePath: string private refs: Ref[] = [] @@ -286,7 +285,7 @@ class Transformer { const name = node.key.name self.methods.set(name, path) if (name === 'render') { - self.renderMethod = path + self.renderJSX.set('render', path) path.traverse({ ReturnStatement (returnPath) { const arg = returnPath.node.argument @@ -300,6 +299,10 @@ class Transformer { } }) } + if (name.startsWith('render')) { + self.renderJSX.set(name, path) + self.refIdMap.set(path, new Set([])) + } if (name === 'constructor') { path.traverse({ AssignmentExpression (p) { @@ -322,12 +325,17 @@ class Transformer { } } }, - IfStatement (path) { + IfStatement: (path) => { const test = path.get('test') as NodePath const consequent = path.get('consequent') if (isContainJSXElement(consequent) && hasComplexExpression(test)) { - const scope = self.renderMethod && self.renderMethod.scope || path.scope - generateAnonymousState(scope, test, self.jsxReferencedIdentifiers, true) + this.renderJSX.forEach(method => { + const renderMethod = path.findParent(p => method === p) + if (renderMethod && renderMethod.isClassMethod()) { + const scope = renderMethod && renderMethod.scope || path.scope + generateAnonymousState(scope, test, this.refIdMap.get(renderMethod)!, true) + } + }) } }, ClassProperty (path) { @@ -348,6 +356,13 @@ class Transformer { JSXExpressionContainer (path) { const attr = path.findParent(p => p.isJSXAttribute()) as NodePath const isFunctionProp = attr && typeof attr.node.name.name === 'string' && attr.node.name.name.startsWith('on') + let renderMethod: NodePath + self.renderJSX.forEach(method => { + renderMethod = path.findParent(p => method === p) as NodePath + }) + + const jsxReferencedIdentifiers = self.refIdMap.get(renderMethod!)! + path.traverse({ MemberExpression (path) { const sibling = path.getSibling('property') @@ -364,9 +379,10 @@ class Transformer { }) const expression = path.get('expression') as NodePath - const scope = self.renderMethod && self.renderMethod.scope || path.scope + const scope = renderMethod! && renderMethod!.scope || path.scope const calleeExpr = expression.get('callee') const parentPath = path.parentPath + if ( hasComplexExpression(expression) && !isFunctionProp && @@ -375,11 +391,11 @@ class Transformer { calleeExpr.get('object').isMemberExpression() && calleeExpr.get('property').isIdentifier({ name: 'bind' })) // is not bind ) { - generateAnonymousState(scope, expression, self.jsxReferencedIdentifiers) + generateAnonymousState(scope, expression, jsxReferencedIdentifiers) } else { if (parentPath.isJSXAttribute()) { if (!(expression.isMemberExpression() || expression.isIdentifier()) && parentPath.node.name.name === 'key') { - generateAnonymousState(scope, expression, self.jsxReferencedIdentifiers) + generateAnonymousState(scope, expression, jsxReferencedIdentifiers) } } } @@ -461,7 +477,7 @@ class Transformer { if (!t.isJSXIdentifier(jsxName)) return if (expression.isJSXElement()) return if (DEFAULT_Component_SET.has(jsxName.name) || expression.isIdentifier() || expression.isMemberExpression() || expression.isLiteral() || expression.isLogicalExpression() || expression.isConditionalExpression() || key.name.startsWith('on') || expression.isCallExpression()) return - generateAnonymousState(scope, expression, self.jsxReferencedIdentifiers) + generateAnonymousState(scope, expression, jsxReferencedIdentifiers) }, JSXElement (path) { const id = path.node.openingElement.name @@ -710,19 +726,22 @@ class Transformer { } parseRender () { - if (this.renderMethod) { - this.result.template = this.result.template + if (this.renderJSX.size) { + this.renderJSX.forEach((method) => { + this.result.template = this.result.template + new RenderParser( - this.renderMethod, + method, this.methods, this.initState, - this.jsxReferencedIdentifiers, + this.refIdMap.get(method)!, this.usedState, this.customComponentNames, - this.customComponentData, this.componentProperies, this.loopRefs ).outputTemplate + }) + } else { + throw codeFrameError(this.classPath.node.loc, '没有定义 render 方法') } } diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts index 4dee778d4e72..33f5c7c59ed9 100644 --- a/packages/taro-transformer-wx/src/render.ts +++ b/packages/taro-transformer-wx/src/render.ts @@ -120,7 +120,6 @@ export class RenderParser { private referencedIdentifiers: Set private renderScope: Scope private usedState: Set - private customComponentData: Array private componentProperies: Set private loopRefs: Map @@ -1124,6 +1123,12 @@ export class RenderParser { JSXExpressionContainer: this.replaceIdWithTemplate(true) } + /** + * + * @param renderPath + * @param referencedIdentifiers + * 这三个属性是需要单独传入的 + */ constructor ( renderPath: NodePath, methods: ClassMethodsMap, @@ -1131,7 +1136,6 @@ export class RenderParser { referencedIdentifiers: Set, usedState: Set, customComponentNames: Set, - customComponentData: Array, componentProperies: Set, loopRefs: Map ) { @@ -1141,7 +1145,6 @@ export class RenderParser { this.referencedIdentifiers = referencedIdentifiers this.usedState = usedState this.customComponentNames = customComponentNames - this.customComponentData = customComponentData this.componentProperies = componentProperies this.loopRefs = loopRefs const renderBody = renderPath.get('body') @@ -1633,9 +1636,6 @@ export class RenderParser { .filter(i => !i.startsWith('$$')) .filter(i => !this.loopRefIdentifiers.has(i)) let properties = propertyKeys.map(i => t.objectProperty(t.identifier(i), t.identifier(i))) - if (this.customComponentData.length > 0) { - properties = properties.concat(this.customComponentData) - } const pendingState = t.objectExpression( properties.concat( Adapter.type === Adapters.swan && transformOptions.isRoot ? t.objectProperty( From 651143fa3b4bf09f77f78b11ca1554ce059877c7 Mon Sep 17 00:00:00 2001 From: yuche Date: Wed, 26 Dec 2018 11:38:06 +0800 Subject: [PATCH 007/103] =?UTF-8?q?refactor(transformer):=20=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=20render=20=E5=87=BD=E6=95=B0=E4=B8=8E?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E7=B1=BB=E9=9D=99=E6=80=81=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E7=9A=84=E8=81=94=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/class.ts | 7 +++--- packages/taro-transformer-wx/src/render.ts | 26 +++++++++++++++++----- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/packages/taro-transformer-wx/src/class.ts b/packages/taro-transformer-wx/src/class.ts index 7a1821c69986..a1f10bbda447 100644 --- a/packages/taro-transformer-wx/src/class.ts +++ b/packages/taro-transformer-wx/src/class.ts @@ -727,7 +727,7 @@ class Transformer { parseRender () { if (this.renderJSX.size) { - this.renderJSX.forEach((method) => { + this.renderJSX.forEach((method, methodName) => { this.result.template = this.result.template + new RenderParser( method, @@ -737,8 +737,9 @@ class Transformer { this.usedState, this.customComponentNames, this.componentProperies, - this.loopRefs - ).outputTemplate + this.loopRefs, + methodName + ).outputTemplate + '\n' }) } else { throw codeFrameError(this.classPath.node.loc, '没有定义 render 方法') diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts index 33f5c7c59ed9..50f67076f358 100644 --- a/packages/taro-transformer-wx/src/render.ts +++ b/packages/taro-transformer-wx/src/render.ts @@ -26,7 +26,7 @@ import { isContainStopPropagation, replaceJSXTextWithTextComponent } from './utils' -import { difference, get as safeGet, cloneDeep } from 'lodash' +import { difference, get as safeGet, cloneDeep, uniq } from 'lodash' import { setJSXAttr, buildBlockElement, @@ -113,6 +113,7 @@ export class RenderParser { private usedThisProperties = new Set() private incrementCalleeId = incrementId() private classComputedState = new Set() + private isDefaultRender: boolean = false private renderPath: NodePath private methods: ClassMethodsMap @@ -310,6 +311,9 @@ export class RenderParser { } setProperies () { + if (!this.isDefaultRender) { + return + } const properties: t.ObjectProperty[] = [] this.componentProperies.forEach((propName) => { properties.push( @@ -1137,7 +1141,8 @@ export class RenderParser { usedState: Set, customComponentNames: Set, componentProperies: Set, - loopRefs: Map + loopRefs: Map, + methodName: string ) { this.renderPath = renderPath this.methods = methods @@ -1149,6 +1154,7 @@ export class RenderParser { this.loopRefs = loopRefs const renderBody = renderPath.get('body') this.renderScope = renderBody.scope + this.isDefaultRender = methodName === 'render' const [, error] = renderPath.node.body.body.filter(s => t.isReturnStatement(s)) if (error) { @@ -1540,12 +1546,22 @@ export class RenderParser { setCustomEvent () { const classPath = this.renderPath.findParent(isClassDcl) as NodePath - let classProp = t.classProperty(t.identifier('$$events'), t.arrayExpression(Array.from(this.usedEvents).map(s => t.stringLiteral(s)))) as any // babel 6 typing 没有 static - classProp.static = true - classPath.node.body.body.unshift(classProp) + const eventPropName = '$$events' + const body = classPath.node.body.body.find(b => t.isClassProperty(b) && b.key.name === eventPropName) as t.ClassProperty + const usedEvents = Array.from(this.usedEvents).map(s => t.stringLiteral(s)) + if (body && t.isArrayExpression(body.value)) { + body.value = t.arrayExpression(uniq(body.value.elements.concat(usedEvents))) + } else { + let classProp = t.classProperty(t.identifier('$$events'), t.arrayExpression(usedEvents)) as any // babel 6 typing 没有 static + classProp.static = true + classPath.node.body.body.unshift(classProp) + } } setUsedState () { + if (!this.isDefaultRender) { + return + } for (const [ key, method ] of this.methods) { if (method) { if (method.isClassMethod()) { From 08a4e1b1b318e119d62d576e717414dd80ddf5ea Mon Sep 17 00:00:00 2001 From: yuche Date: Thu, 27 Dec 2018 10:43:46 +0800 Subject: [PATCH 008/103] =?UTF-8?q?refactor(transformer):=20=E7=B1=BB?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E7=BB=84=E4=BB=B6=E7=9A=84=20createData=20?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/render.ts | 81 ++++++++++++++++++++-- 1 file changed, 74 insertions(+), 7 deletions(-) diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts index 50f67076f358..caef6adf5d2b 100644 --- a/packages/taro-transformer-wx/src/render.ts +++ b/packages/taro-transformer-wx/src/render.ts @@ -114,6 +114,7 @@ export class RenderParser { private incrementCalleeId = incrementId() private classComputedState = new Set() private isDefaultRender: boolean = false + private renderArg: t.Identifier | t.ObjectPattern | null = null private renderPath: NodePath private methods: ClassMethodsMap @@ -1167,6 +1168,23 @@ export class RenderParser { if (Adapter.type === Adapters.quickapp) { renderBody.traverse(this.quickappVistor) } + + const renderMethodArgs = this.renderPath.node.params + if (!this.isDefaultRender) { + const len = renderMethodArgs.length + if (len === 0) { + // + } else if (len === 1) { + const renderArg = renderMethodArgs[0] + if (t.isRestElement(renderArg)) { + throw codeFrameError(renderMethodArgs, '类函数式组件只能传入一个参数,如果需要传入更多参数可以考虑传入一个对象。') + } + this.renderArg = renderArg as any + } else { + throw codeFrameError(renderMethodArgs, '类函数式组件只能传入一个参数,如果需要传入更多参数可以考虑传入一个对象。') + } + } + this.setOutputTemplate() this.checkDuplicateName() this.removeJSXStatement() @@ -1627,7 +1645,7 @@ export class RenderParser { } setPendingState () { - const propertyKeys = Array.from( + let propertyKeys = Array.from( new Set(Array.from(this.referencedIdentifiers) .map(i => i.name)) ) @@ -1645,12 +1663,16 @@ export class RenderParser { return !this.methods.has(i) || isGet }) .filter(i => !this.loopScopes.has(i)) - .filter(i => !this.initState.has(i)) .filter(i => !this.templates.has(i)) .filter(i => isVarName(i)) .filter(i => i !== MAP_CALL_ITERATOR && !this.reserveStateWords.has(i)) .filter(i => !i.startsWith('$$')) .filter(i => !this.loopRefIdentifiers.has(i)) + + if (this.isDefaultRender) { + propertyKeys = propertyKeys.filter(i => !this.initState.has(i)) + } + let properties = propertyKeys.map(i => t.objectProperty(t.identifier(i), t.identifier(i))) const pendingState = t.objectExpression( properties.concat( @@ -1669,15 +1691,60 @@ export class RenderParser { }) ) ) - this.renderPath.node.body.body = this.renderPath.node.body.body.concat( - buildAssignState(pendingState), - t.returnStatement( - t.memberExpression(t.thisExpression(), t.identifier('state')) + if (this.isDefaultRender) { + this.renderPath.node.body.body = this.renderPath.node.body.body.concat( + buildAssignState(pendingState), + t.returnStatement( + t.memberExpression(t.thisExpression(), t.identifier('state')) + ) ) - ) + } else { + const usedState = Array.from(this.usedThisState).map(s => t.objectProperty(t.identifier(s), t.memberExpression(t.thisExpression(), t.identifier(s)))) + if (this.renderArg) { + if (t.isIdentifier(this.renderArg)) { + const renderArgName = this.renderArg.name + const shadowArgName = this.renderPath.scope.generateUid(renderArgName) + const renderBody = this.renderPath.get('body') + renderBody.traverse({ + Scope ({ scope }) { + scope.rename(renderArgName, shadowArgName) + } + }) + this.renderPath.node.body.body.unshift( + t.expressionStatement(t.assignmentExpression('=', t.identifier(renderArgName), t.objectExpression([ + t.objectProperty( + t.identifier(shadowArgName), + t.identifier(shadowArgName) + ) + ]))) + ) + usedState.push(t.objectProperty( + t.identifier(shadowArgName), + t.identifier(shadowArgName) + )) + } else { + // TODO + // usedState.push() + } + } + this.renderPath.node.body.body.push( + t.returnStatement(t.objectExpression(pendingState.properties.concat(usedState))) + ) + + if (t.isIdentifier(this.renderPath.node.key)) { + this.renderPath.node.key.name = this.getCreateJSXMethodName(name) + } else { + throw codeFrameError(this.renderPath.node, '类函数对象必须指明函数名') + } + } } + getCreateJSXMethodName = (name: string) => `_create${name}Data` + createData () { + if (!this.isDefaultRender) { + return + } const renderBody = this.renderPath.get('body') renderBody.traverse({ ThisExpression (path) { From f4f2c387c01d898117246085bd0d09971f5cee57 Mon Sep 17 00:00:00 2001 From: yuche Date: Thu, 27 Dec 2018 11:08:40 +0800 Subject: [PATCH 009/103] =?UTF-8?q?refactor(eslint):=20=E5=8F=96=E6=B6=88?= =?UTF-8?q?=E6=8E=89=E6=97=A0=E6=B3=95=E5=9C=A8=E7=B1=BB=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E4=B8=AD=E4=BD=BF=E7=94=A8=20JSX=20=E7=9A=84=E8=A7=84=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/eslint-plugin-taro/rules/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin-taro/rules/index.js b/packages/eslint-plugin-taro/rules/index.js index 869b1a270461..edce1cbfa959 100644 --- a/packages/eslint-plugin-taro/rules/index.js +++ b/packages/eslint-plugin-taro/rules/index.js @@ -3,8 +3,8 @@ const has = require('has') const allRules = { // 'if-statement-in-map-loop': require('./if-statement-in-map-loop'), 'manipulate-jsx-as-array': require('./manipulate-jsx-as-array'), - // 'no-anonymous-function-in-props': require('./no-anonymous-function-in-props'), - 'no-jsx-in-class-method': require('./no-jsx-in-class-method'), + //'no-anonymous-function-in-props': require('./no-anonymous-function-in-props'), + // 'no-jsx-in-class-method': require('./no-jsx-in-class-method'), 'no-spread-in-props': require('./no-spread-in-props'), 'no-stateless-component': require('./no-stateless-component'), // 'jsx-handler-names': require('./jsx-handler-names'), From 3b47c9d75d630c1bd977b7397bce52c8133675ff Mon Sep 17 00:00:00 2001 From: yuche Date: Thu, 27 Dec 2018 17:00:13 +0800 Subject: [PATCH 010/103] =?UTF-8?q?feat(transformer):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=B1=BB=E5=87=BD=E6=95=B0=E5=BC=8F=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/class.ts | 38 ++++++++-- packages/taro-transformer-wx/src/constant.ts | 3 +- packages/taro-transformer-wx/src/jsx.ts | 3 +- packages/taro-transformer-wx/src/render.ts | 78 +++++++++++--------- 4 files changed, 78 insertions(+), 44 deletions(-) diff --git a/packages/taro-transformer-wx/src/class.ts b/packages/taro-transformer-wx/src/class.ts index a1f10bbda447..aa6748674c3b 100644 --- a/packages/taro-transformer-wx/src/class.ts +++ b/packages/taro-transformer-wx/src/class.ts @@ -284,8 +284,9 @@ class Transformer { if (t.isIdentifier(node.key)) { const name = node.key.name self.methods.set(name, path) - if (name === 'render') { - self.renderJSX.set('render', path) + if (name.startsWith('render')) { + self.renderJSX.set(name, path) + self.refIdMap.set(path, new Set([])) path.traverse({ ReturnStatement (returnPath) { const arg = returnPath.node.argument @@ -296,13 +297,38 @@ class Transformer { returnPath.get('argument').replaceWith(t.nullLiteral()) } } + }, + CallExpression (callPath) { + const callee = callPath.get('callee') + if (!callee.isMemberExpression()) { + return + } + const args = callPath.node.arguments + const { object, property } = callee.node + if (t.isThisExpression(object) && t.isIdentifier(property) && property.name.startsWith('render')) { + if (args.length > 1) { + // @TODO: 加入文档地址 + throw codeFrameError(args[0], '类属性函数只能传入一个参数,如果你需要传入多个参数,考虑传入一个对象并使用解构语法,参考:') + } + const name = property.name + callPath.replaceWith(t.jSXElement( + t.jSXOpeningElement(t.jSXIdentifier('Template'), [ + t.jSXAttribute(t.jSXIdentifier('is'), t.stringLiteral(name)), + t.jSXAttribute(t.jSXIdentifier('data'), t.jSXExpressionContainer( + t.callExpression(t.memberExpression( + t.thisExpression(), + t.identifier(`_create${name.slice(6)}Data`) + ), args) + )) + ]), + t.jSXClosingElement(t.jSXIdentifier('Template')), + [], + false + )) + } } }) } - if (name.startsWith('render')) { - self.renderJSX.set(name, path) - self.refIdMap.set(path, new Set([])) - } if (name === 'constructor') { path.traverse({ AssignmentExpression (p) { diff --git a/packages/taro-transformer-wx/src/constant.ts b/packages/taro-transformer-wx/src/constant.ts index b81e3e1f58b5..8b99b01e83b6 100644 --- a/packages/taro-transformer-wx/src/constant.ts +++ b/packages/taro-transformer-wx/src/constant.ts @@ -46,7 +46,8 @@ export const DEFAULT_Component_SET = new Set([ 'Ad', 'Block', 'Import', - 'OfficialAccount' + 'OfficialAccount', + 'Template' ]) export const INTERNAL_SAFE_GET = 'internal_safe_get' diff --git a/packages/taro-transformer-wx/src/jsx.ts b/packages/taro-transformer-wx/src/jsx.ts index 9e5c772d28e4..ee54c5d0a176 100644 --- a/packages/taro-transformer-wx/src/jsx.ts +++ b/packages/taro-transformer-wx/src/jsx.ts @@ -167,6 +167,7 @@ export function parseJSXElement (element: t.JSXElement): string { const componentSpecialProps = SPECIAL_COMPONENT_PROPS.get(componentName) const componentTransfromProps = TRANSFORM_COMPONENT_PROPS.get(Adapter.type) let hasElseAttr = false + const isJSXMetHod = componentName === 'Template' && attributes.some(a => a.name.name === 'is' && t.isStringLiteral(a.value) && a.value.value.startsWith('render')) attributes.forEach((a, index) => { if (a.name.name === Adapter.else && !['block', 'Block'].includes(componentName) && !isDefaultComponent) { hasElseAttr = true @@ -227,7 +228,7 @@ export function parseJSXElement (element: t.JSXElement): string { value = code } } else { - value = isBindEvent || isAlipayEvent ? code : `{{${code}}}` + value = isBindEvent || isAlipayEvent ? code : `{{${isJSXMetHod && name === 'data' ? '...' : ''}${code}}}` } } if (Adapter.type === Adapters.swan && name === Adapter.for) { diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts index caef6adf5d2b..0a89b21ff478 100644 --- a/packages/taro-transformer-wx/src/render.ts +++ b/packages/taro-transformer-wx/src/render.ts @@ -114,7 +114,8 @@ export class RenderParser { private incrementCalleeId = incrementId() private classComputedState = new Set() private isDefaultRender: boolean = false - private renderArg: t.Identifier | t.ObjectPattern | null = null + // private renderArg: t.Identifier | t.ObjectPattern | null = null + private renderMethodName: string = '' private renderPath: NodePath private methods: ClassMethodsMap @@ -1179,12 +1180,19 @@ export class RenderParser { if (t.isRestElement(renderArg)) { throw codeFrameError(renderMethodArgs, '类函数式组件只能传入一个参数,如果需要传入更多参数可以考虑传入一个对象。') } - this.renderArg = renderArg as any + // this.renderArg = renderArg as any } else { throw codeFrameError(renderMethodArgs, '类函数式组件只能传入一个参数,如果需要传入更多参数可以考虑传入一个对象。') } } + if (t.isIdentifier(this.renderPath.node.key)) { + this.renderMethodName = this.renderPath.node.key.name + this.renderPath.node.key.name = this.getCreateJSXMethodName(this.renderMethodName) + } else { + throw codeFrameError(this.renderPath.node, '类函数对象必须指明函数名') + } + this.setOutputTemplate() this.checkDuplicateName() this.removeJSXStatement() @@ -1506,6 +1514,9 @@ export class RenderParser { setOutputTemplate () { this.outputTemplate = parseJSXElement(this.finalReturnElement) + if (!this.isDefaultRender) { + this.outputTemplate = `` + } } removeJSXStatement () { @@ -1700,46 +1711,41 @@ export class RenderParser { ) } else { const usedState = Array.from(this.usedThisState).map(s => t.objectProperty(t.identifier(s), t.memberExpression(t.thisExpression(), t.identifier(s)))) - if (this.renderArg) { - if (t.isIdentifier(this.renderArg)) { - const renderArgName = this.renderArg.name - const shadowArgName = this.renderPath.scope.generateUid(renderArgName) - const renderBody = this.renderPath.get('body') - renderBody.traverse({ - Scope ({ scope }) { - scope.rename(renderArgName, shadowArgName) - } - }) - this.renderPath.node.body.body.unshift( - t.expressionStatement(t.assignmentExpression('=', t.identifier(renderArgName), t.objectExpression([ - t.objectProperty( - t.identifier(shadowArgName), - t.identifier(shadowArgName) - ) - ]))) - ) - usedState.push(t.objectProperty( - t.identifier(shadowArgName), - t.identifier(shadowArgName) - )) - } else { - // TODO - // usedState.push() - } - } + // if (this.renderArg) { + // if (t.isIdentifier(this.renderArg)) { + // const renderArgName = this.renderArg.name + // const shadowArgName = this.renderPath.scope.generateUid(renderArgName) + // const renderBody = this.renderPath.get('body') + // renderBody.traverse({ + // Scope ({ scope }) { + // scope.rename(renderArgName, shadowArgName) + // } + // }) + // this.renderPath.node.body.body.unshift( + // // t.expressionStatement(t.assignmentExpression('=', t.identifier(renderArgName), t.objectExpression([ + // // t.objectProperty( + // // t.identifier(shadowArgName), + // // t.identifier(shadowArgName) + // // ) + // // ]))) + // buildConstVariableDeclaration(shadowArgName, t.identifier(renderArgName)) + // ) + // usedState.push(t.objectProperty( + // t.identifier(shadowArgName), + // t.identifier(shadowArgName) + // )) + // } else { + // // TODO + // // usedState.push() + // } + // } this.renderPath.node.body.body.push( t.returnStatement(t.objectExpression(pendingState.properties.concat(usedState))) ) - - if (t.isIdentifier(this.renderPath.node.key)) { - this.renderPath.node.key.name = this.getCreateJSXMethodName(name) - } else { - throw codeFrameError(this.renderPath.node, '类函数对象必须指明函数名') - } } } - getCreateJSXMethodName = (name: string) => `_create${name}Data` + getCreateJSXMethodName = (name: string) => `_create${name.slice(6)}Data` createData () { if (!this.isDefaultRender) { From 8845343ae4bf36eb98f491bc3ffc02112ee258c4 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Wed, 2 Jan 2019 00:33:03 +0800 Subject: [PATCH 011/103] =?UTF-8?q?feat(cli):=20=E4=BD=BF=E7=94=A8=20types?= =?UTF-8?q?cript=20=E9=87=8D=E6=9E=84=20cli=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/bin/taro | 2 +- packages/taro-cli/bin/taro-build | 4 +- packages/taro-cli/bin/taro-convert | 2 +- packages/taro-cli/bin/taro-doctor | 4 +- packages/taro-cli/bin/taro-info | 4 +- packages/taro-cli/bin/taro-init | 4 +- packages/taro-cli/bin/taro-update | 9 +- packages/taro-cli/global.d.ts | 4 + packages/taro-cli/package.json | 32 +- packages/taro-cli/src/build.js | 90 - packages/taro-cli/src/build.ts | 89 + .../src/config/{babel.js => babel.ts} | 10 +- .../src/config/{babylon.js => babylon.ts} | 2 +- .../{browser_list.js => browser_list.ts} | 2 +- .../src/config/{index.js => index.ts} | 2 +- packages/taro-cli/src/config/uglify.js | 3 - packages/taro-cli/src/config/uglify.ts | 1 + packages/taro-cli/src/convertor/helper.ts | 66 + .../src/{convertor.js => convertor/index.ts} | 289 +-- packages/taro-cli/src/creator.js | 86 - packages/taro-cli/src/creator.ts | 118 + .../{configSchema.js => configSchema.ts} | 4 +- ...{configValidator.js => configValidator.ts} | 15 +- ...{eslintValidator.js => eslintValidator.ts} | 11 +- .../src/doctor/{index.js => index.ts} | 2 +- packages/taro-cli/src/doctor/interface.ts | 5 + .../src/doctor/{joi2desc.js => joi2desc.ts} | 2 +- ...ackageValidator.js => packageValidator.ts} | 18 +- ...mandValidator.js => recommandValidator.ts} | 14 +- ...idatorEslintrc.js => validatorEslintrc.ts} | 2 +- packages/taro-cli/src/extra/util_wxs | 11 - packages/taro-cli/src/{h5.js => h5.ts} | 162 +- packages/taro-cli/src/mini/astProcess.ts | 886 +++++++ packages/taro-cli/src/mini/compileScript.ts | 146 ++ packages/taro-cli/src/mini/compileStyle.ts | 241 ++ packages/taro-cli/src/mini/component.ts | 327 +++ packages/taro-cli/src/mini/constants.ts | 18 + packages/taro-cli/src/mini/copy.ts | 20 + packages/taro-cli/src/mini/entry.ts | 179 ++ packages/taro-cli/src/mini/helper.ts | 326 +++ packages/taro-cli/src/mini/index.ts | 151 ++ packages/taro-cli/src/mini/interface.ts | 29 + packages/taro-cli/src/mini/native.ts | 106 + packages/taro-cli/src/mini/npmExact.ts | 69 + packages/taro-cli/src/mini/page.ts | 218 ++ packages/taro-cli/src/mini/watch.ts | 202 ++ .../taro-cli/src/{project.js => project.ts} | 47 +- packages/taro-cli/src/{rn.js => rn.ts} | 94 +- .../{ColorPropType.js => ColorPropType.ts} | 4 +- ...{ImageResizeMode.js => ImageResizeMode.ts} | 6 +- ...ylePropTypes.js => ImageStylePropTypes.ts} | 14 +- ...{LayoutPropTypes.js => LayoutPropTypes.ts} | 6 +- ...wPropTypesIOS.js => ShadowPropTypesIOS.ts} | 8 +- ...tValidation.js => StyleSheetValidation.ts} | 14 +- ...tylePropTypes.js => TextStylePropTypes.ts} | 8 +- ...formPropTypes.js => TransformPropTypes.ts} | 6 +- ...tylePropTypes.js => ViewStylePropTypes.ts} | 12 +- ...catedPropType.js => deprecatedPropType.ts} | 6 +- packages/taro-cli/src/rn/StyleSheet/index.js | 3 - packages/taro-cli/src/rn/StyleSheet/index.ts | 5 + .../{normalizeColor.js => normalizeColor.ts} | 5 +- .../rn/{styleProcess.js => styleProcess.ts} | 40 +- .../src/rn/{transformJS.js => transformJS.ts} | 121 +- packages/taro-cli/src/{ui.js => ui.ts} | 84 +- .../util/{ast_convert.js => astConvert.ts} | 38 +- packages/taro-cli/src/util/constants.ts | 254 ++ packages/taro-cli/src/util/index.js | 602 ----- packages/taro-cli/src/util/index.ts | 390 +++ packages/taro-cli/src/util/{npm.js => npm.ts} | 60 +- ...olve_npm_files.js => resolve_npm_files.ts} | 145 +- packages/taro-cli/src/util/types.ts | 180 ++ packages/taro-cli/src/weapp.js | 2218 ----------------- packages/taro-cli/tsconfig.json | 26 + packages/taro-cli/tslint.json | 31 + packages/taro/types/index.d.ts | 5 +- 75 files changed, 4789 insertions(+), 3630 deletions(-) create mode 100644 packages/taro-cli/global.d.ts delete mode 100644 packages/taro-cli/src/build.js create mode 100644 packages/taro-cli/src/build.ts rename packages/taro-cli/src/config/{babel.js => babel.ts} (57%) rename packages/taro-cli/src/config/{babylon.js => babylon.ts} (93%) rename packages/taro-cli/src/config/{browser_list.js => browser_list.ts} (74%) rename packages/taro-cli/src/config/{index.js => index.ts} (83%) delete mode 100644 packages/taro-cli/src/config/uglify.js create mode 100644 packages/taro-cli/src/config/uglify.ts create mode 100644 packages/taro-cli/src/convertor/helper.ts rename packages/taro-cli/src/{convertor.js => convertor/index.ts} (74%) delete mode 100644 packages/taro-cli/src/creator.js create mode 100644 packages/taro-cli/src/creator.ts rename packages/taro-cli/src/doctor/{configSchema.js => configSchema.ts} (98%) rename packages/taro-cli/src/doctor/{configValidator.js => configValidator.ts} (70%) rename packages/taro-cli/src/doctor/{eslintValidator.js => eslintValidator.ts} (78%) rename packages/taro-cli/src/doctor/{index.js => index.ts} (89%) create mode 100644 packages/taro-cli/src/doctor/interface.ts rename packages/taro-cli/src/doctor/{joi2desc.js => joi2desc.ts} (98%) rename packages/taro-cli/src/doctor/{packageValidator.js => packageValidator.ts} (81%) rename packages/taro-cli/src/doctor/{recommandValidator.js => recommandValidator.ts} (92%) rename packages/taro-cli/src/doctor/{validatorEslintrc.js => validatorEslintrc.ts} (92%) delete mode 100644 packages/taro-cli/src/extra/util_wxs rename packages/taro-cli/src/{h5.js => h5.ts} (87%) create mode 100644 packages/taro-cli/src/mini/astProcess.ts create mode 100644 packages/taro-cli/src/mini/compileScript.ts create mode 100644 packages/taro-cli/src/mini/compileStyle.ts create mode 100644 packages/taro-cli/src/mini/component.ts create mode 100644 packages/taro-cli/src/mini/constants.ts create mode 100644 packages/taro-cli/src/mini/copy.ts create mode 100644 packages/taro-cli/src/mini/entry.ts create mode 100644 packages/taro-cli/src/mini/helper.ts create mode 100644 packages/taro-cli/src/mini/index.ts create mode 100644 packages/taro-cli/src/mini/interface.ts create mode 100644 packages/taro-cli/src/mini/native.ts create mode 100644 packages/taro-cli/src/mini/npmExact.ts create mode 100644 packages/taro-cli/src/mini/page.ts create mode 100644 packages/taro-cli/src/mini/watch.ts rename packages/taro-cli/src/{project.js => project.ts} (83%) rename packages/taro-cli/src/{rn.js => rn.ts} (71%) rename packages/taro-cli/src/rn/StyleSheet/{ColorPropType.js => ColorPropType.ts} (95%) rename packages/taro-cli/src/rn/StyleSheet/{ImageResizeMode.js => ImageResizeMode.ts} (93%) rename packages/taro-cli/src/rn/StyleSheet/{ImageStylePropTypes.js => ImageStylePropTypes.ts} (82%) rename packages/taro-cli/src/rn/StyleSheet/{LayoutPropTypes.js => LayoutPropTypes.ts} (99%) rename packages/taro-cli/src/rn/StyleSheet/{ShadowPropTypesIOS.js => ShadowPropTypesIOS.ts} (89%) rename packages/taro-cli/src/rn/StyleSheet/{StyleSheetValidation.js => StyleSheetValidation.ts} (84%) rename packages/taro-cli/src/rn/StyleSheet/{TextStylePropTypes.js => TextStylePropTypes.ts} (93%) rename packages/taro-cli/src/rn/StyleSheet/{TransformPropTypes.js => TransformPropTypes.ts} (95%) rename packages/taro-cli/src/rn/StyleSheet/{ViewStylePropTypes.js => ViewStylePropTypes.ts} (86%) rename packages/taro-cli/src/rn/StyleSheet/{deprecatedPropType.js => deprecatedPropType.ts} (90%) delete mode 100644 packages/taro-cli/src/rn/StyleSheet/index.js create mode 100644 packages/taro-cli/src/rn/StyleSheet/index.ts rename packages/taro-cli/src/rn/StyleSheet/{normalizeColor.js => normalizeColor.ts} (99%) rename packages/taro-cli/src/rn/{styleProcess.js => styleProcess.ts} (69%) rename packages/taro-cli/src/rn/{transformJS.js => transformJS.ts} (81%) rename packages/taro-cli/src/{ui.js => ui.ts} (87%) rename packages/taro-cli/src/util/{ast_convert.js => astConvert.ts} (64%) create mode 100644 packages/taro-cli/src/util/constants.ts delete mode 100644 packages/taro-cli/src/util/index.js create mode 100644 packages/taro-cli/src/util/index.ts rename packages/taro-cli/src/util/{npm.js => npm.ts} (71%) rename packages/taro-cli/src/util/{resolve_npm_files.js => resolve_npm_files.ts} (70%) create mode 100644 packages/taro-cli/src/util/types.ts delete mode 100644 packages/taro-cli/src/weapp.js create mode 100644 packages/taro-cli/tsconfig.json create mode 100644 packages/taro-cli/tslint.json diff --git a/packages/taro-cli/bin/taro b/packages/taro-cli/bin/taro index e4117d5ee517..8f66b31d26b0 100755 --- a/packages/taro-cli/bin/taro +++ b/packages/taro-cli/bin/taro @@ -1,7 +1,7 @@ #! /usr/bin/env node const program = require('commander') -const { getPkgVersion, printPkgVersion } = require('../src/util') +const { getPkgVersion, printPkgVersion } = require('../dist/util') printPkgVersion() diff --git a/packages/taro-cli/bin/taro-build b/packages/taro-cli/bin/taro-build index 124553abd985..3c141de6cfa3 100755 --- a/packages/taro-cli/bin/taro-build +++ b/packages/taro-cli/bin/taro-build @@ -5,8 +5,8 @@ const program = require('commander') const chalk = require('chalk') const _ = require('lodash') -const build = require('../src/build') -const { PROJECT_CONFIG } = require('../src/util') +const build = require('../dist/build').default +const { PROJECT_CONFIG } = require('../dist/util/constants') const projectConfPath = path.join(process.cwd(), PROJECT_CONFIG) program diff --git a/packages/taro-cli/bin/taro-convert b/packages/taro-cli/bin/taro-convert index 28bba8f4f202..aac8fd0c6410 100755 --- a/packages/taro-cli/bin/taro-convert +++ b/packages/taro-cli/bin/taro-convert @@ -2,7 +2,7 @@ const program = require('commander') -const Convertor = require('../src/convertor') +const Convertor = require('../dist/convertor') program .parse(process.argv) diff --git a/packages/taro-cli/bin/taro-doctor b/packages/taro-cli/bin/taro-doctor index 771a7d6e0293..a0b60c550d83 100755 --- a/packages/taro-cli/bin/taro-doctor +++ b/packages/taro-cli/bin/taro-doctor @@ -6,7 +6,7 @@ const _ = require('lodash/fp') const ora = require('ora') const chalk = require('chalk') const fs = require('fs-extra') -const { PROJECT_CONFIG } = require('../src/util') +const { PROJECT_CONFIG } = require('../dist/util') const PROJECT_CONF_PATH = path.join(process.cwd(), PROJECT_CONFIG) if (!fs.existsSync(PROJECT_CONF_PATH)) { @@ -14,7 +14,7 @@ if (!fs.existsSync(PROJECT_CONF_PATH)) { process.exit(1) } -const { validators } = require('../src/doctor') +const { validators } = require('../dist/doctor') const NOTE_ALL_RIGHT = chalk.green('[✓] ') const NOTE_VALID = chalk.yellow('[!] ') diff --git a/packages/taro-cli/bin/taro-info b/packages/taro-cli/bin/taro-info index 8bc584716487..67c9477b15af 100755 --- a/packages/taro-cli/bin/taro-info +++ b/packages/taro-cli/bin/taro-info @@ -2,7 +2,7 @@ const fs = require('fs') const path = require('path') const envinfo = require('envinfo') -const {getPkgVersion, UPDATE_PACKAGE_LIST} = require('../src/util') +const { getPkgVersion, UPDATE_PACKAGE_LIST } = require('../dist/util') const process = require('process') const program = require('commander') @@ -37,7 +37,7 @@ function rnInfo (options) { } async function info (options) { - let info = await envinfo.run( + const info = await envinfo.run( { System: ['OS', 'Shell'], Binaries: ['Node', 'Yarn', 'npm'], diff --git a/packages/taro-cli/bin/taro-init b/packages/taro-cli/bin/taro-init index 16af1599e760..1e71db5db137 100755 --- a/packages/taro-cli/bin/taro-init +++ b/packages/taro-cli/bin/taro-init @@ -2,7 +2,7 @@ const program = require('commander') -const Project = require('../src/project') +const Project = require('../dist/project').default program .option('--name [name]', '项目名称') @@ -15,7 +15,7 @@ program const args = program.args const { template, description, name, css } = program -let typescript = '' +let typescript = false /** * 非标准做法 diff --git a/packages/taro-cli/bin/taro-update b/packages/taro-cli/bin/taro-update index 157aeb2a8c8a..475119914d96 100755 --- a/packages/taro-cli/bin/taro-update +++ b/packages/taro-cli/bin/taro-update @@ -3,14 +3,13 @@ const path = require('path') const fs = require('fs-extra') const program = require('commander') const chalk = require('chalk') -const { getPkgItemByKey } = require('../src/util') +const { getPkgItemByKey, shouldUseYarn, shouldUseCnpm } = require('../dist/util') const ora = require('ora') const exec = require('child_process').exec const getLatestVersion = require('latest-version') -const { PROJECT_CONFIG, UPDATE_PACKAGE_LIST} = require('../src/util') +const { PROJECT_CONFIG, UPDATE_PACKAGE_LIST } = require('../dist/util/constants') const projectConfPath = path.join(process.cwd(), PROJECT_CONFIG) const pkgPath = path.join(process.cwd(), 'package.json') -const { shouldUseYarn, shouldUseCnpm } = require('../src/util') const pkgName = getPkgItemByKey('name') @@ -50,7 +49,7 @@ function updateSelf () { command = 'npm i -g @tarojs/cli@latest' } - let child = exec(command) + const child = exec(command) const spinner = ora('即将将 Taro 开发工具 taro-cli 更新到最新版本...').start() @@ -103,7 +102,7 @@ async function updateProject () { command = 'npm install' } - let child = exec(command) + const child = exec(command) const spinner = ora('即将将项目所有 Taro 相关依赖更新到最新版本...').start() diff --git a/packages/taro-cli/global.d.ts b/packages/taro-cli/global.d.ts new file mode 100644 index 000000000000..6568666452a0 --- /dev/null +++ b/packages/taro-cli/global.d.ts @@ -0,0 +1,4 @@ +declare module '*.json' { + const value: any + export default value +} diff --git a/packages/taro-cli/package.json b/packages/taro-cli/package.json index c6bbdf283266..ff14d93e8e70 100644 --- a/packages/taro-cli/package.json +++ b/packages/taro-cli/package.json @@ -4,7 +4,14 @@ "description": "cli tool for taro", "main": "index.js", "scripts": { - "test": "jest" + "test": "jest", + "build": "run-s clean prod", + "dev": "tsc -w", + "prod": "tsc", + "clean": "rimraf dist", + "lint": "tslint src/**/*.ts --fix", + "lint:typecheck": "tslint -p tsconfig.json src/**/*.ts --fix", + "prepack": "npm run build" }, "repository": { "type": "git", @@ -27,6 +34,7 @@ "@tarojs/transformer-wx": "1.2.13", "autoprefixer": "^8.4.1", "babel-core": "^6.26.3", + "babel-eslint": "^8.2.3", "babel-generator": "^6.26.1", "babel-plugin-danger-remove-unused-import": "^1.1.1", "babel-plugin-remove-dead-code": "^1.3.2", @@ -46,12 +54,11 @@ "css-to-react-native-transform": "^1.4.0", "ejs": "^2.6.1", "envinfo": "^6.0.1", - "babel-eslint": "^8.2.3", "eslint": "^4.15.0", "eslint-config-taro": "^1.1.4", - "eslint-plugin-taro": "^1.1.4", "eslint-plugin-import": "^2.8.0", "eslint-plugin-react": "^7.4.0", + "eslint-plugin-taro": "^1.1.4", "eslint-plugin-typescript": "^0.12.0", "fs-extra": "^5.0.0", "generic-names": "^2.0.1", @@ -75,7 +82,7 @@ "postcss-pxtransform": "1.2.13", "postcss-taro-unit-transform": "1.2.13", "postcss-url": "^7.3.2", - "prettier": "^1.14.3", + "prettier": "^1.15.3", "prop-types": "^15.6.2", "resolve": "^1.6.0", "semver": "^5.5.0", @@ -85,6 +92,16 @@ "vinyl-fs": "^3.0.2" }, "devDependencies": { + "@types/autoprefixer": "^9.1.1", + "@tarojs/taro": "^1.2.2", + "@types/babel-core": "^6.25.5", + "@types/babel-generator": "^6.25.2", + "@types/babel-traverse": "^6.25.4", + "@types/babel-types": "^6.25.2", + "@types/fs-extra": "^5.0.4", + "@types/jest": "^23.3.10", + "@types/lodash": "^4.14.119", + "@types/node": "^10.12.18", "babel-jest": "^23.6.0", "babel-plugin-transform-class-properties": "^6.24.1", "babel-preset-env": "^1.7.0", @@ -92,6 +109,11 @@ "babel-preset-stage-0": "^6.24.1", "jest": "^23.6.0", "jest-react-native": "^18.0.0", - "react-native": "^0.55.4" + "npm-run-all": "^4.1.5", + "react-native": "^0.55.4", + "tslint": "^5.12.0", + "tslint-config-prettier": "^1.17.0", + "tslint-config-standard": "^8.0.1", + "typescript": "^3.2.2" } } diff --git a/packages/taro-cli/src/build.js b/packages/taro-cli/src/build.js deleted file mode 100644 index f2af9fb15762..000000000000 --- a/packages/taro-cli/src/build.js +++ /dev/null @@ -1,90 +0,0 @@ -const fs = require('fs-extra') -const path = require('path') -const chalk = require('chalk') -const _ = require('lodash') - -const Util = require('./util') -const CONFIG = require('./config') - -const appPath = process.cwd() - - -function build (args, buildConfig) { - const { type, watch } = buildConfig - const configDir = require(path.join(appPath, Util.PROJECT_CONFIG))(_.merge) - const outputPath = path.join(appPath, configDir.outputRoot || CONFIG.OUTPUT_DIR) - if (!fs.existsSync(outputPath)) { - fs.mkdirSync(outputPath) - } else { - if (type !== Util.BUILD_TYPES.H5) { - Util.emptyDirectory(outputPath) - } - } - switch (type) { - case Util.BUILD_TYPES.H5: - buildForH5({ watch }) - break - case Util.BUILD_TYPES.WEAPP: - buildForWeapp({ watch }) - break - case Util.BUILD_TYPES.SWAN: - buildForSwan({ watch }) - break - case Util.BUILD_TYPES.ALIPAY: - buildForAlipay({ watch }) - break - case Util.BUILD_TYPES.TT: - buildForTt({ watch }) - break - case Util.BUILD_TYPES.RN: - buildForRN({ watch }) - break - case Util.BUILD_TYPES.UI: - buildForUILibrary({ watch }) - break - default: - console.log(chalk.red('输入类型错误,目前只支持 weapp/h5/rn/swan/alipay/tt 六端类型')) - } -} - -function buildForWeapp ({ watch }) { - require('./weapp').build({ - watch, - adapter: Util.BUILD_TYPES.WEAPP - }) -} - -function buildForSwan ({ watch }) { - require('./weapp').build({ - watch, - adapter: Util.BUILD_TYPES.SWAN - }) -} - -function buildForAlipay ({ watch }) { - require('./weapp').build({ - watch, - adapter: Util.BUILD_TYPES.ALIPAY - }) -} - -function buildForTt ({ watch }) { - require('./weapp').build({ - watch, - adapter: Util.BUILD_TYPES.TT - }) -} - -function buildForH5 (buildConfig) { - require('./h5').build(buildConfig) -} - -function buildForRN ({ watch }) { - require('./rn').build({ watch }) -} - -function buildForUILibrary ({ watch }) { - require('./ui').build({ watch }) -} - -module.exports = build diff --git a/packages/taro-cli/src/build.ts b/packages/taro-cli/src/build.ts new file mode 100644 index 000000000000..27d34773fafd --- /dev/null +++ b/packages/taro-cli/src/build.ts @@ -0,0 +1,89 @@ +import * as path from 'path' +import * as fs from 'fs-extra' +import chalk from 'chalk' +import * as _ from 'lodash' + +import * as Util from './util' +import CONFIG from './config' +import { BUILD_TYPES, PROJECT_CONFIG } from './util/constants' +import { IBuildConfig } from './util/types' + +const appPath = process.cwd() + +export default function build (args, buildConfig: IBuildConfig) { + const { type, watch } = buildConfig + const configDir = require(path.join(appPath, PROJECT_CONFIG))(_.merge) + const outputPath = path.join(appPath, configDir.outputRoot || CONFIG.OUTPUT_DIR) + if (!fs.existsSync(outputPath)) { + fs.mkdirSync(outputPath) + } else { + if (type !== BUILD_TYPES.H5) { + Util.emptyDirectory(outputPath) + } + } + switch (type) { + case BUILD_TYPES.H5: + buildForH5({ watch }) + break + case BUILD_TYPES.WEAPP: + buildForWeapp({ watch }) + break + case BUILD_TYPES.SWAN: + buildForSwan({ watch }) + break + case BUILD_TYPES.ALIPAY: + buildForAlipay({ watch }) + break + case BUILD_TYPES.TT: + buildForTt({ watch }) + break + case BUILD_TYPES.RN: + buildForRN({ watch }) + break + case BUILD_TYPES.UI: + buildForUILibrary({ watch }) + break + default: + console.log(chalk.red('输入类型错误,目前只支持 weapp/h5/rn/swan/alipay/tt 六端类型')) + } +} + +function buildForWeapp ({ watch }: IBuildConfig) { + require('./mini').build({ + watch, + adapter: BUILD_TYPES.WEAPP + }) +} + +function buildForSwan ({ watch }: IBuildConfig) { + require('./mini').build({ + watch, + adapter: BUILD_TYPES.SWAN + }) +} + +function buildForAlipay ({ watch }: IBuildConfig) { + require('./mini').build({ + watch, + adapter: BUILD_TYPES.ALIPAY + }) +} + +function buildForTt ({ watch }: IBuildConfig) { + require('./mini').build({ + watch, + adapter: BUILD_TYPES.TT + }) +} + +function buildForH5 (buildConfig: IBuildConfig) { + require('./h5').build(buildConfig) +} + +function buildForRN ({ watch }: IBuildConfig) { + require('./rn').build({ watch }) +} + +function buildForUILibrary ({ watch }: IBuildConfig) { + require('./ui').build({ watch }) +} diff --git a/packages/taro-cli/src/config/babel.js b/packages/taro-cli/src/config/babel.ts similarity index 57% rename from packages/taro-cli/src/config/babel.js rename to packages/taro-cli/src/config/babel.ts index 3b2e56859fb0..aba848350e57 100644 --- a/packages/taro-cli/src/config/babel.js +++ b/packages/taro-cli/src/config/babel.ts @@ -1,4 +1,4 @@ -module.exports = { +const babelOptions: IBabelOptions = { sourceMap: true, presets: [ 'env' @@ -10,3 +10,11 @@ module.exports = { 'transform-object-rest-spread' ] } + +export default babelOptions + +export interface IBabelOptions { + sourceMap: boolean, + presets: string[], + plugins: any[] +} diff --git a/packages/taro-cli/src/config/babylon.js b/packages/taro-cli/src/config/babylon.ts similarity index 93% rename from packages/taro-cli/src/config/babylon.js rename to packages/taro-cli/src/config/babylon.ts index 015dd1180141..1c1e778de91d 100644 --- a/packages/taro-cli/src/config/babylon.js +++ b/packages/taro-cli/src/config/babylon.ts @@ -1,4 +1,4 @@ -module.exports = { +export default { sourceType: 'module', plugins: [ 'typescript', diff --git a/packages/taro-cli/src/config/browser_list.js b/packages/taro-cli/src/config/browser_list.ts similarity index 74% rename from packages/taro-cli/src/config/browser_list.js rename to packages/taro-cli/src/config/browser_list.ts index afdd1afc81e4..cf45da8e1957 100644 --- a/packages/taro-cli/src/config/browser_list.js +++ b/packages/taro-cli/src/config/browser_list.ts @@ -1,4 +1,4 @@ -module.exports = [ +export default [ 'last 3 versions', 'Android >= 4.1', 'ios >= 8' diff --git a/packages/taro-cli/src/config/index.js b/packages/taro-cli/src/config/index.ts similarity index 83% rename from packages/taro-cli/src/config/index.js rename to packages/taro-cli/src/config/index.ts index e341dd8e7666..677c1b768226 100644 --- a/packages/taro-cli/src/config/index.js +++ b/packages/taro-cli/src/config/index.ts @@ -1,4 +1,4 @@ -module.exports = { +export default { OUTPUT_DIR: 'dist', SOURCE_DIR: 'src', TEMP_DIR: '.temp', diff --git a/packages/taro-cli/src/config/uglify.js b/packages/taro-cli/src/config/uglify.js deleted file mode 100644 index 7acaac2b6a15..000000000000 --- a/packages/taro-cli/src/config/uglify.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - -} diff --git a/packages/taro-cli/src/config/uglify.ts b/packages/taro-cli/src/config/uglify.ts new file mode 100644 index 000000000000..43ea6b431bb8 --- /dev/null +++ b/packages/taro-cli/src/config/uglify.ts @@ -0,0 +1 @@ +export default { } diff --git a/packages/taro-cli/src/convertor/helper.ts b/packages/taro-cli/src/convertor/helper.ts new file mode 100644 index 000000000000..542d4dbc7820 --- /dev/null +++ b/packages/taro-cli/src/convertor/helper.ts @@ -0,0 +1,66 @@ +import path from 'path' +import fs from 'fs-extra' +import * as t from 'babel-types' + +import { + printLog, + promoteRelativePath, + resolveScriptPath +} from '../util' + +import { + processTypeEnum, + REG_SCRIPT, + REG_TYPESCRIPT +} from '../util/constants' + +export function analyzeImportUrl ( + sourceFilePath: string, + scriptFiles: Set, + source: t.StringLiteral, + value: string +) { + const valueExtname = path.extname(value) + if (path.isAbsolute(value)) { + printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 是绝对路径!`) + return + } + if (value.indexOf('.') === 0) { + if (REG_SCRIPT.test(valueExtname) || REG_TYPESCRIPT.test(valueExtname)) { + const vpath = path.resolve(sourceFilePath, '..', value) + let fPath = value + if (fs.existsSync(vpath)) { + fPath = vpath + } else { + printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 不存在!`) + } + scriptFiles.add(fPath) + } else { + let vpath = resolveScriptPath(path.resolve(sourceFilePath, '..', value)) + if (vpath) { + if (!fs.existsSync(vpath)) { + printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 不存在!`) + } else { + if (fs.lstatSync(vpath).isDirectory()) { + if (fs.existsSync(path.join(vpath, 'index.js'))) { + vpath = path.join(vpath, 'index.js') + } else { + printLog(processTypeEnum.ERROR, '引用目录', `文件 ${sourceFilePath} 中引用了目录 ${value}!`) + return + } + } + let relativePath = path.relative(sourceFilePath, vpath) + const relativePathExtname = path.extname(relativePath) + scriptFiles.add(vpath) + relativePath = promoteRelativePath(relativePath) + if (/\.wxs/.test(relativePathExtname)) { + relativePath += '.js' + } else { + relativePath = relativePath.replace(relativePathExtname, '.js') + } + source.value = relativePath + } + } + } + } +} diff --git a/packages/taro-cli/src/convertor.js b/packages/taro-cli/src/convertor/index.ts similarity index 74% rename from packages/taro-cli/src/convertor.js rename to packages/taro-cli/src/convertor/index.ts index 258751e26ea8..ff8ead65a194 100644 --- a/packages/taro-cli/src/convertor.js +++ b/packages/taro-cli/src/convertor/index.ts @@ -1,39 +1,43 @@ -const fs = require('fs-extra') -const path = require('path') - -const chalk = require('chalk') -const prettier = require('prettier') -const traverse = require('babel-traverse').default -const t = require('babel-types') -const template = require('babel-template') -const taroize = require('@tarojs/taroize') -const wxTransformer = require('@tarojs/transformer-wx') -const postcss = require('postcss') -const unitTransform = require('postcss-taro-unit-transform') - -const { - BUILD_TYPES, - MINI_APP_FILES, +import * as fs from 'fs-extra' +import * as path from 'path' + +import { AppConfig, TabBar } from '@tarojs/taro' +import chalk from 'chalk' +import * as prettier from 'prettier' +import traverse, { NodePath } from 'babel-traverse' +import * as t from 'babel-types' +import * as taroize from '@tarojs/taroize' +import * as wxTransformer from '@tarojs/transformer-wx' +import * as postcss from 'postcss' +import * as unitTransform from 'postcss-taro-unit-transform' + +import { printLog, - pocessTypeEnum, promoteRelativePath, resolveScriptPath, - REG_SCRIPT, - REG_TYPESCRIPT, processStyleImports, getPkgVersion, pascalCase, - emptyDirectory, + emptyDirectory +} from '../util' +import { + BUILD_TYPES, + MINI_APP_FILES, + processTypeEnum, + REG_TYPESCRIPT, REG_URL, - REG_IMAGE -} = require('./util') - -const { generateMinimalEscapeCode } = require('./util/ast_convert') + REG_IMAGE, + IMINI_APP_FILE_TYPE +} from '../util/constants' +import { generateMinimalEscapeCode } from '../util/astConvert' +import Creator from '../creator' +import babylonConfig from '../config/babylon' +import { IPrettierConfig } from '../util/types' +import { analyzeImportUrl } from './helper' -const Creator = require('./creator') -const babylonConfig = require('./config/babylon') +const template = require('babel-template') -const prettierJSConfig = { +const prettierJSConfig: IPrettierConfig = { semi: false, singleQuote: true, parser: 'babel' @@ -41,66 +45,64 @@ const prettierJSConfig = { const OUTPUT_STYLE_EXTNAME = '.scss' -const WX_GLOBAL_FN = ['getApp', 'getCurrentPages', 'requirePlugin'] +const WX_GLOBAL_FN = new Set(['getApp', 'getCurrentPages', 'requirePlugin']) -function analyzeImportUrl (sourceFilePath, scriptFiles, source, value) { - const valueExtname = path.extname(value) - if (path.isAbsolute(value)) { - printLog(pocessTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 是绝对路径!`) - return - } - if (value.indexOf('.') === 0) { - if (REG_SCRIPT.test(valueExtname) || REG_TYPESCRIPT.test(valueExtname)) { - const vpath = path.resolve(sourceFilePath, '..', value) - let fPath = value - if (fs.existsSync(vpath)) { - fPath = vpath - } else { - printLog(pocessTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 不存在!`) - } - scriptFiles.add(fPath) - } else { - let vpath = resolveScriptPath(path.resolve(sourceFilePath, '..', value)) - if (vpath) { - if (!fs.existsSync(vpath)) { - printLog(pocessTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 不存在!`) - } else { - if (fs.lstatSync(vpath).isDirectory()) { - if (fs.existsSync(path.join(vpath, 'index.js'))) { - vpath = path.join(vpath, 'index.js') - } else { - printLog(pocessTypeEnum.ERROR, '引用目录', `文件 ${sourceFilePath} 中引用了目录 ${value}!`) - return - } - } - let relativePath = path.relative(sourceFilePath, vpath) - const relativePathExtname = path.extname(relativePath) - scriptFiles.add(vpath) - relativePath = promoteRelativePath(relativePath) - if (/\.wxs/.test(relativePathExtname)) { - relativePath += '.js' - } else { - relativePath = relativePath.replace(relativePathExtname, '.js') - } - source.value = relativePath - } - } - } - } +interface IComponent { + name: string, + path: string +} + +interface IImport { + ast: t.File, + name: string, + wxs?: boolean +} + +interface IParseAstOptions { + ast: t.File, + sourceFilePath: string, + outputFilePath: string, + importStylePath?: string | null, + depComponents?: Set, + imports?: IImport[], + isApp?: boolean } -class Convertor { +interface ITaroizeOptions { + json?: string, + script?: string, + wxml?: string, + path?: string +} + +export default class Convertor { + root: string + convertRoot: string + convertDir: string + importsDir: string + fileTypes: IMINI_APP_FILE_TYPE + pages: Set + components: Set + hadBeenCopyedFiles: Set + hadBeenBuiltComponents: Set + hadBeenBuiltImports: Set + entryJSPath: string + entryJSONPath: string + entryStylePath: string + entryJSON: AppConfig + entryStyle: string + constructor () { this.root = process.cwd() this.convertRoot = path.join(this.root, 'taroConvert') this.convertDir = path.join(this.convertRoot, 'src') this.importsDir = path.join(this.convertDir, 'imports') this.fileTypes = MINI_APP_FILES[BUILD_TYPES.WEAPP] - this.pages = new Set() - this.components = new Set() - this.hadBeenCopyedFiles = new Set() - this.hadBeenBuiltComponents = new Set() - this.hadBeenBuiltImports = new Set() + this.pages = new Set() + this.components = new Set() + this.hadBeenCopyedFiles = new Set() + this.hadBeenBuiltComponents = new Set() + this.hadBeenBuiltImports = new Set() this.init() } @@ -120,10 +122,18 @@ class Convertor { } } - parseAst ({ ast, sourceFilePath, outputFilePath, importStylePath, depComponents, imports = [], isApp = false }) { - const scriptFiles = new Set() + parseAst ({ + ast, + sourceFilePath, + outputFilePath, + importStylePath, + depComponents, + imports = [], + isApp = false + }: IParseAstOptions): { ast: t.File, scriptFiles: Set } { + const scriptFiles = new Set() const self = this - let componentClassName = null + let componentClassName: string let needInsertImportTaro = false traverse(ast, { Program: { @@ -167,9 +177,9 @@ class Convertor { }) if (isTaroComponent) { if (node.id === null) { - const parentNode = astPath.parentPath.node + const parentNode = astPath.parentPath.node as t.VariableDeclarator if (t.isVariableDeclarator(astPath.parentPath)) { - componentClassName = parentNode.id.name + componentClassName = (parentNode.id as t.Identifier).name } } else { componentClassName = node.id.name @@ -216,19 +226,19 @@ class Convertor { const callee = calleePath.node if (callee.type === 'Identifier') { if (callee.name === 'require') { - const args = node.arguments + const args = node.arguments as Array const value = args[0].value analyzeImportUrl(sourceFilePath, scriptFiles, args[0], value) - } else if (WX_GLOBAL_FN.includes(callee.name)) { + } else if (WX_GLOBAL_FN.has(callee.name)) { calleePath.replaceWith( - t.memberExpression(t.identifier('Taro'), callee) + t.memberExpression(t.identifier('Taro'), callee as t.Identifier) ) needInsertImportTaro = true } } else if (callee.type === 'MemberExpression') { - const object = callee.object + const object = callee.object as t.Identifier if (object.name === 'wx') { - calleePath.get('object').replaceWith(t.identifier('Taro')) + (calleePath.get('object') as NodePath).replaceWith(t.identifier('Taro')) needInsertImportTaro = true } } @@ -236,10 +246,11 @@ class Convertor { }) }, exit (astPath) { - const lastImport = astPath.get('body').filter(p => p.isImportDeclaration()).pop() - const hasTaroImport = astPath.get('body').some(p => p.isImportDeclaration() && p.node.source.value === '@tarojs/taro') + const bodyNode = astPath.get('body') as NodePath[] + const lastImport = bodyNode.filter(p => p.isImportDeclaration()).pop() + const hasTaroImport = bodyNode.some(p => p.isImportDeclaration() && p.node.source.value === '@tarojs/taro') if (needInsertImportTaro && !hasTaroImport) { - astPath.node.body.unshift( + (astPath.node as t.Program).body.unshift( t.importDeclaration( [t.importDefaultSpecifier(t.identifier('Taro'))], t.stringLiteral('@tarojs/taro') @@ -251,9 +262,9 @@ class Convertor { const value = astPath.node.value const extname = path.extname(value) if (extname && REG_IMAGE.test(extname) && !REG_URL.test(value)) { - let imageRelativePath = null - let sourceImagePath = null - let outputImagePath = null + let imageRelativePath: string + let sourceImagePath: string + let outputImagePath: string if (path.isAbsolute(value)) { sourceImagePath = path.join(self.root, value) } else { @@ -263,9 +274,9 @@ class Convertor { outputImagePath = self.getDistFilePath(sourceImagePath) if (fs.existsSync(sourceImagePath)) { self.copyFileToTaro(sourceImagePath, outputImagePath) - printLog(pocessTypeEnum.COPY, '图片', self.generateShowPath(outputImagePath)) + printLog(processTypeEnum.COPY, '图片', self.generateShowPath(outputImagePath)) } else { - printLog(pocessTypeEnum.ERROR, '图片不存在', self.generateShowPath(sourceImagePath)) + printLog(processTypeEnum.ERROR, '图片不存在', self.generateShowPath(sourceImagePath)) } if (astPath.parentPath.isVariableDeclarator()) { astPath.replaceWith(t.callExpression(t.identifier('require'), [t.stringLiteral(imageRelativePath)])) @@ -302,7 +313,7 @@ class Convertor { } if (isApp) { - astPath.node.body.push(template(`Taro.render(, document.getElementById('app'))`, babylonConfig)()) + (astPath.node as t.Program).body.push(template(`Taro.render(, document.getElementById('app'))`, babylonConfig)()) } } } @@ -321,11 +332,11 @@ class Convertor { this.entryStylePath = path.join(this.root, `app${this.fileTypes.STYLE}`) try { this.entryJSON = JSON.parse(String(fs.readFileSync(this.entryJSONPath))) - printLog(pocessTypeEnum.CONVERT, '入口文件', this.generateShowPath(this.entryJSPath)) - printLog(pocessTypeEnum.CONVERT, '入口配置', this.generateShowPath(this.entryJSONPath)) + printLog(processTypeEnum.CONVERT, '入口文件', this.generateShowPath(this.entryJSPath)) + printLog(processTypeEnum.CONVERT, '入口配置', this.generateShowPath(this.entryJSONPath)) if (fs.existsSync(this.entryStylePath)) { this.entryStyle = String(fs.readFileSync(this.entryStylePath)) - printLog(pocessTypeEnum.CONVERT, '入口样式', this.generateShowPath(this.entryStylePath)) + printLog(processTypeEnum.CONVERT, '入口样式', this.generateShowPath(this.entryStylePath)) } } catch (err) { this.entryJSON = {} @@ -360,7 +371,7 @@ class Convertor { }) } - generateScriptFiles (files) { + generateScriptFiles (files: Set) { if (!files) { return } @@ -389,19 +400,19 @@ class Convertor { }) const jsCode = generateMinimalEscapeCode(ast) this.writeFileToTaro(outputFilePath, prettier.format(jsCode, prettierJSConfig)) - printLog(pocessTypeEnum.COPY, 'JS 文件', this.generateShowPath(outputFilePath)) + printLog(processTypeEnum.COPY, 'JS 文件', this.generateShowPath(outputFilePath)) this.hadBeenCopyedFiles.add(file) this.generateScriptFiles(scriptFiles) }) } } - writeFileToTaro (dist, code) { + writeFileToTaro (dist: string, code: string) { fs.ensureDirSync(path.dirname(dist)) fs.writeFileSync(dist, code) } - copyFileToTaro (from, to, options) { + copyFileToTaro (from: string, to: string, options?: fs.CopyOptionsSync) { const filename = path.basename(from) if (fs.statSync(from).isFile() && !path.extname(to)) { fs.ensureDir(to) @@ -411,12 +422,12 @@ class Convertor { return fs.copySync(from, to, options) } - getDistFilePath (src, extname) { + getDistFilePath (src: string, extname?: string): string { if (!extname) return src.replace(this.root, this.convertDir) return src.replace(this.root, this.convertDir).replace(path.extname(src), extname) } - generateShowPath (filePath) { + generateShowPath (filePath: string): string { return filePath.replace(path.join(this.root, '/'), '').split(path.sep).join('/') } @@ -439,7 +450,7 @@ class Convertor { }) const jsCode = generateMinimalEscapeCode(ast) this.writeFileToTaro(entryDistJSPath, prettier.format(jsCode, prettierJSConfig)) - printLog(pocessTypeEnum.GENERATE, '入口文件', this.generateShowPath(entryDistJSPath)) + printLog(processTypeEnum.GENERATE, '入口文件', this.generateShowPath(entryDistJSPath)) if (this.entryStyle) { this.traverseStyle(this.entryStylePath, this.entryStyle) } @@ -452,7 +463,7 @@ class Convertor { } } - generateTabBarIcon (tabBar) { + generateTabBarIcon (tabBar: TabBar) { const { list = [] } = tabBar const icons = new Set() if (Array.isArray(list) && list.length) { @@ -466,7 +477,7 @@ class Convertor { .forEach(iconPath => { const iconDistPath = this.getDistFilePath(iconPath) this.copyFileToTaro(iconPath, iconDistPath) - printLog(pocessTypeEnum.COPY, 'TabBar 图标', this.generateShowPath(iconDistPath)) + printLog(processTypeEnum.COPY, 'TabBar 图标', this.generateShowPath(iconDistPath)) }) } } @@ -482,15 +493,15 @@ class Convertor { const pageTemplPath = pagePath + this.fileTypes.TEMPL try { - const param = {} const depComponents = new Set() if (!fs.existsSync(pageJSPath)) { throw new Error(`页面 ${page} 没有 JS 文件!`) } - printLog(pocessTypeEnum.CONVERT, '页面文件', this.generateShowPath(pageJSPath)) + const param: ITaroizeOptions = {} + printLog(processTypeEnum.CONVERT, '页面文件', this.generateShowPath(pageJSPath)) if (fs.existsSync(pageConfigPath)) { - printLog(pocessTypeEnum.CONVERT, '页面配置', this.generateShowPath(pageConfigPath)) + printLog(processTypeEnum.CONVERT, '页面配置', this.generateShowPath(pageConfigPath)) const pageConfigStr = String(fs.readFileSync(pageConfigPath)) const pageConfig = JSON.parse(pageConfigStr) const pageUsingComponnets = pageConfig.usingComponents @@ -512,12 +523,12 @@ class Convertor { } param.script = String(fs.readFileSync(pageJSPath)) if (fs.existsSync(pageTemplPath)) { - printLog(pocessTypeEnum.CONVERT, '页面模板', this.generateShowPath(pageTemplPath)) + printLog(processTypeEnum.CONVERT, '页面模板', this.generateShowPath(pageTemplPath)) param.wxml = String(fs.readFileSync(pageTemplPath)) } - let pageStyle = null + let pageStyle: string | null = null if (fs.existsSync(pageStylePath)) { - printLog(pocessTypeEnum.CONVERT, '页面样式', this.generateShowPath(pageStylePath)) + printLog(processTypeEnum.CONVERT, '页面样式', this.generateShowPath(pageStylePath)) pageStyle = String(fs.readFileSync(pageStylePath)) } param.path = path.dirname(pageJSPath) @@ -532,20 +543,20 @@ class Convertor { }) const jsCode = generateMinimalEscapeCode(ast) this.writeFileToTaro(pageDistJSPath, prettier.format(jsCode, prettierJSConfig)) - printLog(pocessTypeEnum.GENERATE, '页面文件', this.generateShowPath(pageDistJSPath)) + printLog(processTypeEnum.GENERATE, '页面文件', this.generateShowPath(pageDistJSPath)) if (pageStyle) { this.traverseStyle(pageStylePath, pageStyle) } this.generateScriptFiles(scriptFiles) this.traverseComponents(depComponents) } catch (err) { - printLog(pocessTypeEnum.ERROR, '页面转换', this.generateShowPath(pageJSPath)) + printLog(processTypeEnum.ERROR, '页面转换', this.generateShowPath(pageJSPath)) console.log(err) } }) } - traverseComponents (components) { + traverseComponents (components: Set) { if (!components || !components.size) { return } @@ -561,14 +572,14 @@ class Convertor { const componentTemplPath = component + this.fileTypes.TEMPL try { - const param = {} + const param: ITaroizeOptions = {} const depComponents = new Set() if (!fs.existsSync(componentJSPath)) { throw new Error(`组件 ${component} 没有 JS 文件!`) } - printLog(pocessTypeEnum.CONVERT, '组件文件', this.generateShowPath(componentJSPath)) + printLog(processTypeEnum.CONVERT, '组件文件', this.generateShowPath(componentJSPath)) if (fs.existsSync(componentConfigPath)) { - printLog(pocessTypeEnum.CONVERT, '组件配置', this.generateShowPath(componentConfigPath)) + printLog(processTypeEnum.CONVERT, '组件配置', this.generateShowPath(componentConfigPath)) const componentConfigStr = String(fs.readFileSync(componentConfigPath)) const componentConfig = JSON.parse(componentConfigStr) const componentUsingComponnets = componentConfig.usingComponents @@ -590,12 +601,12 @@ class Convertor { } param.script = String(fs.readFileSync(componentJSPath)) if (fs.existsSync(componentTemplPath)) { - printLog(pocessTypeEnum.CONVERT, '组件模板', this.generateShowPath(componentTemplPath)) + printLog(processTypeEnum.CONVERT, '组件模板', this.generateShowPath(componentTemplPath)) param.wxml = String(fs.readFileSync(componentTemplPath)) } - let componentStyle = null + let componentStyle: string | null = null if (fs.existsSync(componentStylePath)) { - printLog(pocessTypeEnum.CONVERT, '组件样式', this.generateShowPath(componentStylePath)) + printLog(processTypeEnum.CONVERT, '组件样式', this.generateShowPath(componentStylePath)) componentStyle = String(fs.readFileSync(componentStylePath)) } param.path = path.dirname(componentJSPath) @@ -610,20 +621,20 @@ class Convertor { }) const jsCode = generateMinimalEscapeCode(ast) this.writeFileToTaro(componentDistJSPath, prettier.format(jsCode, prettierJSConfig)) - printLog(pocessTypeEnum.GENERATE, '组件文件', this.generateShowPath(componentDistJSPath)) + printLog(processTypeEnum.GENERATE, '组件文件', this.generateShowPath(componentDistJSPath)) if (componentStyle) { this.traverseStyle(componentStylePath, componentStyle) } this.generateScriptFiles(scriptFiles) this.traverseComponents(depComponents) } catch (err) { - printLog(pocessTypeEnum.ERROR, '组件转换', this.generateShowPath(componentJSPath)) + printLog(processTypeEnum.ERROR, '组件转换', this.generateShowPath(componentJSPath)) console.log(err) } }) } - async styleUnitTransform (filePath, content) { + async styleUnitTransform (filePath: string, content: string) { const postcssResult = await postcss([ unitTransform() ]).process(content, { @@ -632,7 +643,7 @@ class Convertor { return postcssResult } - async traverseStyle (filePath, style) { + async traverseStyle (filePath: string, style: string) { const { imports, content } = processStyleImports(style, BUILD_TYPES.WEAPP, (str, stylePath) => { let relativePath = stylePath if (path.isAbsolute(relativePath)) { @@ -644,7 +655,7 @@ class Convertor { const styleDist = this.getDistFilePath(filePath, OUTPUT_STYLE_EXTNAME) const { css } = await this.styleUnitTransform(filePath, content) this.writeFileToTaro(styleDist, css) - printLog(pocessTypeEnum.GENERATE, '样式文件', this.generateShowPath(styleDist)) + printLog(processTypeEnum.GENERATE, '样式文件', this.generateShowPath(styleDist)) if (imports && imports.length) { imports.forEach(importItem => { const importPath = path.isAbsolute(importItem) @@ -698,15 +709,15 @@ class Convertor { spaces: 2, EOL: '\n' }) - printLog(pocessTypeEnum.GENERATE, '文件', this.generateShowPath(path.join(configDir, 'index.js'))) - printLog(pocessTypeEnum.GENERATE, '文件', this.generateShowPath(path.join(configDir, 'dev.js'))) - printLog(pocessTypeEnum.GENERATE, '文件', this.generateShowPath(path.join(configDir, 'prod.js'))) - printLog(pocessTypeEnum.GENERATE, '文件', this.generateShowPath(pkgPath)) - printLog(pocessTypeEnum.GENERATE, '文件', this.generateShowPath(path.join(this.convertRoot, 'project.config.json'))) - printLog(pocessTypeEnum.GENERATE, '文件', this.generateShowPath(path.join(this.convertRoot, '.gitignore'))) - printLog(pocessTypeEnum.GENERATE, '文件', this.generateShowPath(path.join(this.convertRoot, '.editorconfig'))) - printLog(pocessTypeEnum.GENERATE, '文件', this.generateShowPath(path.join(this.convertRoot, '.eslintrc'))) - printLog(pocessTypeEnum.GENERATE, '文件', this.generateShowPath(path.join(this.convertDir, 'index.html'))) + printLog(processTypeEnum.GENERATE, '文件', this.generateShowPath(path.join(configDir, 'index.js'))) + printLog(processTypeEnum.GENERATE, '文件', this.generateShowPath(path.join(configDir, 'dev.js'))) + printLog(processTypeEnum.GENERATE, '文件', this.generateShowPath(path.join(configDir, 'prod.js'))) + printLog(processTypeEnum.GENERATE, '文件', this.generateShowPath(pkgPath)) + printLog(processTypeEnum.GENERATE, '文件', this.generateShowPath(path.join(this.convertRoot, 'project.config.json'))) + printLog(processTypeEnum.GENERATE, '文件', this.generateShowPath(path.join(this.convertRoot, '.gitignore'))) + printLog(processTypeEnum.GENERATE, '文件', this.generateShowPath(path.join(this.convertRoot, '.editorconfig'))) + printLog(processTypeEnum.GENERATE, '文件', this.generateShowPath(path.join(this.convertRoot, '.eslintrc'))) + printLog(processTypeEnum.GENERATE, '文件', this.generateShowPath(path.join(this.convertDir, 'index.html'))) }) } @@ -716,5 +727,3 @@ class Convertor { this.generateConfigFiles() } } - -module.exports = Convertor diff --git a/packages/taro-cli/src/creator.js b/packages/taro-cli/src/creator.js deleted file mode 100644 index 86e8b846b37e..000000000000 --- a/packages/taro-cli/src/creator.js +++ /dev/null @@ -1,86 +0,0 @@ -const path = require('path') -const fs = require('fs-extra') -const memFs = require('mem-fs') -const editor = require('mem-fs-editor') - -const { - getRootPath -} = require('./util') - -class Creator { - constructor () { - const store = memFs.create() - this.fs = editor.create(store) - this.sourceRoot(path.join(getRootPath())) - this.init() - } - - init () {} - - sourceRoot (rootPath) { - if (typeof rootPath === 'string') { - this._rootPath = path.resolve(rootPath) - } - if (!fs.existsSync(this._rootPath)) { - fs.ensureDirSync(this._rootPath) - } - return this._rootPath - } - - templatePath () { - let filepath = path.join.apply(path, arguments) - if (!path.isAbsolute(filepath)) { - filepath = path.join(this._rootPath, 'templates', filepath) - } - return filepath - } - - destinationRoot (rootPath) { - if (typeof rootPath === 'string') { - this._destinationRoot = path.resolve(rootPath) - if (!fs.existsSync(rootPath)) { - fs.ensureDirSync(rootPath) - } - process.chdir(rootPath) - } - return this._destinationRoot || process.cwd() - } - - destinationPath () { - let filepath = path.join.apply(path, arguments) - if (!path.isAbsolute(filepath)) { - filepath = path.join(this.destinationRoot(), filepath) - } - return filepath - } - - template (template, source, dest, data, options) { - if (typeof dest !== 'string') { - options = data - data = dest - dest = source - } - this.fs.copyTpl( - this.templatePath(template, source), - this.destinationPath(dest), - Object.assign({}, this, data), - options - ) - return this - } - - copy (template, type, source, dest) { - dest = dest || source - this.template(template, type, source, dest) - return this - } - - writeGitKeepFile (dirname) { - dirname = path.resolve(dirname) - fs.writeFileSync(path.join(dirname, '.gitkeep'), 'Place hold file', 'utf8') - } - - write () {} -} - -module.exports = Creator diff --git a/packages/taro-cli/src/creator.ts b/packages/taro-cli/src/creator.ts new file mode 100644 index 000000000000..39571bd965ef --- /dev/null +++ b/packages/taro-cli/src/creator.ts @@ -0,0 +1,118 @@ +import * as path from 'path' +import * as fs from 'fs-extra' +import * as memFs from 'mem-fs' +import * as editor from 'mem-fs-editor' + +import { + getRootPath +} from './util' + +interface IFile { + contents: Buffer | NodeJS.ReadableStream | null, + cwd: string, + base: string | null | undefined, + history: string[], + relative: string, + dirname: string, + basename: string, + stem: string, + extname: string, + symlink: string, + stat: fs.Stats | null +} + +interface IReadOptions { + raw?: boolean +} + +interface IAppendOptions { + trimEnd?: boolean, + separator?: string +} + +interface IMemFsEditor { + store: { + [key: string]: IFile + }, + read(filePath: string, options?: IReadOptions): string | Buffer, + readJSON(filePath: string, defaults?: JSON): JSON, + write(filePath: string, contents: string | Buffer): string, + writeJSON(filepath: string, contents: JSON, replacer?: ((key: string, value: any) => any) | undefined, space?: string | number | undefined): string, + append(filePath: string, contents: string | Buffer, options?: IAppendOptions): string | Buffer, + copyTpl(from: string, to: string, context: object, templateOptions: object), + commit(cb: () => void) +} + +export default class Creator { + fs: IMemFsEditor + protected _rootPath: string + private _destinationRoot: string + + constructor () { + const store = memFs.create() + this.fs = editor.create(store) + this.sourceRoot(path.join(getRootPath())) + this.init() + } + + init () {} + + sourceRoot (rootPath?: string) { + if (typeof rootPath === 'string') { + this._rootPath = path.resolve(rootPath) + } + if (!fs.existsSync(this._rootPath)) { + fs.ensureDirSync(this._rootPath) + } + return this._rootPath + } + + templatePath (...args: string[]): string { + let filepath = path.join.apply(path, args) + if (!path.isAbsolute(filepath)) { + filepath = path.join(this._rootPath, 'templates', filepath) + } + return filepath + } + + destinationRoot (rootPath?: string): string { + if (typeof rootPath === 'string') { + this._destinationRoot = path.resolve(rootPath) + if (!fs.existsSync(rootPath)) { + fs.ensureDirSync(rootPath) + } + process.chdir(rootPath) + } + return this._destinationRoot || process.cwd() + } + + destinationPath (...args: string[]): string { + let filepath = path.join.apply(path, args) + if (!path.isAbsolute(filepath)) { + filepath = path.join(this.destinationRoot(), filepath) + } + return filepath + } + + template (template: string, source: string, dest: string, data?: object, options?) { + if (typeof dest !== 'string') { + options = data + data = dest + dest = source + } + this.fs.copyTpl( + this.templatePath(template, source), + this.destinationPath(dest), + Object.assign({}, this, data), + options + ) + return this + } + + writeGitKeepFile (dirname: string) { + dirname = path.resolve(dirname) + fs.writeFileSync(path.join(dirname, '.gitkeep'), 'Place hold file', 'utf8') + } + + write () {} +} diff --git a/packages/taro-cli/src/doctor/configSchema.js b/packages/taro-cli/src/doctor/configSchema.ts similarity index 98% rename from packages/taro-cli/src/doctor/configSchema.js rename to packages/taro-cli/src/doctor/configSchema.ts index 51441b227109..25f7798e7335 100644 --- a/packages/taro-cli/src/doctor/configSchema.js +++ b/packages/taro-cli/src/doctor/configSchema.ts @@ -1,4 +1,4 @@ -const Joi = require('joi'); +import Joi from 'joi' const schema = Joi.object().keys({ 'projectName': Joi.string().required(), @@ -100,4 +100,4 @@ const schema = Joi.object().keys({ }) }) -module.exports = schema +export default schema diff --git a/packages/taro-cli/src/doctor/configValidator.js b/packages/taro-cli/src/doctor/configValidator.ts similarity index 70% rename from packages/taro-cli/src/doctor/configValidator.js rename to packages/taro-cli/src/doctor/configValidator.ts index 41e6a402b5ea..53e257be11b2 100644 --- a/packages/taro-cli/src/doctor/configValidator.js +++ b/packages/taro-cli/src/doctor/configValidator.ts @@ -1,10 +1,11 @@ -const configSchema = require('./configSchema') -const Joi = require('joi') -const _ = require('lodash/fp') -const path = require('path') -const joi2desc = require('./joi2desc') +import Joi from 'joi' +import _ from 'lodash/fp' +import path from 'path' +import joi2desc from './joi2desc' +import configSchema from './configSchema' + +import { PROJECT_CONFIG } from '../util/constants' -const { PROJECT_CONFIG } = require('../util') const PROJECT_CONF_PATH = path.join(process.cwd(), PROJECT_CONFIG) const PROJECT_CONF = require(PROJECT_CONF_PATH)(_.merge) @@ -27,7 +28,7 @@ function buildReport (errors) { } } -module.exports = async function () { +export default async function () { const { error } = Joi.validate(PROJECT_CONF, configSchema, { abortEarly: false }) return buildReport(error) } diff --git a/packages/taro-cli/src/doctor/eslintValidator.js b/packages/taro-cli/src/doctor/eslintValidator.ts similarity index 78% rename from packages/taro-cli/src/doctor/eslintValidator.js rename to packages/taro-cli/src/doctor/eslintValidator.ts index c2b03be66cea..498a9d6c6464 100644 --- a/packages/taro-cli/src/doctor/eslintValidator.js +++ b/packages/taro-cli/src/doctor/eslintValidator.ts @@ -1,14 +1,15 @@ -const path = require('path') -const _ = require('lodash') -const { CLIEngine } = require('eslint') +import path from 'path' +import _ from 'lodash' +import { CLIEngine } from 'eslint' + +import { PROJECT_CONFIG } from '../util/constants' -const { PROJECT_CONFIG } = require('../util') const projectConfPath = path.join(process.cwd(), PROJECT_CONFIG) const projectConf = require(projectConfPath)(_.merge) const ESLINT_CONFIG_PATH = path.join(__dirname, 'validatorEslintrc.js') -module.exports = function () { +export default function () { const eslintCli = new CLIEngine({ cwd: process.cwd(), useEslintrc: false, diff --git a/packages/taro-cli/src/doctor/index.js b/packages/taro-cli/src/doctor/index.ts similarity index 89% rename from packages/taro-cli/src/doctor/index.js rename to packages/taro-cli/src/doctor/index.ts index bab3d7b8109c..3dec316e1010 100644 --- a/packages/taro-cli/src/doctor/index.js +++ b/packages/taro-cli/src/doctor/index.ts @@ -1,4 +1,4 @@ -module.exports = { +export default { validators: [ require('./configValidator'), require('./packageValidator'), diff --git a/packages/taro-cli/src/doctor/interface.ts b/packages/taro-cli/src/doctor/interface.ts new file mode 100644 index 000000000000..efe551e4a556 --- /dev/null +++ b/packages/taro-cli/src/doctor/interface.ts @@ -0,0 +1,5 @@ +export interface IErrorLine { + desc: string, + valid: boolean, + solution?: string +} diff --git a/packages/taro-cli/src/doctor/joi2desc.js b/packages/taro-cli/src/doctor/joi2desc.ts similarity index 98% rename from packages/taro-cli/src/doctor/joi2desc.js rename to packages/taro-cli/src/doctor/joi2desc.ts index 7f43c13af799..4fe795fdb705 100644 --- a/packages/taro-cli/src/doctor/joi2desc.js +++ b/packages/taro-cli/src/doctor/joi2desc.ts @@ -108,6 +108,6 @@ const joi2desc = { 'symbol.map': '' } -module.exports = function (error) { +export default function (error) { return joi2desc[error.type] || error.message } diff --git a/packages/taro-cli/src/doctor/packageValidator.js b/packages/taro-cli/src/doctor/packageValidator.ts similarity index 81% rename from packages/taro-cli/src/doctor/packageValidator.js rename to packages/taro-cli/src/doctor/packageValidator.ts index 5a9c7f4f5934..8f4d605a3e86 100644 --- a/packages/taro-cli/src/doctor/packageValidator.js +++ b/packages/taro-cli/src/doctor/packageValidator.ts @@ -1,14 +1,16 @@ -const _ = require('lodash/fp') -const npmCheck = require('npm-check') -const cliPkg = require('../../package.json') +import _ from 'lodash/fp' +import npmCheck from 'npm-check' +import { getPkgVersion } from '../util' + +const pkgVersion = getPkgVersion() const isTaroPkg = pkg => /^@tarojs\//.test(pkg.moduleName) -const isCliVersionNotMatch = _.compose(_.negate(_.equals(cliPkg.version)), _.get('installed')) +const isCliVersionNotMatch = _.compose(_.negate(_.equals(pkgVersion)), _.get('installed')) const isPkgInstalled = _.get('isInstalled') const isPkgNotInstalled = _.negate(isPkgInstalled) async function checkPkgs () { - let errorLines = [] + let errorLines: any[] = [] const pkgs = await npmCheck() .then(_.invoke('all')) .then(_.get('packages')) @@ -28,7 +30,7 @@ async function checkPkgs () { function taroCliVersionNotMatch (pkgs) { const pkgsNotMatch = _.filter(pkg => isPkgInstalled(pkg) && isCliVersionNotMatch(pkg), pkgs) const lines = _.map(pkg => Object({ - desc: `${pkg.moduleName} (${pkg.installed}) 与当前使用的 @tarojs/cli (${cliPkg.version}) 版本不一致, 请更新为统一的版本`, + desc: `${pkg.moduleName} (${pkg.installed}) 与当前使用的 @tarojs/cli (${pkgVersion}) 版本不一致, 请更新为统一的版本`, valid: false }), pkgsNotMatch) return lines @@ -41,7 +43,7 @@ function taroShouldUpdate (pkgs) { return [{ // 需要正确设置 next 版本以使 npm-check 在判定最新版本时将 rc 版本也算在内 - desc: `检测到最新稳定版本 Taro ${taroPkg.latest} , 当前 cli 版本 ${cliPkg.version}`, + desc: `检测到最新稳定版本 Taro ${taroPkg.latest} , 当前 cli 版本 ${pkgVersion}`, valid: true, // 并非错误,仅提示即可 solution: `前往 https://github.com/NervJS/taro/releases 了解详情` }] @@ -56,4 +58,4 @@ function pkgsNotInstalled (pkgs) { return lines } -module.exports = checkPkgs +export default checkPkgs diff --git a/packages/taro-cli/src/doctor/recommandValidator.js b/packages/taro-cli/src/doctor/recommandValidator.ts similarity index 92% rename from packages/taro-cli/src/doctor/recommandValidator.js rename to packages/taro-cli/src/doctor/recommandValidator.ts index d3e036ad4cd5..0c5001409816 100644 --- a/packages/taro-cli/src/doctor/recommandValidator.js +++ b/packages/taro-cli/src/doctor/recommandValidator.ts @@ -1,7 +1,9 @@ -const _ = require('lodash/fp') -const fs = require('fs-extra') -const path = require('path') -const chalk = require('chalk') +import _ from 'lodash/fp' +import fs from 'fs-extra' +import path from 'path' +import chalk from 'chalk' + +import { IErrorLine } from './interface' const PROJECT_PACKAGE_PATH = path.join(process.cwd(), 'package.json') const PROJECT_FOLDER_FILES = fs.readdirSync('./') @@ -27,8 +29,8 @@ const hasReadme = inProjectFolder(README) const hasGitignore = inProjectFolder(GITIGNORE) const hasEditorconfig = inProjectFolder(EDITORCONFIG) -module.exports = async function () { - const errorLines = [] +export default async function () { + const errorLines: IErrorLine[] = [] if (!hasRecommandTestFrameworks) { errorLines.push({ diff --git a/packages/taro-cli/src/doctor/validatorEslintrc.js b/packages/taro-cli/src/doctor/validatorEslintrc.ts similarity index 92% rename from packages/taro-cli/src/doctor/validatorEslintrc.js rename to packages/taro-cli/src/doctor/validatorEslintrc.ts index 521a005d3929..4e168dbb2596 100644 --- a/packages/taro-cli/src/doctor/validatorEslintrc.js +++ b/packages/taro-cli/src/doctor/validatorEslintrc.ts @@ -1,4 +1,4 @@ -module.exports = { +export default { 'extends': ['taro'], 'rules': { 'no-unused-vars': ['error', { 'varsIgnorePattern': 'Taro' }], diff --git a/packages/taro-cli/src/extra/util_wxs b/packages/taro-cli/src/extra/util_wxs deleted file mode 100644 index e6e011c2e14a..000000000000 --- a/packages/taro-cli/src/extra/util_wxs +++ /dev/null @@ -1,11 +0,0 @@ -var assign = function (s, d) { - if (typeof s !== 'object') { - return d - } - s = s || {} - d = d || {} - return JSON.parse((JSON.stringify(s) + JSON.stringify(d)).replace('}{', ',')) -} -module.exports = { - assign: assign -}; diff --git a/packages/taro-cli/src/h5.js b/packages/taro-cli/src/h5.ts similarity index 87% rename from packages/taro-cli/src/h5.js rename to packages/taro-cli/src/h5.ts index 9b1d32303fc1..fd9ad58343f3 100644 --- a/packages/taro-cli/src/h5.js +++ b/packages/taro-cli/src/h5.ts @@ -1,24 +1,33 @@ -const fs = require('fs-extra') -const path = require('path') -const chokidar = require('chokidar') -const wxTransformer = require('@tarojs/transformer-wx') -const klaw = require('klaw') -const traverse = require('babel-traverse').default -const t = require('babel-types') -const babel = require('babel-core') -const generate = require('better-babel-generator').default -const _ = require('lodash') -const rimraf = require('rimraf') -const { promisify } = require('util') -const minimatch = require('minimatch') - -const Util = require('./util') -const npmProcess = require('./util/npm') -const CONFIG = require('./config') -const { source: toAst, getObjKey } = require('./util/ast_convert') +import * as fs from 'fs-extra' +import * as path from 'path' + +import * as chokidar from 'chokidar' +import * as wxTransformer from '@tarojs/transformer-wx' +import * as klaw from 'klaw' +import traverse, { NodePath } from 'babel-traverse' +import * as t from 'babel-types' +import * as babel from 'babel-core' +import generate from 'better-babel-generator' +import * as _ from 'lodash' +import * as rimraf from 'rimraf' +import { promisify } from 'util' +import minimatch from 'minimatch' + +import * as Util from './util' +import * as npmProcess from './util/npm' +import CONFIG from './config' +import { convertSourceStringToAstExpression as toAst, getObjKey } from './util/astConvert' +import { + PROJECT_CONFIG, + REG_TYPESCRIPT, + REG_SCRIPTS, + processTypeEnum, + BUILD_TYPES +} from './util/constants' +import { ICopyOptions } from './mini/interface' const appPath = process.cwd() -const projectConfig = require(path.join(appPath, Util.PROJECT_CONFIG))(_.merge) +const projectConfig = require(path.join(appPath, PROJECT_CONFIG))(_.merge) const h5Config = projectConfig.h5 || {} const routerConfig = h5Config.router || {} const routerMode = routerConfig.mode === 'browser' ? 'browser' : 'hash' @@ -32,7 +41,7 @@ const tempDir = CONFIG.TEMP_DIR const tempPath = path.join(appPath, tempDir) const entryFilePath = Util.resolveScriptPath(path.join(sourcePath, CONFIG.ENTRY)) const entryFileName = path.basename(entryFilePath) -let pxTransformConfig = { designWidth: projectConfig.designWidth || 750 } +const pxTransformConfig = { designWidth: projectConfig.designWidth || 750 } const pathAlias = projectConfig.alias || {} const PACKAGES = { @@ -70,7 +79,7 @@ if (projectConfig.hasOwnProperty(DEVICE_RATIO)) { pxTransformConfig[DEVICE_RATIO] = projectConfig.deviceRatio } -let pages = [] +let pages: string[] = [] let tabBar let tabbarPos @@ -104,7 +113,7 @@ function processEntry (code, filePath) { code, sourcePath: filePath, isNormal: true, - isTyped: Util.REG_TYPESCRIPT.test(filePath), + isTyped: REG_TYPESCRIPT.test(filePath), adapter: 'h5' }).ast let taroImportDefaultName @@ -298,7 +307,7 @@ function processEntry (code, filePath) { if (!hasConstructor) { astPath.pushContainer('body', t.classMethod( 'method', t.identifier('constructor'), [t.identifier('props'), t.identifier('context')], - t.blockStatement([toAst('super(props, context)'), additionalConstructorNode]), false, false)) + t.blockStatement([toAst('super(props, context)'), additionalConstructorNode] as any), false, false)) } if (tabBar) { if (!hasComponentWillMount) { @@ -337,7 +346,7 @@ function processEntry (code, filePath) { }) root = rootNode ? rootNode.value.value : '' } - value.elements.forEach(v => { + (value.elements as t.StringLiteral[]).forEach(v => { const pagePath = `${root}/${v.value}`.replace(/\/{2,}/g, '/') pages.push(pagePath.replace(/^\//, '')) }) @@ -345,7 +354,7 @@ function processEntry (code, filePath) { // tabBar tabBar = value value.properties.forEach(node => { - if (node.keyName === 'position') tabbarPos = node.value.value + if ((node as any).keyName === 'position') tabbarPos = (node as any).value.value }) } else if ((keyName === 'iconPath' || keyName === 'selectedIconPath') && t.isStringLiteral(value)) { astPath.replaceWith( @@ -360,7 +369,7 @@ function processEntry (code, filePath) { ClassDeclaration: ClassDeclarationOrExpression, ClassProperty: { enter (astPath) { - const node = astPath.node + const node = astPath.node as t.ClassProperty const key = node.key const value = node.value const keyName = getObjKey(key) @@ -372,7 +381,7 @@ function processEntry (code, filePath) { }, ImportDeclaration: { enter (astPath) { - const node = astPath.node + const node = astPath.node as t.ImportDeclaration const source = node.source const specifiers = node.specifiers let value = source.value @@ -384,7 +393,7 @@ function processEntry (code, filePath) { const pathArr = value.split('/') if (pathArr.indexOf('pages') >= 0) { astPath.remove() - } else if (Util.REG_SCRIPTS.test(value)) { + } else if (REG_SCRIPTS.test(value)) { const realPath = path.resolve(filePath, '..', value) const dirname = path.dirname(realPath) const extname = path.extname(realPath) @@ -395,7 +404,7 @@ function processEntry (code, filePath) { return } if (value === PACKAGES['@tarojs/taro']) { - let specifier = specifiers.find(item => item.type === 'ImportDefaultSpecifier') + const specifier = specifiers.find(item => item.type === 'ImportDefaultSpecifier') if (specifier) { hasAddNervJsImportDefaultName = true taroImportDefaultName = specifier.local.name @@ -406,11 +415,11 @@ function processEntry (code, filePath) { t.importDefaultSpecifier(t.identifier(nervJsImportDefaultName)) ) } - const taroApisSpecifiers = [] - const deletedIdx = [] + const taroApisSpecifiers: t.ImportSpecifier[] = [] + const deletedIdx: number[] = [] specifiers.forEach((item, index) => { - if (item.imported && taroApis.indexOf(item.imported.name) >= 0) { - taroApisSpecifiers.push(t.importSpecifier(t.identifier(item.local.name), t.identifier(item.imported.name))) + if ((item as any).imported && taroApis.indexOf((item as any).imported.name) >= 0) { + taroApisSpecifiers.push(t.importSpecifier(t.identifier(item.local.name), t.identifier((item as any).imported.name))) deletedIdx.push(index) } }) @@ -450,14 +459,16 @@ function processEntry (code, filePath) { }, CallExpression: { enter (astPath) { - const node = astPath.node - const callee = node.callee + const node = astPath.node as t.CallExpression + const callee = node.callee as t.Identifier const calleeName = callee.name const parentPath = astPath.parentPath if (t.isMemberExpression(callee)) { - if (callee.object.name === taroImportDefaultName && callee.property.name === 'render') { - callee.object.name = nervJsImportDefaultName + const object = callee.object as t.Identifier + const property = callee.property as t.Identifier + if (object.name === taroImportDefaultName && property.name === 'render') { + object.name = nervJsImportDefaultName renderCallCode = generate(astPath.node).code astPath.remove() } @@ -474,7 +485,7 @@ function processEntry (code, filePath) { }, ClassMethod: { exit (astPath) { - const node = astPath.node + const node = astPath.node as t.ClassMethod const key = node.key const keyName = getObjKey(key) if (keyName === 'constructor') { @@ -499,10 +510,11 @@ function processEntry (code, filePath) { }, JSXOpeningElement: { enter (astPath) { - if (astPath.node.name.name === 'Provider') { - for (let v of astPath.node.attributes) { + const node = astPath.node as t.JSXOpeningElement + if ((node.name as any).name === 'Provider') { + for (const v of node.attributes) { if (v.name.name !== 'store') continue - storeName = v.value.expression.name + storeName = (v.value as any).expression.name break } } @@ -510,12 +522,13 @@ function processEntry (code, filePath) { }, Program: { exit (astPath) { + const node = astPath.node as t.Program const importNervjsNode = t.importDefaultSpecifier(t.identifier(nervJsImportDefaultName)) const importRouterNode = toAst(`import { Router } from '${PACKAGES['@tarojs/router']}'`) const importTaroH5Node = toAst(`import ${taroImportDefaultName} from '${PACKAGES['@tarojs/taro-h5']}'`) const importComponentNode = toAst(`import { View, ${tabBarComponentName}, ${tabBarContainerComponentName}, ${tabBarPanelComponentName}} from '${PACKAGES['@tarojs/components']}'`) - const lastImportIndex = _.findLastIndex(astPath.node.body, t.isImportDeclaration) - const lastImportNode = astPath.get(`body.${lastImportIndex > -1 ? lastImportIndex : 0}`) + const lastImportIndex = _.findLastIndex(node.body, t.isImportDeclaration) + const lastImportNode = astPath.get(`body.${lastImportIndex > -1 ? lastImportIndex : 0}`) as NodePath const extraNodes = [ importTaroH5Node, importRouterNode, @@ -534,7 +547,7 @@ function processEntry (code, filePath) { lastImportNode.insertAfter(extraNodes) if (renderCallCode) { const renderCallNode = toAst(renderCallCode) - astPath.pushContainer('body', renderCallNode) + node.body.push(renderCallNode as any) } } } @@ -555,13 +568,13 @@ function processOthers (code, filePath, fileType) { code, sourcePath: filePath, isNormal: true, - isTyped: Util.REG_TYPESCRIPT.test(filePath), + isTyped: REG_TYPESCRIPT.test(filePath), adapter: 'h5' }).ast let taroImportDefaultName let hasAddNervJsImportDefaultName = false let hasJSX = false - let isPage = fileType === FILE_TYPE.PAGE + const isPage = fileType === FILE_TYPE.PAGE let hasComponentDidMount = false let hasComponentDidShow = false @@ -630,7 +643,7 @@ function processOthers (code, filePath, fileType) { ClassDeclaration: ClassDeclarationOrExpression, ClassMethod: isPage ? { exit (astPath) { - const node = astPath.node + const node = astPath.node as t.ClassMethod const key = node.key const keyName = getObjKey(key) if (keyName === 'componentDidMount') { @@ -642,7 +655,7 @@ function processOthers (code, filePath, fileType) { } : {}, ImportDeclaration: { enter (astPath) { - const node = astPath.node + const node = astPath.node as t.ImportDeclaration const source = node.source let value = source.value const specifiers = node.specifiers @@ -650,7 +663,7 @@ function processOthers (code, filePath, fileType) { source.value = value = Util.replaceAliasPath(filePath, value, pathAlias) } if (!Util.isNpmPkg(value)) { - if (Util.REG_SCRIPTS.test(value)) { + if (REG_SCRIPTS.test(value)) { const realPath = path.resolve(filePath, '..', value) const dirname = path.dirname(realPath) const extname = path.extname(realPath) @@ -658,7 +671,7 @@ function processOthers (code, filePath, fileType) { node.source = t.stringLiteral(Util.promoteRelativePath(path.relative(filePath, removeExtPath)).replace(/\\/g, '/')) } } else if (value === PACKAGES['@tarojs/taro']) { - let specifier = specifiers.find(item => item.type === 'ImportDefaultSpecifier') + const specifier = specifiers.find(item => item.type === 'ImportDefaultSpecifier') if (specifier) { hasAddNervJsImportDefaultName = true taroImportDefaultName = specifier.local.name @@ -669,11 +682,11 @@ function processOthers (code, filePath, fileType) { t.importDefaultSpecifier(t.identifier(nervJsImportDefaultName)) ) } - const taroApisSpecifiers = [] - const deletedIdx = [] + const taroApisSpecifiers: t.ImportSpecifier[] = [] + const deletedIdx: number[] = [] specifiers.forEach((item, index) => { - if (item.imported && taroApis.indexOf(item.imported.name) >= 0) { - taroApisSpecifiers.push(t.importSpecifier(t.identifier(item.local.name), t.identifier(item.imported.name))) + if ((item as t.ImportSpecifier).imported && taroApis.indexOf((item as t.ImportSpecifier).imported.name) >= 0) { + taroApisSpecifiers.push(t.importSpecifier(t.identifier(item.local.name), t.identifier((item as t.ImportSpecifier).imported.name))) deletedIdx.push(index) } }) @@ -703,7 +716,7 @@ function processOthers (code, filePath, fileType) { if (isPage) { astPath.traverse(programExitVisitor) } - const node = astPath.node + const node = astPath.node as t.Program if (hasJSX && !hasAddNervJsImportDefaultName) { node.body.unshift( t.importDeclaration([ @@ -713,7 +726,7 @@ function processOthers (code, filePath, fileType) { } if (taroImportDefaultName) { const importTaro = toAst(`import ${taroImportDefaultName} from '${PACKAGES['@tarojs/taro-h5']}'`) - node.body.unshift(importTaro) + node.body.unshift(importTaro as any) } } } @@ -775,11 +788,12 @@ function classifyFiles (filename) { base: path.basename(relSrcPath, path.extname(relSrcPath)) }) - const isPage = pages.some(page => { + const isPage: boolean = pages.some(page => { const relPage = path.normalize( path.relative(appPath, page) ) if (path.relative(relPage, relSrcPath) === '') return true + return false }) if (isPage) { @@ -804,12 +818,12 @@ function getDist (filename, isScriptFile) { }) } -function processFiles (filePath) { +export function processFiles (filePath) { const file = fs.readFileSync(filePath) const dirname = path.dirname(filePath) const extname = path.extname(filePath) const distDirname = dirname.replace(sourcePath, tempDir) - const isScriptFile = Util.REG_SCRIPTS.test(extname) + const isScriptFile = REG_SCRIPTS.test(extname) const distPath = getDist(filePath, isScriptFile) try { @@ -843,33 +857,33 @@ function watchFiles () { .on('add', filePath => { pages = [] const relativePath = path.relative(appPath, filePath) - Util.printLog(Util.pocessTypeEnum.CREATE, '添加文件', relativePath) + Util.printLog(processTypeEnum.CREATE, '添加文件', relativePath) processFiles(filePath) }) .on('change', filePath => { pages = [] const relativePath = path.relative(appPath, filePath) - Util.printLog(Util.pocessTypeEnum.MODIFY, '文件变动', relativePath) + Util.printLog(processTypeEnum.MODIFY, '文件变动', relativePath) processFiles(filePath) }) .on('unlink', filePath => { const relativePath = path.relative(appPath, filePath) const extname = path.extname(relativePath) - const isScriptFile = Util.REG_SCRIPTS.test(extname) + const isScriptFile = REG_SCRIPTS.test(extname) const dist = getDist(filePath, isScriptFile) - Util.printLog(Util.pocessTypeEnum.UNLINK, '删除文件', relativePath) + Util.printLog(processTypeEnum.UNLINK, '删除文件', relativePath) fs.unlinkSync(dist) }) } -function buildTemp () { +export function buildTemp () { fs.ensureDirSync(tempPath) return new Promise((resolve, reject) => { klaw(sourcePath) .on('data', file => { const relativePath = path.relative(appPath, file.path) if (!file.stats.isDirectory()) { - Util.printLog(Util.pocessTypeEnum.CREATE, '发现文件', relativePath) + Util.printLog(processTypeEnum.CREATE, '发现文件', relativePath) processFiles(file.path) } }) @@ -885,7 +899,7 @@ async function buildDist (buildConfig) { const sourceRoot = projectConfig.sourceRoot || CONFIG.SOURCE_DIR h5Config.env = projectConfig.env Object.assign(h5Config.env, { - TARO_ENV: JSON.stringify(Util.BUILD_TYPES.H5) + TARO_ENV: JSON.stringify(BUILD_TYPES.H5) }) h5Config.defineConstants = projectConfig.defineConstants h5Config.plugins = projectConfig.plugins @@ -938,7 +952,7 @@ function copyFiles () { const to = path.join(projectDir, pattern.to) let ignore = pattern.ignore || globalIgnore if (fs.existsSync(from)) { - const copyOptions = {} + const copyOptions: ICopyOptions = {} if (ignore) { ignore = Array.isArray(ignore) ? ignore : [ignore] copyOptions.filter = src => { @@ -953,26 +967,20 @@ function copyFiles () { } copyFileSync(from, to, copyOptions) } else { - Util.printLog(Util.pocessTypeEnum.ERROR, '拷贝失败', `${pattern.from} 文件不存在!`) + Util.printLog(processTypeEnum.ERROR, '拷贝失败', `${pattern.from} 文件不存在!`) } } }) } } -async function build (buildConfig) { - process.env.TARO_ENV = Util.BUILD_TYPES.H5 +export async function build (buildConfig) { + process.env.TARO_ENV = BUILD_TYPES.H5 await clean() copyFiles() - await buildTemp(buildConfig) + await buildTemp() await buildDist(buildConfig) if (buildConfig.watch) { watchFiles() } } - -module.exports = { - build, - buildTemp, - processFiles -} diff --git a/packages/taro-cli/src/mini/astProcess.ts b/packages/taro-cli/src/mini/astProcess.ts new file mode 100644 index 000000000000..e45a7ba5235f --- /dev/null +++ b/packages/taro-cli/src/mini/astProcess.ts @@ -0,0 +1,886 @@ +import * as fs from 'fs-extra' +import * as path from 'path' + +import * as babel from 'babel-core' +import * as t from 'babel-types' +import generate from 'babel-generator' +import traverse from 'babel-traverse' +import _ from 'lodash' +import { Config as IConfig } from '@tarojs/taro' + +const template = require('babel-template') + +import { + CONFIG_MAP, + REG_SCRIPT, + REG_TYPESCRIPT, + REG_JSON, + REG_FONT, + REG_IMAGE, + REG_MEDIA, + REG_STYLE, + CSS_EXT, + processTypeEnum, + BUILD_TYPES +} from '../util/constants' +import { + resolveScriptPath, + printLog, + promoteRelativePath, + isNpmPkg, + isAliasPath, + replaceAliasPath +} from '../util' +import { convertObjectToAstExpression, convertArrayToAstExpression } from '../util/astConvert' +import babylonConfig from '../config/babylon' + +import { + NODE_MODULES_REG, + PARSE_AST_TYPE, + taroJsComponents, + taroJsRedux, + taroJsFramework, + DEVICE_RATIO_NAME +} from './constants' +import { IComponentObj } from './interface' +import { getExactedNpmFilePath, getNotExistNpmList } from './npmExact' +import { + getBuildData, + isFileToBePage +} from './helper' +import { processStyleUseCssModule } from './compileStyle' + +function traverseObjectNode (node) { + const { buildAdapter } = getBuildData() + if (node.type === 'ClassProperty' || node.type === 'ObjectProperty') { + const properties = node.value.properties + const obj = {} + properties.forEach(p => { + let key = t.isIdentifier(p.key) ? p.key.name : p.key.value + if (CONFIG_MAP[buildAdapter][key]) { + key = CONFIG_MAP[buildAdapter][key] + } + obj[key] = traverseObjectNode(p.value) + }) + return obj + } + if (node.type === 'ObjectExpression') { + const properties = node.properties + const obj= {} + properties.forEach(p => { + let key = t.isIdentifier(p.key) ? p.key.name : p.key.value + if (CONFIG_MAP[buildAdapter][key]) { + key = CONFIG_MAP[buildAdapter][key] + } + obj[key] = traverseObjectNode(p.value) + }) + return obj + } + if (node.type === 'ArrayExpression') { + return node.elements.map(item => traverseObjectNode(item)) + } + if (node.type === 'NullLiteral') { + return null + } + return node.value +} + +interface IAnalyzeImportUrlOptions { + astPath: any, + value: string, + sourceFilePath: string, + filePath: string, + styleFiles: string[], + scriptFiles: string[], + jsonFiles: string[], + mediaFiles: string[] +} + +function analyzeImportUrl ({ + astPath, + value, + sourceFilePath, + filePath, + styleFiles, + scriptFiles, + jsonFiles, + mediaFiles +}: IAnalyzeImportUrlOptions): void { + const valueExtname = path.extname(value) + const node = astPath.node + const { + nodeModulesPath, + npmOutputDir, + sourceDir, + outputDir + } = getBuildData() + if (value.indexOf('.') === 0) { + let importPath = path.resolve(path.dirname(sourceFilePath), value) + importPath = resolveScriptPath(importPath) + if (isFileToBePage(importPath)) { + astPath.remove() + } else { + if (REG_SCRIPT.test(valueExtname) || REG_TYPESCRIPT.test(valueExtname)) { + const vpath = path.resolve(sourceFilePath, '..', value) + let fPath = value + if (fs.existsSync(vpath) && vpath !== sourceFilePath) { + fPath = vpath + } + if (scriptFiles.indexOf(fPath) < 0) { + scriptFiles.push(fPath) + } + } else if (REG_JSON.test(valueExtname)) { + const vpath = path.resolve(sourceFilePath, '..', value) + if (jsonFiles.indexOf(vpath) < 0) { + jsonFiles.push(vpath) + } + if (fs.existsSync(vpath)) { + const obj = JSON.parse(fs.readFileSync(vpath).toString()) + const specifiers = node.specifiers + let defaultSpecifier = null + specifiers.forEach(item => { + if (item.type === 'ImportDefaultSpecifier') { + defaultSpecifier = item.local.name + } + }) + if (defaultSpecifier) { + let objArr: t.NullLiteral | t.Expression = t.nullLiteral() + if (Array.isArray(obj)) { + objArr = t.arrayExpression(convertArrayToAstExpression(obj)) + } else { + objArr = t.objectExpression(convertObjectToAstExpression(obj)) + } + astPath.replaceWith(t.variableDeclaration('const', [t.variableDeclarator(t.identifier(defaultSpecifier), objArr)])) + } + } + } else if (REG_FONT.test(valueExtname) || REG_IMAGE.test(valueExtname) || REG_MEDIA.test(valueExtname)) { + const vpath = path.resolve(sourceFilePath, '..', value) + if (!fs.existsSync(vpath)) { + printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 不存在!`) + return + } + if (mediaFiles.indexOf(vpath) < 0) { + mediaFiles.push(vpath) + } + const specifiers = node.specifiers + let defaultSpecifier = null + specifiers.forEach(item => { + if (item.type === 'ImportDefaultSpecifier') { + defaultSpecifier = item.local.name + } + }) + let sourceDirPath = sourceDir + if (NODE_MODULES_REG.test(vpath)) { + sourceDirPath = nodeModulesPath + } + + if (defaultSpecifier) { + astPath.replaceWith(t.variableDeclaration('const', [t.variableDeclarator(t.identifier(defaultSpecifier), t.stringLiteral(vpath.replace(sourceDirPath, '').replace(/\\/g, '/')))])) + } else { + astPath.remove() + } + } else if (REG_STYLE.test(valueExtname)) { + const stylePath = path.resolve(path.dirname(sourceFilePath), value) + if (styleFiles.indexOf(stylePath) < 0) { + styleFiles.push(stylePath) + } + astPath.remove() + } else { + let vpath = resolveScriptPath(path.resolve(sourceFilePath, '..', value)) + let outputVpath + if (NODE_MODULES_REG.test(vpath)) { + outputVpath = vpath.replace(nodeModulesPath, npmOutputDir) + } else { + outputVpath = vpath.replace(sourceDir, outputDir) + } + let relativePath = path.relative(filePath, outputVpath) + if (vpath && vpath !== sourceFilePath) { + if (!fs.existsSync(vpath)) { + printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 不存在!`) + } else { + if (fs.lstatSync(vpath).isDirectory()) { + if (fs.existsSync(path.join(vpath, 'index.js'))) { + vpath = path.join(vpath, 'index.js') + relativePath = path.join(relativePath, 'index.js') + } else { + printLog(processTypeEnum.ERROR, '引用目录', `文件 ${sourceFilePath} 中引用了目录 ${value}!`) + return + } + } + if (scriptFiles.indexOf(vpath) < 0) { + scriptFiles.push(vpath) + } + relativePath = promoteRelativePath(relativePath) + relativePath = relativePath.replace(path.extname(relativePath), '.js') + node.source.value = relativePath + } + } + } + } + } +} + +export interface IParseAstReturn { + code: string, + styleFiles: string[], + scriptFiles: string[], + jsonFiles: string[], + mediaFiles: string[] + configObj: IConfig, + componentClassName: string +} + +export function parseAst ( + type: PARSE_AST_TYPE, + ast: t.File, + depComponents: IComponentObj[], + sourceFilePath: string, + filePath: string, + npmSkip: boolean = false +): IParseAstReturn { + const styleFiles: string[] = [] + const scriptFiles: string[] = [] + const jsonFiles: string[] = [] + const mediaFiles: string[] = [] + + const { + nodeModulesPath, + npmOutputDir, + sourceDir, + outputDir, + buildAdapter, + constantsReplaceList, + isProduction, + npmConfig, + alias: pathAlias, + compileInclude, + projectConfig + } = getBuildData() + const notExistNpmList = getNotExistNpmList() + const taroMiniAppFramework = `@tarojs/taro-${buildAdapter}` + let configObj: IConfig = {} + let componentClassName: string = '' + let taroJsReduxConnect: string = '' + let taroImportDefaultName + let needExportDefault = false + let exportTaroReduxConnected: string | null = null + ast = babel.transformFromAst(ast, '', { + plugins: [ + [require('babel-plugin-danger-remove-unused-import'), { ignore: ['@tarojs/taro', 'react', 'nervjs'] }], + [require('babel-plugin-transform-define').default, constantsReplaceList] + ] + }).ast as t.File + traverse(ast, { + ClassDeclaration (astPath) { + const node = astPath.node + let hasCreateData = false + if (node.superClass) { + astPath.traverse({ + ClassMethod (astPath) { + if (astPath.get('key').isIdentifier({ name: '_createData' })) { + hasCreateData = true + } + } + }) + if (hasCreateData) { + needExportDefault = true + astPath.traverse({ + ClassMethod (astPath) { + const node = astPath.node + if (node.kind === 'constructor') { + astPath.traverse({ + ExpressionStatement (astPath) { + const node = astPath.node + if (node.expression && + node.expression.type === 'AssignmentExpression' && + node.expression.operator === '=') { + const left = node.expression.left + if (left.type === 'MemberExpression' && + left.object.type === 'ThisExpression' && + left.property.type === 'Identifier' && + left.property.name === 'config') { + configObj = traverseObjectNode(node.expression.right) + } + } + } + }) + } + } + }) + if (node.id === null) { + componentClassName = '_TaroComponentClass' + astPath.replaceWith( + t.classDeclaration( + t.identifier(componentClassName), + node.superClass as t.Expression, + node.body as t.ClassBody, + node.decorators as t.Decorator[] || [] + ) + ) + } else if (node.id.name === 'App') { + componentClassName = '_App' + astPath.replaceWith( + t.classDeclaration( + t.identifier(componentClassName), + node.superClass as t.Expression, + node.body as t.ClassBody, + node.decorators as t.Decorator[] || [] + ) + ) + } else { + componentClassName = node.id.name + } + } + } + }, + + ClassExpression (astPath) { + const node = astPath.node + if (node.superClass) { + let hasCreateData = false + astPath.traverse({ + ClassMethod (astPath) { + if (astPath.get('key').isIdentifier({ name: '_createData' })) { + hasCreateData = true + } + } + }) + if (hasCreateData) { + needExportDefault = true + if (node.id === null) { + const parentNode = astPath.parentPath.node as any + if (t.isVariableDeclarator(astPath.parentPath)) { + componentClassName = parentNode.id.name + } else { + componentClassName = '_TaroComponentClass' + } + astPath.replaceWith( + t.classExpression( + t.identifier(componentClassName), + node.superClass as t.Expression, + node.body as t.ClassBody, + node.decorators as t.Decorator[] || [] + ) + ) + } else if (node.id.name === 'App') { + componentClassName = '_App' + astPath.replaceWith( + t.classExpression( + t.identifier(componentClassName), + node.superClass as t.Expression, + node.body as t.ClassBody, + node.decorators as t.Decorator[] || [] + ) + ) + } else { + componentClassName = node.id.name + } + } + } + }, + + ClassProperty (astPath) { + const node = astPath.node + if (node.key.name === 'config') { + configObj = traverseObjectNode(node) + } + }, + + ImportDeclaration (astPath) { + const node = astPath.node + const source = node.source + let value = source.value + const specifiers = node.specifiers + // alias 替换 + if (isAliasPath(value, pathAlias)) { + value = replaceAliasPath(sourceFilePath, value, pathAlias) + source.value = value + } + if (isNpmPkg(value) && !notExistNpmList.has(value)) { + if (value === taroJsComponents) { + astPath.remove() + } else { + let isDepComponent = false + if (depComponents && depComponents.length) { + depComponents.forEach(item => { + if (item.path === value) { + isDepComponent = true + } + }) + } + if (isDepComponent) { + astPath.remove() + } else { + const specifiers = node.specifiers + if (value === taroJsFramework) { + let defaultSpecifier: string | null = null + specifiers.forEach(item => { + if (item.type === 'ImportDefaultSpecifier') { + defaultSpecifier = item.local.name + } + }) + if (defaultSpecifier) { + taroImportDefaultName = defaultSpecifier + } + value = taroMiniAppFramework + } else if (value === taroJsRedux) { + specifiers.forEach(item => { + if (item.type === 'ImportSpecifier') { + const local = item.local + if (local.type === 'Identifier' && local.name === 'connect') { + taroJsReduxConnect = item.imported.name + } + } + }) + } + if (!npmSkip) { + source.value = getExactedNpmFilePath({ + npmName: value, + filePath, + isProduction, + npmConfig, + buildAdapter, + npmOutputDir, + compileInclude + }) + } else { + source.value = value + } + } + } + } else if (CSS_EXT.indexOf(path.extname(value)) !== -1 && specifiers.length > 0) { // 对 使用 import style from './style.css' 语法引入的做转化处理 + printLog(processTypeEnum.GENERATE, '替换代码', `为文件 ${sourceFilePath} 生成 css modules`) + const styleFilePath = path.join(path.dirname(sourceFilePath), value) + const styleCode = fs.readFileSync(styleFilePath).toString() + const result = processStyleUseCssModule({ + css: styleCode, + filePath: styleFilePath + }) + const tokens = result.root.exports || {} + const objectPropperties: t.ObjectProperty[] = [] + for (const key in tokens) { + if (tokens.hasOwnProperty(key)) { + objectPropperties.push(t.objectProperty(t.identifier(key), t.stringLiteral(tokens[key]))) + } + } + let defaultDeclator: t.VariableDeclarator[] | null = null + let normalDeclator: t.VariableDeclarator[] | null = null + const importItems: any[] = [] + specifiers.forEach(s => { + if (t.isImportDefaultSpecifier(s)) { + defaultDeclator = [t.variableDeclarator(t.identifier(s.local.name), t.objectExpression(objectPropperties))] + } else { + importItems.push(t.objectProperty(t.identifier(s.local.name), t.identifier(s.local.name))) + } + }) + normalDeclator = [t.variableDeclarator(t.objectPattern(importItems), t.objectExpression(objectPropperties))] + if (defaultDeclator) { + astPath.insertBefore(t.variableDeclaration('const', defaultDeclator)) + } + if (normalDeclator) { + astPath.insertBefore(t.variableDeclaration('const', normalDeclator)) + } + astPath.remove() + if (styleFiles.indexOf(styleFilePath) < 0) { // add this css file to queue + styleFiles.push(styleFilePath) + } + } else if (path.isAbsolute(value)) { + printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 是绝对路径!`) + } + }, + + CallExpression (astPath) { + const node = astPath.node + const callee = node.callee as (t.Identifier | t.MemberExpression) + if (t.isMemberExpression(callee)) { + if (taroImportDefaultName && (callee.object as t.Identifier).name === taroImportDefaultName && (callee.property as t.Identifier).name === 'render') { + astPath.remove() + } + } else if (callee.name === 'require') { + const args = node.arguments as t.StringLiteral[] + let value = args[0].value + if (isAliasPath(value, pathAlias)) { + value = replaceAliasPath(sourceFilePath, value, pathAlias) + args[0].value = value + } + if (isNpmPkg(value) && !notExistNpmList.has(value)) { + if (value === taroJsComponents) { + astPath.remove() + } else { + let isDepComponent = false + if (depComponents && depComponents.length) { + depComponents.forEach(item => { + if (item.path === value) { + isDepComponent = true + } + }) + } + if (isDepComponent) { + astPath.remove() + } else { + if (t.isVariableDeclaration(astPath.parentPath.parentPath)) { + const parentNode = astPath.parentPath.parentPath.node as t.VariableDeclaration + if (parentNode.declarations.length === 1 && parentNode.declarations[0].init) { + const id = parentNode.declarations[0].id + if (value === taroJsFramework && id.type === 'Identifier') { + taroImportDefaultName = id.name + value = taroMiniAppFramework + } else if (value === taroJsRedux) { + const declarations = parentNode.declarations + declarations.forEach(item => { + const id = item.id + if (id.type === 'ObjectPattern') { + const properties = id.properties as any + properties.forEach(p => { + if (p.type === 'ObjectProperty') { + if (p.value.type === 'Identifier' && p.value.name === 'connect') { + taroJsReduxConnect = p.key.name + } + } + }) + } + }) + } + } + } + if (!npmSkip) { + args[0].value = getExactedNpmFilePath({ + npmName: value, + filePath, + isProduction, + npmConfig, + buildAdapter, + npmOutputDir, + compileInclude + }) + } else { + args[0].value = value + } + } + } + } else if (CSS_EXT.indexOf(path.extname(value)) !== -1 && t.isVariableDeclarator(astPath.parentPath)) { // 对 使用 const style = require('./style.css') 语法引入的做转化处理 + printLog(processTypeEnum.GENERATE, '替换代码', `为文件 ${sourceFilePath} 生成 css modules`) + const styleFilePath = path.join(path.dirname(sourceFilePath), value) + const styleCode = fs.readFileSync(styleFilePath).toString() + const result = processStyleUseCssModule({ + css: styleCode, + filePath: styleFilePath + }) + const tokens = result.root.exports || {} + const objectPropperties: t.ObjectProperty[] = [] + for (const key in tokens) { + if (tokens.hasOwnProperty(key)) { + objectPropperties.push(t.objectProperty(t.identifier(key), t.stringLiteral(tokens[key]))) + } + } + astPath.replaceWith(t.objectExpression(objectPropperties)) + if (styleFiles.indexOf(styleFilePath) < 0) { // add this css file to queue + styleFiles.push(styleFilePath) + } + } else if (path.isAbsolute(value)) { + printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 是绝对路径!`) + } + } + }, + + ExportDefaultDeclaration (astPath) { + const node = astPath.node + const declaration = node.declaration + needExportDefault = false + if ( + declaration && + (declaration.type === 'ClassDeclaration' || declaration.type === 'ClassExpression') + ) { + const superClass = declaration.superClass + if (superClass) { + let hasCreateData = false + astPath.traverse({ + ClassMethod (astPath) { + if (astPath.get('key').isIdentifier({ name: '_createData' })) { + hasCreateData = true + } + } + }) + if (hasCreateData) { + needExportDefault = true + if (declaration.id === null) { + componentClassName = '_TaroComponentClass' + } else if (declaration.id.name === 'App') { + componentClassName = '_App' + } else { + componentClassName = declaration.id.name + } + const isClassDcl = declaration.type === 'ClassDeclaration' + const classDclProps = [t.identifier(componentClassName), superClass, declaration.body, declaration.decorators || []] + astPath.replaceWith(isClassDcl ? t.classDeclaration.apply(null, classDclProps) : t.classExpression.apply(null, classDclProps)) + } + } + } else if (declaration.type === 'CallExpression') { + const callee = declaration.callee + if (callee && callee.type === 'CallExpression') { + const subCallee = callee.callee + if (subCallee.type === 'Identifier' && subCallee.name === taroJsReduxConnect) { + const args = declaration.arguments as t.Identifier[] + if (args.length === 1 && args[0].name === componentClassName) { + needExportDefault = true + exportTaroReduxConnected = `${componentClassName}__Connected` + astPath.replaceWith(t.variableDeclaration('const', [t.variableDeclarator(t.identifier(`${componentClassName}__Connected`), t.callExpression(declaration.callee as t.Expression, declaration.arguments as Array))])) + } + } + } + } + }, + + ExportNamedDeclaration (astPath) { + const node = astPath.node + const source = node.source + if (source && source.type === 'StringLiteral') { + const value = source.value + analyzeImportUrl({ astPath, value, sourceFilePath, filePath, styleFiles, scriptFiles, jsonFiles, mediaFiles }) + } + }, + + ExportAllDeclaration (astPath) { + const node = astPath.node + const source = node.source + if (source && source.type === 'StringLiteral') { + const value = source.value + analyzeImportUrl({ astPath, value, sourceFilePath, filePath, styleFiles, scriptFiles, jsonFiles, mediaFiles }) + } + }, + + Program: { + exit (astPath) { + astPath.traverse({ + ImportDeclaration (astPath) { + const node = astPath.node + const source = node.source + const value = source.value + analyzeImportUrl({ astPath, value, sourceFilePath, filePath, styleFiles, scriptFiles, jsonFiles, mediaFiles }) + }, + CallExpression (astPath) { + const node = astPath.node + const callee = node.callee as t.Identifier + if (callee.name === 'require') { + const args = node.arguments as t.StringLiteral[] + const value = args[0].value + const valueExtname = path.extname(value) + if (value.indexOf('.') === 0) { + let importPath = path.resolve(path.dirname(sourceFilePath), value) + importPath = resolveScriptPath(importPath) + if (isFileToBePage(importPath)) { + if (astPath.parent.type === 'AssignmentExpression' || 'ExpressionStatement') { + astPath.parentPath.remove() + } else if (astPath.parent.type === 'VariableDeclarator') { + astPath.parentPath.parentPath.remove() + } else { + astPath.remove() + } + } else { + if (REG_STYLE.test(valueExtname)) { + const stylePath = path.resolve(path.dirname(sourceFilePath), value) + if (styleFiles.indexOf(stylePath) < 0) { + styleFiles.push(stylePath) + } + if (astPath.parent.type === 'AssignmentExpression' || 'ExpressionStatement') { + astPath.parentPath.remove() + } else if (astPath.parent.type === 'VariableDeclarator') { + astPath.parentPath.parentPath.remove() + } else { + astPath.remove() + } + } else if (REG_JSON.test(valueExtname)) { + const vpath = path.resolve(sourceFilePath, '..', value) + if (jsonFiles.indexOf(vpath) < 0) { + jsonFiles.push(vpath) + } + if (fs.existsSync(vpath)) { + const obj = JSON.parse(fs.readFileSync(vpath).toString()) + let objArr: t.NullLiteral | t.Expression = t.nullLiteral() + if (Array.isArray(obj)) { + objArr = t.arrayExpression(convertArrayToAstExpression(obj)) + } else { + objArr = t.objectExpression(convertObjectToAstExpression(obj)) + } + astPath.replaceWith(t.objectExpression(objArr as any)) + } + } else if (REG_SCRIPT.test(valueExtname) || REG_TYPESCRIPT.test(valueExtname)) { + const vpath = path.resolve(sourceFilePath, '..', value) + let fPath = value + if (fs.existsSync(vpath) && vpath !== sourceFilePath) { + fPath = vpath + } + if (scriptFiles.indexOf(fPath) < 0) { + scriptFiles.push(fPath) + } + } else if (REG_FONT.test(valueExtname) || REG_IMAGE.test(valueExtname) || REG_MEDIA.test(valueExtname)) { + const vpath = path.resolve(sourceFilePath, '..', value) + if (mediaFiles.indexOf(vpath) < 0) { + mediaFiles.push(vpath) + } + let sourceDirPath = sourceDir + if (NODE_MODULES_REG.test(vpath)) { + sourceDirPath = nodeModulesPath + } + astPath.replaceWith(t.stringLiteral(vpath.replace(sourceDirPath, '').replace(/\\/g, '/'))) + } else { + let vpath = resolveScriptPath(path.resolve(sourceFilePath, '..', value)) + let outputVpath + if (NODE_MODULES_REG.test(vpath)) { + outputVpath = vpath.replace(nodeModulesPath, npmOutputDir) + } else { + outputVpath = vpath.replace(sourceDir, outputDir) + } + let relativePath = path.relative(filePath, outputVpath) + if (vpath) { + if (!fs.existsSync(vpath)) { + printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 不存在!`) + } else { + if (fs.lstatSync(vpath).isDirectory()) { + if (fs.existsSync(path.join(vpath, 'index.js'))) { + vpath = path.join(vpath, 'index.js') + relativePath = path.join(relativePath, 'index.js') + } else { + printLog(processTypeEnum.ERROR, '引用目录', `文件 ${sourceFilePath} 中引用了目录 ${value}!`) + return + } + } + if (scriptFiles.indexOf(vpath) < 0) { + scriptFiles.push(vpath) + } + relativePath = promoteRelativePath(relativePath) + relativePath = relativePath.replace(path.extname(relativePath), '.js') + args[0].value = relativePath + } + } + } + } + } + } + } + }) + const node = astPath.node as t.Program + const exportVariableName = exportTaroReduxConnected || componentClassName + if (needExportDefault) { + const exportDefault = template(`export default ${exportVariableName}`, babylonConfig as any)() + node.body.push(exportDefault as any) + } + const taroMiniAppFrameworkPath = !npmSkip ? getExactedNpmFilePath({ + npmName: taroMiniAppFramework, + filePath, + isProduction, + npmConfig, + buildAdapter, + npmOutputDir, + compileInclude + }) : taroMiniAppFramework + switch (type) { + case PARSE_AST_TYPE.ENTRY: + const pxTransformConfig = { + designWidth: projectConfig.designWidth || 750 + } + if (projectConfig.hasOwnProperty(DEVICE_RATIO_NAME)) { + pxTransformConfig[DEVICE_RATIO_NAME] = projectConfig.deviceRatio + } + node.body.push(template(`App(require('${taroMiniAppFrameworkPath}').default.createApp(${exportVariableName}))`, babylonConfig as any)() as any) + node.body.push(template(`Taro.initPxTransform(${JSON.stringify(pxTransformConfig)})`, babylonConfig as any)() as any) + break + case PARSE_AST_TYPE.PAGE: + if (buildAdapter === BUILD_TYPES.WEAPP) { + node.body.push(template(`Component(require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}, true))`, babylonConfig as any)() as any) + } else { + node.body.push(template(`Page(require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}, true))`, babylonConfig as any)() as any) + } + break + case PARSE_AST_TYPE.COMPONENT: + node.body.push(template(`Component(require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}))`, babylonConfig as any)() as any) + break + default: + break + } + } + } + }) + return { + code: generate(ast).code, + styleFiles, + scriptFiles, + jsonFiles, + configObj, + mediaFiles, + componentClassName + } +} + +export function parseComponentExportAst (ast: t.File, componentName: string, componentPath: string, componentType: string): string | null { + const { + constantsReplaceList + } = getBuildData() + let componentRealPath: string | null = null + let importExportName + ast = babel.transformFromAst(ast, '', { + plugins: [ + [require('babel-plugin-transform-define').default, constantsReplaceList] + ] + }).ast as t.File + traverse(ast, { + ExportNamedDeclaration (astPath) { + const node = astPath.node + const specifiers = node.specifiers + const source = node.source + if (source && source.type === 'StringLiteral') { + specifiers.forEach(specifier => { + const exported = specifier.exported + if (_.kebabCase(exported.name) === componentName) { + componentRealPath = resolveScriptPath(path.resolve(path.dirname(componentPath), source.value)) + } + }) + } else { + specifiers.forEach(specifier => { + const exported = specifier.exported + if (_.kebabCase(exported.name) === componentName) { + importExportName = exported.name + } + }) + } + }, + + ExportDefaultDeclaration (astPath) { + const node = astPath.node + const declaration = node.declaration as t.Identifier + if (componentType === 'default') { + importExportName = declaration.name + } + }, + + CallExpression (astPath) { + if (astPath.get('callee').isIdentifier({ name: 'require' })) { + const arg = astPath.get('arguments')[0] + if (t.isStringLiteral(arg.node)) { + componentRealPath = resolveScriptPath(path.resolve(path.dirname(componentPath), arg.node.value)) + } + } + }, + + Program: { + exit (astPath) { + astPath.traverse({ + ImportDeclaration (astPath) { + const node = astPath.node + const specifiers = node.specifiers + const source = node.source + if (importExportName) { + specifiers.forEach(specifier => { + const local = specifier.local + if (local.name === importExportName) { + componentRealPath = resolveScriptPath(path.resolve(path.dirname(componentPath), source.value)) + } + }) + } + } + }) + } + } + }) + return componentRealPath +} diff --git a/packages/taro-cli/src/mini/compileScript.ts b/packages/taro-cli/src/mini/compileScript.ts new file mode 100644 index 000000000000..975c5cbcc42b --- /dev/null +++ b/packages/taro-cli/src/mini/compileScript.ts @@ -0,0 +1,146 @@ +import * as fs from 'fs-extra' +import * as path from 'path' + +import * as wxTransformer from '@tarojs/transformer-wx' + +import { + printLog, + isDifferentArray +} from '../util' +import { + BUILD_TYPES, + processTypeEnum, + REG_TYPESCRIPT +} from '../util/constants' +import { callPlugin } from '../util/npm' +import { IWxTransformResult } from '../util/types' + +import { + babelConfig, + shouldTransformAgain, + getBuildData, + copyFilesFromSrcToOutput, + getDependencyTree, + uglifyJS +} from './helper' +import { parseAst } from './astProcess' +import { PARSE_AST_TYPE, NODE_MODULES_REG } from './constants' +import { copyFileSync } from './copy' +import { IDependency } from './interface' + +const isBuildingScripts: Map = new Map() + +export function initCompileScripts () { + isBuildingScripts.clear() +} + +export function compileDepScripts (scriptFiles: string[]) { + const { + nodeModulesPath, + npmOutputDir, + projectConfig, + sourceDir, + outputDir, + appPath, + buildAdapter, + constantsReplaceList, + isProduction + } = getBuildData() + const dependencyTree = getDependencyTree() + scriptFiles.forEach(async item => { + if (path.isAbsolute(item)) { + let outputItem + if (NODE_MODULES_REG.test(item)) { + outputItem = item.replace(nodeModulesPath, npmOutputDir).replace(path.extname(item), '.js') + } else { + outputItem = item.replace(path.join(sourceDir), path.join(outputDir)).replace(path.extname(item), '.js') + } + const weappConf = Object.assign({}, projectConfig.weapp) + const useCompileConf = Object.assign({}, weappConf.compile) + const compileExclude = useCompileConf.exclude || [] + let isInCompileExclude = false + compileExclude.forEach(excludeItem => { + if (item.indexOf(path.join(appPath, excludeItem)) >= 0) { + isInCompileExclude = true + } + }) + if (isInCompileExclude) { + copyFileSync(item, outputItem) + return + } + if (!isBuildingScripts.get(outputItem)) { + isBuildingScripts.set(outputItem, true) + try { + const code = fs.readFileSync(item).toString() + const transformResult = wxTransformer({ + code, + sourcePath: item, + outputPath: outputItem, + isNormal: true, + isTyped: REG_TYPESCRIPT.test(item), + adapter: buildAdapter, + env: constantsReplaceList + }) + const ast = transformResult.ast + const res = parseAst(PARSE_AST_TYPE.NORMAL, ast, [], item, outputItem) + const fileDep = dependencyTree.get(item) || {} as IDependency + let resCode = res.code + resCode = await compileScriptFile(res.code, item, outputItem, buildAdapter) + fs.ensureDirSync(path.dirname(outputItem)) + if (isProduction) { + uglifyJS(resCode, item) + } + fs.writeFileSync(outputItem, resCode) + let modifyOutput = outputItem.replace(appPath + path.sep, '') + modifyOutput = modifyOutput.split(path.sep).join('/') + printLog(processTypeEnum.GENERATE, '依赖文件', modifyOutput) + // 编译依赖的脚本文件 + if (isDifferentArray(fileDep['script'], res.scriptFiles)) { + compileDepScripts(res.scriptFiles) + } + // 拷贝依赖文件 + if (isDifferentArray(fileDep['json'], res.jsonFiles)) { + copyFilesFromSrcToOutput(res.jsonFiles) + } + if (isDifferentArray(fileDep['media'], res.mediaFiles)) { + copyFilesFromSrcToOutput(res.mediaFiles) + } + fileDep['script'] = res.scriptFiles + fileDep['json'] = res.jsonFiles + fileDep['media'] = res.mediaFiles + dependencyTree.set(item, fileDep) + } catch (err) { + printLog(processTypeEnum.ERROR, '编译失败', item.replace(appPath + path.sep, '')) + console.log(err) + } + } + } + }) +} + +export async function compileScriptFile ( + content: string, + sourceFilePath: string, + outputFilePath: string, + adapter: BUILD_TYPES +): Promise { + const { + constantsReplaceList + } = getBuildData() + const compileScriptRes = await callPlugin('babel', content, sourceFilePath, babelConfig) + const code = compileScriptRes.code + if (!shouldTransformAgain) { + return code + } + const transformResult: IWxTransformResult = wxTransformer({ + code, + sourcePath: sourceFilePath, + outputPath: outputFilePath, + isNormal: true, + isTyped: false, + adapter, + env: constantsReplaceList + }) + const res = parseAst(PARSE_AST_TYPE.NORMAL, transformResult.ast, [], sourceFilePath, outputFilePath) + return res.code +} diff --git a/packages/taro-cli/src/mini/compileStyle.ts b/packages/taro-cli/src/mini/compileStyle.ts new file mode 100644 index 000000000000..023b5ce654c3 --- /dev/null +++ b/packages/taro-cli/src/mini/compileStyle.ts @@ -0,0 +1,241 @@ +import * as fs from 'fs-extra' +import * as path from 'path' + +import * as autoprefixer from 'autoprefixer' +import * as postcss from 'postcss' +import * as pxtransform from 'postcss-pxtransform' +import * as cssUrlParse from 'postcss-url' +import * as Scope from 'postcss-modules-scope' +import * as Values from 'postcss-modules-values' +import * as LocalByDefault from 'postcss-modules-local-by-default' +import * as ExtractImports from 'postcss-modules-extract-imports' +import * as ResolveImports from 'postcss-modules-resolve-imports' + +import browserList from '../config/browser_list' +import { + resolveNpmPkgMainPath, + resolveNpmFilesPath +} from '../util/resolve_npm_files' +import { + callPlugin, callPluginSync +} from '../util/npm' +import { + isNpmPkg, + processStyleImports, + promoteRelativePath +} from '../util' +import { CSS_EXT, FILE_PROCESSOR_MAP } from '../util/constants' +import { IMiniAppConfig } from '../util/types' + +import { + getBuildData +} from './helper' +import { DEVICE_RATIO_NAME } from './constants' + +const genericNames = require('generic-names') + +interface IStyleObj { + css: string, + filePath: string +} + +const appPath = process.cwd() +const isBuildingStyles: Map = new Map() + +export function initCompileStyles () { + isBuildingStyles.clear() +} + +/** + * css module processor + * @param styleObj { css: string, filePath: '' } + * @returns postcss.process() + */ +export function processStyleUseCssModule (styleObj: IStyleObj): any { + const { projectConfig } = getBuildData() + const weappConf = Object.assign({}, projectConfig.weapp) + const useModuleConf = weappConf.module || {} + const customPostcssConf = useModuleConf.postcss || {} + const customCssModulesConf = Object.assign({ + enable: false, + config: { + generateScopedName: '[name]__[local]___[hash:base64:5]', + namingPattern: 'global' + } + }, customPostcssConf.cssModules || {}) + if (!customCssModulesConf.enable) { + return styleObj + } + const namingPattern = customCssModulesConf.config.namingPattern + if (namingPattern === 'module') { + // 只对 xxx.module.[css|scss|less|styl] 等样式文件做处理 + const DO_USE_CSS_MODULE_REGEX = /^(.*\.module).*\.(css|scss|less|styl)$/ + if (!DO_USE_CSS_MODULE_REGEX.test(styleObj.filePath)) return styleObj + } else { + // 对 xxx.global.[css|scss|less|styl] 等样式文件不做处理 + const DO_NOT_USE_CSS_MODULE_REGEX = /^(.*\.global).*\.(css|scss|less|styl)$/ + if (DO_NOT_USE_CSS_MODULE_REGEX.test(styleObj.filePath)) return styleObj + } + const generateScopedName = customCssModulesConf.config.generateScopedName + const context = process.cwd() + let scopedName + if (generateScopedName) { + scopedName = genericNames(generateScopedName, { context }) + } else { + scopedName = (local, filename) => Scope.generateScopedName(local, path.relative(context, filename)) + } + const postcssPlugins = [ + Values, + LocalByDefault, + ExtractImports, + new Scope({ generateScopedName: scopedName }), + new ResolveImports({ resolve: Object.assign({}, { extensions: CSS_EXT }) }) + ] + const runner = postcss(postcssPlugins) + const result = runner.process(styleObj.css, Object.assign({}, { from: styleObj.filePath })) + return result +} + +async function processStyleWithPostCSS (styleObj: IStyleObj): Promise { + const { projectConfig, npmConfig, isProduction, buildAdapter } = getBuildData() + const weappConf = Object.assign({}, projectConfig.weapp) + const useModuleConf = weappConf.module || {} + const customPostcssConf = useModuleConf.postcss || {} + const customCssModulesConf = Object.assign({ + enable: false, + config: { + generateScopedName: '[name]__[local]___[hash:base64:5]' + } + }, customPostcssConf.cssModules || {}) + const customPxtransformConf = Object.assign({ + enable: true, + config: {} + }, customPostcssConf.pxtransform || {}) + const customUrlConf = Object.assign({ + enable: true, + config: { + limit: 10240 + } + }, customPostcssConf.url || {}) + const customAutoprefixerConf = Object.assign({ + enable: true, + config: { + browsers: browserList + } + }, customPostcssConf.autoprefixer || {}) + const postcssPxtransformOption = { + designWidth: projectConfig.designWidth || 750, + platform: 'weapp' + } + + if (projectConfig.hasOwnProperty(DEVICE_RATIO_NAME)) { + postcssPxtransformOption[DEVICE_RATIO_NAME] = projectConfig.deviceRatio + } + const cssUrlConf = Object.assign({ limit: 10240 }, customUrlConf) + const maxSize = Math.round((customUrlConf.config.limit || cssUrlConf.limit) / 1024) + const postcssPxtransformConf = Object.assign({}, postcssPxtransformOption, customPxtransformConf, customPxtransformConf.config) + const processors: any[] = [] + if (customAutoprefixerConf.enable) { + processors.push(autoprefixer(customAutoprefixerConf.config)) + } + if (customPxtransformConf.enable) { + processors.push(pxtransform(postcssPxtransformConf)) + } + if (cssUrlConf.enable) { + processors.push(cssUrlParse({ + url: 'inline', + maxSize, + encodeType: 'base64' + })) + } + + const defaultPostCSSPluginNames = ['autoprefixer', 'pxtransform', 'url', 'cssModules'] + Object.keys(customPostcssConf).forEach(pluginName => { + if (defaultPostCSSPluginNames.indexOf(pluginName) < 0) { + const pluginConf = customPostcssConf[pluginName] + if (pluginConf && pluginConf.enable) { + if (!isNpmPkg(pluginName)) { // local plugin + pluginName = path.join(appPath, pluginName) + } + processors.push(require(resolveNpmPkgMainPath(pluginName, isProduction, npmConfig, buildAdapter))(pluginConf.config || {})) + } + } + }) + let css = styleObj.css + if (customCssModulesConf.enable) { + css = processStyleUseCssModule(styleObj).css + } + const postcssResult = await postcss(processors).process(css, { + from: styleObj.filePath + }) + return postcssResult.css +} + +function compileImportStyles (filePath: string, importStyles: string[]) { + const { sourceDir, outputDir } = getBuildData() + if (importStyles.length) { + importStyles.forEach(async importItem => { + const importFilePath = path.resolve(filePath, '..', importItem) + if (fs.existsSync(importFilePath)) { + await compileDepStyles(importFilePath.replace(sourceDir, outputDir), [importFilePath]) + } + }) + } +} + +export function compileDepStyles (outputFilePath: string, styleFiles: string[]) { + if (isBuildingStyles.get(outputFilePath)) { + return Promise.resolve({}) + } + const { projectConfig, npmConfig, isProduction, buildAdapter } = getBuildData() + const pluginsConfig = projectConfig.plugins || {} + const weappConf = projectConfig.weapp || {} as IMiniAppConfig + const useCompileConf = Object.assign({}, weappConf.compile) + const compileInclude = useCompileConf.include || [] + isBuildingStyles.set(outputFilePath, true) + return Promise.all(styleFiles.map(async p => { + const filePath = path.join(p) + const fileExt = path.extname(filePath) + const pluginName = FILE_PROCESSOR_MAP[fileExt] + const fileContent = fs.readFileSync(filePath).toString() + const cssImportsRes = processStyleImports(fileContent, buildAdapter, (str, stylePath) => { + if (stylePath.indexOf('~') === 0) { + let newStylePath = stylePath + newStylePath = stylePath.replace('~', '') + const npmInfo = resolveNpmFilesPath(newStylePath, isProduction, npmConfig, buildAdapter, appPath, compileInclude) + const importRelativePath = promoteRelativePath(path.relative(filePath, npmInfo.main)) + return str.replace(stylePath, importRelativePath) + } + return str + }) + compileImportStyles(filePath, cssImportsRes.imports) + if (pluginName) { + return callPlugin(pluginName, cssImportsRes.content, filePath, pluginsConfig[pluginName] || {}) + .then(res => ({ + css: cssImportsRes.style.join('\n') + '\n' + res.css, + filePath + })) + } + return new Promise(resolve => { + resolve({ + css: cssImportsRes.style.join('\n') + '\n' + cssImportsRes.content, + filePath + }) + }) + })).then(async resList => { + Promise.all(resList.map(res => processStyleWithPostCSS(res))) + .then(cssList => { + let resContent = cssList.map(res => res).join('\n') + if (isProduction) { + const cssoPuginConfig = pluginsConfig.csso || { enable: true } + if (cssoPuginConfig.enable) { + const cssoConfig = cssoPuginConfig.config || {} + const cssoResult = callPluginSync('csso', resContent, outputFilePath, cssoConfig) + resContent = cssoResult.css + } + } + fs.ensureDirSync(path.dirname(outputFilePath)) + fs.writeFileSync(outputFilePath, resContent) + }) + }) +} diff --git a/packages/taro-cli/src/mini/component.ts b/packages/taro-cli/src/mini/component.ts new file mode 100644 index 000000000000..451990d1c265 --- /dev/null +++ b/packages/taro-cli/src/mini/component.ts @@ -0,0 +1,327 @@ +import * as fs from 'fs-extra' +import * as path from 'path' + +import { Config as IConfig } from '@tarojs/taro' +import * as wxTransformer from '@tarojs/transformer-wx' +import * as _ from 'lodash' +import traverse from 'babel-traverse' + +import { IWxTransformResult } from '../util/types' +import { + REG_TYPESCRIPT, + processTypeEnum +} from '../util/constants' +import { + printLog, + isEmptyObject, + promoteRelativePath, + isDifferentArray +} from '../util' + +import { parseComponentExportAst, parseAst } from './astProcess' +import { IComponentObj, IBuildResult } from './interface' +import { + setHasBeenBuiltComponents, + isComponentHasBeenBuilt, + getBuildData, + setComponentExportsMap, + getComponentExportsMap, + getRealComponentsPathList, + uglifyJS, + copyFilesFromSrcToOutput, + getComponentsBuildResult, + getDependencyTree, + buildUsingComponents, + getDepComponents +} from './helper' +import { compileScriptFile, compileDepScripts } from './compileScript' +import { compileDepStyles } from './compileStyle' +import { transfromNativeComponents, processNativeWxml } from './native' +import { PARSE_AST_TYPE, NODE_MODULES_REG, NODE_MODULES } from './constants' + +const notTaroComponents = new Set() +const componentsNamedMap = new Map() + +export function getComponentsNamedMap () { + return componentsNamedMap +} + +export function isFileToBeTaroComponent ( + code: string, + sourcePath: string, + outputPath: string +) { + const { + buildAdapter, + constantsReplaceList + } = getBuildData() + const transformResult: IWxTransformResult = wxTransformer({ + code, + sourcePath: sourcePath, + outputPath: outputPath, + isNormal: true, + isTyped: REG_TYPESCRIPT.test(sourcePath), + adapter: buildAdapter, + env: constantsReplaceList + }) + const { ast }: IWxTransformResult = transformResult + let isTaroComponent = false + + traverse(ast, { + ClassDeclaration (astPath) { + astPath.traverse({ + ClassMethod (astPath) { + if (astPath.get('key').isIdentifier({ name: 'render' })) { + astPath.traverse({ + JSXElement () { + isTaroComponent = true + } + }) + } + } + }) + }, + + ClassExpression (astPath) { + astPath.traverse({ + ClassMethod (astPath) { + if (astPath.get('key').isIdentifier({ name: 'render' })) { + astPath.traverse({ + JSXElement () { + isTaroComponent = true + } + }) + } + } + }) + } + }) + + return { + isTaroComponent, + transformResult + } +} + +export interface IComponentBuildConfig { + outputDir?: string, + outputDirName?: string, + npmSkip?: boolean +} + +export function buildDepComponents ( + componentPathList: IComponentObj[], + buildConfig?: IComponentBuildConfig +): Promise { + return Promise.all(componentPathList.map(componentObj => buildSingleComponent(componentObj, buildConfig))) +} + +export async function buildSingleComponent ( + componentObj: IComponentObj, + buildConfig: IComponentBuildConfig = {} +): Promise { + const componentsBuildResult = getComponentsBuildResult() + if (isComponentHasBeenBuilt(componentObj.path as string) && componentsBuildResult[componentObj.path as string]) { + return componentsBuildResult[componentObj.path as string] + } + const { + appPath, + buildAdapter, + constantsReplaceList, + sourceDir, + outputDir, + sourceDirName, + outputDirName, + npmOutputDir, + nodeModulesPath, + outputFilesTypes, + isProduction + } = getBuildData() + + if (componentObj.path) { + componentsNamedMap.set(componentObj.path, { + name: componentObj.name, + type: componentObj.type + }) + } + const component = componentObj.path + if (!component) { + printLog(processTypeEnum.ERROR, '组件错误', `组件${_.upperFirst(_.camelCase(componentObj.name))}路径错误,请检查!(可能原因是导出的组件名不正确)`) + return { + js: '', + wxss: '', + wxml: '' + } + } + let componentShowPath = component.replace(appPath + path.sep, '') + componentShowPath = componentShowPath.split(path.sep).join('/') + let isComponentFromNodeModules = false + let sourceDirPath = sourceDir + let buildOutputDir = outputDir + // 来自 node_modules 的组件 + if (NODE_MODULES_REG.test(componentShowPath)) { + isComponentFromNodeModules = true + sourceDirPath = nodeModulesPath + buildOutputDir = npmOutputDir + } + let outputComponentShowPath = componentShowPath.replace(isComponentFromNodeModules ? NODE_MODULES : sourceDirName, buildConfig.outputDirName || outputDirName) + outputComponentShowPath = outputComponentShowPath.replace(path.extname(outputComponentShowPath), '') + printLog(processTypeEnum.COMPILE, '组件文件', componentShowPath) + const componentContent = fs.readFileSync(component).toString() + const outputComponentJSPath = component.replace(sourceDirPath, buildConfig.outputDir || buildOutputDir).replace(path.extname(component), outputFilesTypes.SCRIPT) + const outputComponentWXMLPath = outputComponentJSPath.replace(path.extname(outputComponentJSPath), outputFilesTypes.TEMPL) + const outputComponentWXSSPath = outputComponentJSPath.replace(path.extname(outputComponentJSPath), outputFilesTypes.STYLE) + const outputComponentJSONPath = outputComponentJSPath.replace(path.extname(outputComponentJSPath), outputFilesTypes.CONFIG) + if (!isComponentHasBeenBuilt(component)) { + setHasBeenBuiltComponents(component) + } + try { + const isTaroComponentRes = isFileToBeTaroComponent(componentContent, component, outputComponentJSPath) + const componentExportsMap = getComponentExportsMap() + if (!isTaroComponentRes.isTaroComponent) { + const transformResult = isTaroComponentRes.transformResult + const componentRealPath = parseComponentExportAst(transformResult.ast, componentObj.name as string, component, componentObj.type as string) + const realComponentObj: IComponentObj = { + path: componentRealPath, + name: componentObj.name, + type: componentObj.type + } + let isInMap = false + notTaroComponents.add(component) + if (!isEmptyObject(componentExportsMap)) { + Object.keys(componentExportsMap).forEach(key => { + componentExportsMap[key].forEach(item => { + if (item.path === component) { + isInMap = true + item.path = componentRealPath + } + }) + }) + } + if (!isInMap) { + const componentExportsMapItem = componentExportsMap.get(component) || [] + componentExportsMapItem.push(realComponentObj) + setComponentExportsMap(component, componentExportsMapItem) + } + return await buildSingleComponent(realComponentObj, buildConfig) + } + const transformResult: IWxTransformResult = wxTransformer({ + code: componentContent, + sourcePath: component, + outputPath: outputComponentJSPath, + isRoot: false, + isTyped: REG_TYPESCRIPT.test(component), + isNormal: false, + adapter: buildAdapter, + env: constantsReplaceList + }) + const componentWXMLContent = isProduction ? transformResult.compressedTemplate : transformResult.template + const componentDepComponents = transformResult.components + const res = parseAst(PARSE_AST_TYPE.COMPONENT, transformResult.ast, componentDepComponents, component, outputComponentJSPath, buildConfig.npmSkip) + let resCode = res.code + resCode = await compileScriptFile(resCode, component, outputComponentJSPath, buildAdapter) + fs.ensureDirSync(path.dirname(outputComponentJSPath)) + if (isProduction) { + uglifyJS(resCode, component) + } + const { usingComponents = {} }: IConfig = res.configObj + if (usingComponents && !isEmptyObject(usingComponents)) { + const keys = Object.keys(usingComponents) + keys.forEach(item => { + componentDepComponents.forEach(component => { + if (_.camelCase(item) === _.camelCase(component.name)) { + delete usingComponents[item] + } + }) + }) + transfromNativeComponents(outputComponentJSONPath.replace(buildConfig.outputDir || buildOutputDir, sourceDirPath), res.configObj) + } + const dependencyTree = getDependencyTree() + const fileDep = dependencyTree.get(component) || {} + // 编译依赖的组件文件 + let realComponentsPathList: IComponentObj[] = [] + if (componentDepComponents.length) { + realComponentsPathList = getRealComponentsPathList(component, componentDepComponents) + res.scriptFiles = res.scriptFiles.map(item => { + for (let i = 0; i < realComponentsPathList.length; i++) { + const componentObj = realComponentsPathList[i] + const componentPath = componentObj.path + if (item === componentPath) { + return '' + } + } + return item + }).filter(item => item) + realComponentsPathList = realComponentsPathList.filter(item => isComponentHasBeenBuilt(item.path as string) || notTaroComponents.has(item.path as string)) + await buildDepComponents(realComponentsPathList) + } + if (!isEmptyObject(componentExportsMap) && realComponentsPathList.length) { + const mapKeys = Object.keys(componentExportsMap) + realComponentsPathList.forEach(componentObj => { + if (mapKeys.indexOf(componentObj.path as string) >= 0) { + const componentMap = componentExportsMap[componentObj.path as string] + componentMap.forEach(componentObj => { + componentDepComponents.forEach(depComponent => { + if (depComponent.name === componentObj.name) { + let componentPath = componentObj.path + let realPath + if (NODE_MODULES_REG.test(componentPath)) { + componentPath = componentPath.replace(nodeModulesPath, npmOutputDir) + realPath = promoteRelativePath(path.relative(outputComponentJSPath, componentPath)) + } else { + realPath = promoteRelativePath(path.relative(component, componentPath)) + } + depComponent.path = realPath.replace(path.extname(realPath), '') + } + }) + }) + } + }) + } + fs.writeFileSync(outputComponentJSONPath, JSON.stringify(_.merge({}, buildUsingComponents(component, componentDepComponents, true), res.configObj), null, 2)) + printLog(processTypeEnum.GENERATE, '组件配置', `${outputDirName}/${outputComponentShowPath}${outputFilesTypes.CONFIG}`) + fs.writeFileSync(outputComponentJSPath, resCode) + printLog(processTypeEnum.GENERATE, '组件逻辑', `${outputDirName}/${outputComponentShowPath}${outputFilesTypes.SCRIPT}`) + fs.writeFileSync(outputComponentWXMLPath, componentWXMLContent) + processNativeWxml(outputComponentWXMLPath.replace(outputDir, sourceDir), componentWXMLContent, outputComponentWXMLPath) + printLog(processTypeEnum.GENERATE, '组件模板', `${outputDirName}/${outputComponentShowPath}${outputFilesTypes.TEMPL}`) + // 编译依赖的脚本文件 + if (isDifferentArray(fileDep['script'], res.scriptFiles)) { + compileDepScripts(res.scriptFiles) + } + const depComponents = getDepComponents() + // 编译样式文件 + if (isDifferentArray(fileDep['style'], res.styleFiles) || isDifferentArray(depComponents.get(component) || [], componentDepComponents)) { + printLog(processTypeEnum.GENERATE, '组件样式', `${outputDirName}/${outputComponentShowPath}${outputFilesTypes.STYLE}`) + await compileDepStyles(outputComponentWXSSPath, res.styleFiles) + } + // 拷贝依赖文件 + if (isDifferentArray(fileDep['json'], res.jsonFiles)) { + copyFilesFromSrcToOutput(res.jsonFiles) + } + if (isDifferentArray(fileDep['media'], res.mediaFiles)) { + copyFilesFromSrcToOutput(res.mediaFiles) + } + fileDep['style'] = res.styleFiles + fileDep['script'] = res.scriptFiles + fileDep['json'] = res.jsonFiles + fileDep['media'] = res.mediaFiles + dependencyTree[component] = fileDep + depComponents.set(component, componentDepComponents) + const buildResult = { + js: outputComponentJSPath, + wxss: outputComponentWXSSPath, + wxml: outputComponentWXMLPath + } + componentsBuildResult.set(component, buildResult) + return buildResult + } catch (err) { + printLog(processTypeEnum.ERROR, '组件编译', `组件${componentShowPath}编译失败!`) + console.log(err) + return { + js: '', + wxss: '', + wxml: '' + } + } +} diff --git a/packages/taro-cli/src/mini/constants.ts b/packages/taro-cli/src/mini/constants.ts new file mode 100644 index 000000000000..13c44e0d256d --- /dev/null +++ b/packages/taro-cli/src/mini/constants.ts @@ -0,0 +1,18 @@ +import * as os from 'os' + +export const taroJsFramework = '@tarojs/taro' +export const taroJsComponents = '@tarojs/components' +export const taroJsRedux = '@tarojs/redux' + +export const NODE_MODULES = 'node_modules' +export const NODE_MODULES_REG = /(.*)node_modules/ + +export enum PARSE_AST_TYPE { + ENTRY = 'ENTRY', + PAGE = 'PAGE', + COMPONENT = 'COMPONENT', + NORMAL = 'NORMAL' +} + +export const DEVICE_RATIO_NAME = 'deviceRatio' +export const isWindows = os.platform() === 'win32' diff --git a/packages/taro-cli/src/mini/copy.ts b/packages/taro-cli/src/mini/copy.ts new file mode 100644 index 000000000000..4458c810f76e --- /dev/null +++ b/packages/taro-cli/src/mini/copy.ts @@ -0,0 +1,20 @@ +import * as fs from 'fs-extra' +import * as path from 'path' + +import { ICopyOptions } from './interface' + +export function copyFileSync (from: string, to: string, options?: ICopyOptions) { + const filename = path.basename(from) + if (fs.statSync(from).isFile() && !path.extname(to)) { + fs.ensureDir(to) + if (from === path.join(to, filename)) { + return + } + return fs.copySync(from, path.join(to, filename), options) + } + if (from === to) { + return + } + fs.ensureDir(path.dirname(to)) + return fs.copySync(from, to, options) +} diff --git a/packages/taro-cli/src/mini/entry.ts b/packages/taro-cli/src/mini/entry.ts new file mode 100644 index 000000000000..feb0b6209535 --- /dev/null +++ b/packages/taro-cli/src/mini/entry.ts @@ -0,0 +1,179 @@ +import * as fs from 'fs-extra' +import * as path from 'path' + +import { AppConfig } from '@tarojs/taro' +import * as wxTransformer from '@tarojs/transformer-wx' + +import { + REG_SCRIPTS, + REG_TYPESCRIPT, + CONFIG_MAP, + processTypeEnum +} from '../util/constants' +import { + isDifferentArray, + printLog, + isEmptyObject, + resolveScriptPath +} from '../util' +import { IWxTransformResult } from '../util/types' + +import { getBuildData, uglifyJS, copyFilesFromSrcToOutput, getDependencyTree } from './helper' +import { PARSE_AST_TYPE } from './constants' +import { compileDepScripts, compileScriptFile } from './compileScript' +import { compileDepStyles } from './compileStyle' +import { parseAst } from './astProcess' +import { buildSingleComponent } from './component' + +async function buildCustomTabbar () { + const { + sourceDir + } = getBuildData() + const customTabbarPath = path.join(sourceDir, 'custom-tab-bar') + const customTabbarJSPath = resolveScriptPath(customTabbarPath) + await buildSingleComponent({ + path: customTabbarJSPath, + name: 'custom-tab-bar' + }) +} + +function buildWorkers (worker: string) { + const { + sourceDir + } = getBuildData() + printLog(processTypeEnum.COMPILE, 'Workers', '编译 worker 相关文件') + const workerDir = path.join(sourceDir, worker) + function fileRecursiveSearch (fileDir) { + fs.readdir(fileDir, (err, files) => { + if (err) { + console.warn(err) + } else { + files.forEach(filename => { + const filePath = path.join(fileDir, filename) + fs.stat(filePath, (err, stats) => { + if (err) { + console.warn(err) + } else { + const isFile = stats.isFile() + const isDir = stats.isDirectory() + if (isFile) { + if (REG_SCRIPTS.test(filePath)) { + compileDepScripts([filePath]) + } else { + copyFilesFromSrcToOutput([filePath]) + } + } else if (isDir) { + fileRecursiveSearch(filePath) + } + } + }) + }) + } + }) + } + fileRecursiveSearch(workerDir) +} + +export async function buildEntry (): Promise { + const { + buildAdapter, + constantsReplaceList, + entryFilePath, + sourceDir, + outputDir, + entryFileName, + sourceDirName, + outputDirName, + projectConfig, + outputFilesTypes, + isProduction + } = getBuildData() + const weappConf = projectConfig.weapp || { appOutput: true} + const appOutput = typeof weappConf.appOutput === 'boolean' ? weappConf.appOutput : true + const entryFileCode = fs.readFileSync(entryFilePath).toString() + const outputEntryFilePath = path.join(outputDir, entryFileName) + + printLog(processTypeEnum.COMPILE, '入口文件', `${sourceDirName}/${entryFileName}`) + try { + const transformResult: IWxTransformResult = wxTransformer({ + code: entryFileCode, + sourcePath: entryFilePath, + outputPath: outputEntryFilePath, + isApp: true, + isTyped: REG_TYPESCRIPT.test(entryFilePath), + adapter: buildAdapter, + env: constantsReplaceList + }) + // app.js的template忽略 + const res = parseAst(PARSE_AST_TYPE.ENTRY, transformResult.ast, [], entryFilePath, outputEntryFilePath) + let resCode = res.code + resCode = await compileScriptFile(resCode, entryFilePath, outputEntryFilePath, buildAdapter) + if (isProduction) { + resCode = uglifyJS(resCode, entryFilePath) + } + if (appOutput) { + fs.writeFileSync(path.join(outputDir, 'app.json'), JSON.stringify(res.configObj, null, 2)) + printLog(processTypeEnum.GENERATE, '入口配置', `${outputDirName}/app.json`) + fs.writeFileSync(path.join(outputDir, 'app.js'), resCode) + printLog(processTypeEnum.GENERATE, '入口文件', `${outputDirName}/app.js`) + } + if (res.configObj.workers) { + buildWorkers(res.configObj.workers) + } + if (res.configObj.tabBar && res.configObj.tabBar.custom) { + await buildCustomTabbar() + } + const dependencyTree = getDependencyTree() + const fileDep = dependencyTree.get(entryFilePath) || { + style: [], + script: [], + json: [], + media: [] + } + // 编译依赖的脚本文件 + if (isDifferentArray(fileDep['script'], res.scriptFiles)) { + compileDepScripts(res.scriptFiles) + } + // 编译样式文件 + if (isDifferentArray(fileDep['style'], res.styleFiles) && appOutput) { + await compileDepStyles(path.join(outputDir, `app${outputFilesTypes.STYLE}`), res.styleFiles) + printLog(processTypeEnum.GENERATE, '入口样式', `${outputDirName}/app${outputFilesTypes.STYLE}`) + } + // 拷贝依赖文件 + if (isDifferentArray(fileDep['json'], res.jsonFiles)) { + copyFilesFromSrcToOutput(res.jsonFiles) + } + + // 处理res.configObj 中的tabBar配置 + const tabBar = res.configObj.tabBar + if (tabBar && typeof tabBar === 'object' && !isEmptyObject(tabBar)) { + const { + list: listConfig, + iconPath: pathConfig, + selectedIconPath: selectedPathConfig + } = CONFIG_MAP[buildAdapter] + const list = tabBar[listConfig] || [] + let tabBarIcons: string[] = [] + list.forEach(item => { + item[pathConfig] && tabBarIcons.push(item[pathConfig]) + item[selectedPathConfig] && tabBarIcons.push(item[selectedPathConfig]) + }) + tabBarIcons = tabBarIcons.map(item => path.resolve(sourceDir, item)) + if (tabBarIcons && tabBarIcons.length) { + res.mediaFiles = res.mediaFiles.concat(tabBarIcons) + } + } + if (isDifferentArray(fileDep['media'], res.mediaFiles)) { + copyFilesFromSrcToOutput(res.mediaFiles) + } + fileDep['style'] = res.styleFiles + fileDep['script'] = res.scriptFiles + fileDep['json'] = res.jsonFiles + fileDep['media'] = res.mediaFiles + dependencyTree.set(entryFilePath, fileDep) + return res.configObj + } catch (err) { + console.log(err) + return {} + } +} diff --git a/packages/taro-cli/src/mini/helper.ts b/packages/taro-cli/src/mini/helper.ts new file mode 100644 index 000000000000..67311c362048 --- /dev/null +++ b/packages/taro-cli/src/mini/helper.ts @@ -0,0 +1,326 @@ +import * as fs from 'fs-extra' +import * as path from 'path' + +import * as _ from 'lodash' +import { AppConfig } from '@tarojs/taro' + +import { + BUILD_TYPES, + MINI_APP_FILES, + IMINI_APP_FILE_TYPE, + PROJECT_CONFIG, + processTypeEnum, + REG_SCRIPTS +} from '../util/constants' +import { + resolveScriptPath, + isAliasPath, + replaceAliasPath, + promoteRelativePath, + isNpmPkg, + printLog, + generateEnvList, + generateConstantsList, + isEmptyObject +} from '../util' +import { callPluginSync } from '../util/npm' +import { resolveNpmPkgMainPath } from '../util/resolve_npm_files' +import { + IProjectConfig, + IOption, + INpmConfig +} from '../util/types' +import defaultBabelConfig from '../config/babel' +import defaultUglifyConfig from '../config/uglify' +import CONFIG from '../config' + +import { + IComponentObj, + IBuildResult, + IDependency +} from './interface' +import { NODE_MODULES_REG } from './constants' +import { getNodeModulesPath, getNpmOutputDir } from './npmExact' + +const appPath = process.cwd() +const configDir = path.join(appPath, PROJECT_CONFIG) +const projectConfig = require(configDir)(_.merge) +const sourceDirName = projectConfig.sourceRoot || CONFIG.SOURCE_DIR +const outputDirName = projectConfig.outputRoot || CONFIG.OUTPUT_DIR +const sourceDir = path.join(appPath, sourceDirName) +const outputDir = path.join(appPath, outputDirName) +const entryFilePath = resolveScriptPath(path.join(sourceDir, CONFIG.ENTRY)) +const entryFileName = path.basename(entryFilePath) + +const plugins = projectConfig.plugins || {} +const pathAlias = projectConfig.alias || {} +const weappConf = projectConfig.weapp || {} +const npmConfig = Object.assign({ + name: CONFIG.NPM_DIR, + dir: null +}, weappConf.npm) +const useCompileConf = Object.assign({}, weappConf.compile) +const compileInclude = useCompileConf.include || [] + +const isCopyingFiles: Map = new Map() +const dependencyTree: Map = new Map() +const hasBeenBuiltComponents: Set = new Set() +const componentExportsMap = new Map() +const componentsBuildResult = new Map() +const depComponents = new Map() + +export interface IBuildData { + appPath: string, + configDir: string, + sourceDirName: string, + outputDirName: string, + sourceDir: string, + outputDir: string, + entryFilePath: string, + entryFileName: string, + projectConfig: IProjectConfig, + npmConfig: INpmConfig, + appConfig: AppConfig, + alias: IOption, + compileInclude: string[], + isProduction: boolean, + buildAdapter: BUILD_TYPES, + outputFilesTypes: IMINI_APP_FILE_TYPE, + constantsReplaceList: IOption, + nodeModulesPath: string, + npmOutputDir: string +} + +const BuildData: IBuildData = { + appPath, + configDir, + sourceDirName, + outputDirName, + sourceDir, + outputDir, + entryFilePath, + entryFileName, + projectConfig, + npmConfig, + alias: pathAlias, + isProduction: false, + appConfig: {}, + compileInclude, + buildAdapter: BUILD_TYPES.WEAPP, + outputFilesTypes: MINI_APP_FILES[BUILD_TYPES.WEAPP], + constantsReplaceList: {}, + nodeModulesPath: getNodeModulesPath(), + npmOutputDir: getNpmOutputDir(outputDir, configDir, npmConfig) +} + +export const babelConfig = _.mergeWith({}, defaultBabelConfig, plugins.babel, (objValue, srcValue) => { + if (Array.isArray(objValue)) { + return Array.from(new Set(srcValue.concat(objValue))) + } +}) + +export const shouldTransformAgain = (function () { + const pluginsStr = JSON.stringify(babelConfig.plugins) + if (/transform-runtime/.test(pluginsStr)) { + return true + } + return false +})() + +export function setAppConfig (appConfig: AppConfig) { + BuildData.appConfig = appConfig +} + +export function setIsProduction (isProduction: boolean) { + BuildData.isProduction = isProduction +} + +export function setBuildAdapter (adapter: BUILD_TYPES) { + BuildData.buildAdapter = adapter + BuildData.outputFilesTypes = MINI_APP_FILES[adapter] + // 可以自定义输出文件类型 + if (weappConf.customFilesTypes && !isEmptyObject(weappConf.customFilesTypes)) { + BuildData.outputFilesTypes = Object.assign({}, BuildData.outputFilesTypes, weappConf.customFilesTypes[adapter] || {}) + } + BuildData.constantsReplaceList = Object.assign({}, generateEnvList(projectConfig.env || {}), generateConstantsList(projectConfig.defineConstants || {}), { + 'process.env.TARO_ENV': adapter + }) +} + +export function getBuildData (): IBuildData { + return BuildData +} + +export function uglifyJS (resCode: string, filePath: string): string { + const uglifyPluginConfig = plugins.uglify || { enable: true } + if (uglifyPluginConfig.enable) { + const uglifyConfig = Object.assign(defaultUglifyConfig, uglifyPluginConfig.config || {}) + const uglifyResult = callPluginSync('uglifyjs', resCode, filePath, uglifyConfig) + if (uglifyResult.error) { + printLog(processTypeEnum.ERROR, '压缩错误', `文件${filePath}`) + console.log(uglifyResult.error) + return resCode + } + return uglifyResult.code + } + return resCode +} + +export function getDependencyTree (): Map { + return dependencyTree +} + +export function setHasBeenBuiltComponents (componentPath: string) { + hasBeenBuiltComponents.add(componentPath) +} + +export function isComponentHasBeenBuilt (componentPath: string): boolean { + return hasBeenBuiltComponents.has(componentPath) +} + +export function deleteHasBeenBuiltComponent (filePath) { + if (hasBeenBuiltComponents.has(filePath)) { + hasBeenBuiltComponents.delete(filePath) + } +} + +export function setComponentExportsMap (key: string, value: IComponentObj[]) { + componentExportsMap.set(key, value) +} + +export function getComponentExportsMapItem (key: string): IComponentObj[] | void { + return componentExportsMap.get(key) +} + +export function getComponentExportsMap (): Map { + return componentExportsMap +} + +export function getComponentsBuildResult (): Map { + return componentsBuildResult +} + +export function getDepComponents (): Map { + return depComponents +} + +export function buildUsingComponents ( + filePath: string, + components: IComponentObj[], + isComponent?: boolean +): IOption { + const usingComponents = Object.create(null) + for (const component of components) { + let componentPath = component.path + if (isAliasPath(componentPath as string, pathAlias)) { + componentPath = replaceAliasPath(filePath, componentPath as string, pathAlias) + } + componentPath = resolveScriptPath(path.resolve(filePath, '..', componentPath as string)) + if (fs.existsSync(componentPath)) { + componentPath = promoteRelativePath(path.relative(filePath, componentPath)) + } else { + componentPath = component.path + } + if (component.name) { + usingComponents[component.name] = (componentPath as string).replace(path.extname(componentPath as string), '') + } + } + return Object.assign({}, isComponent ? { component: true } : { usingComponents: {} }, components.length ? { + usingComponents + } : {}) +} + +export function getRealComponentsPathList ( + filePath: string, + components: IComponentObj[] +): IComponentObj[] { + const { isProduction, buildAdapter } = BuildData + return components.map(component => { + let componentPath = component.path + if (isAliasPath(componentPath as string, pathAlias)) { + componentPath = replaceAliasPath(filePath, componentPath as string, pathAlias) + } + if (isNpmPkg(componentPath as string)) { + try { + componentPath = resolveNpmPkgMainPath(componentPath as string, isProduction, npmConfig, buildAdapter) + } catch (err) { + console.log(err) + } + } else { + componentPath = path.resolve(path.dirname(filePath), componentPath as string) + componentPath = resolveScriptPath(componentPath) + } + if (componentPath && isFileToBePage(componentPath)) { + printLog(processTypeEnum.ERROR, '组件引用', `文件${component.path}已经在 app.js 中被指定为页面,不能再作为组件来引用!`) + } + return { + path: componentPath, + name: component.name, + type: component.type + } + }) +} + +export function isFileToBePage (filePath: string): boolean { + let isPage = false + const { appConfig, sourceDir } = BuildData + const extname = path.extname(filePath) + const pages = appConfig.pages || [] + const filePathWithoutExt = filePath.replace(extname, '') + pages.forEach(page => { + if (filePathWithoutExt === path.join(sourceDir, page)) { + isPage = true + } + }) + return isPage && REG_SCRIPTS.test(extname) +} + +export function getDepStyleList ( + outputFilePath: string, + buildDepComponentsResult: IBuildResult[] +): string[] { + let depWXSSList: string[] = [] + if (buildDepComponentsResult.length) { + depWXSSList = buildDepComponentsResult.map(item => { + let wxss = item.wxss + wxss = wxss.replace(sourceDir, outputDir) + wxss = promoteRelativePath(path.relative(outputFilePath, wxss)) + return wxss + }) + } + return depWXSSList +} + +export function initCopyFiles () { + isCopyingFiles.clear() +} + +export function copyFilesFromSrcToOutput (files: string[]) { + const { nodeModulesPath, npmOutputDir } = BuildData + files.forEach(file => { + let outputFilePath + if (NODE_MODULES_REG.test(file)) { + outputFilePath = file.replace(nodeModulesPath, npmOutputDir) + } else { + outputFilePath = file.replace(sourceDir, outputDir) + } + if (isCopyingFiles.get(outputFilePath)) { + return + } + isCopyingFiles.set(outputFilePath, true) + let modifySrc = file.replace(appPath + path.sep, '') + modifySrc = modifySrc.split(path.sep).join('/') + let modifyOutput = outputFilePath.replace(appPath + path.sep, '') + modifyOutput = modifyOutput.split(path.sep).join('/') + printLog(processTypeEnum.COPY, '文件', modifyOutput) + if (!fs.existsSync(file)) { + printLog(processTypeEnum.ERROR, '文件', `${modifySrc} 不存在`) + } else { + fs.ensureDir(path.dirname(outputFilePath)) + if (file === outputFilePath) { + return + } + fs.copySync(file, outputFilePath) + } + }) +} diff --git a/packages/taro-cli/src/mini/index.ts b/packages/taro-cli/src/mini/index.ts new file mode 100644 index 000000000000..af15e4b335ad --- /dev/null +++ b/packages/taro-cli/src/mini/index.ts @@ -0,0 +1,151 @@ +import * as fs from 'fs-extra' +import * as path from 'path' + +import chalk from 'chalk' +import * as minimatch from 'minimatch' +import * as _ from 'lodash' + +import { + printLog, + getInstalledNpmPkgVersion, + getPkgVersion +} from '../util' +import { processTypeEnum, BUILD_TYPES } from '../util/constants' +import { IMiniAppBuildConfig } from '../util/types' + +import { + getBuildData, + setIsProduction, + setBuildAdapter, + setAppConfig +} from './helper' +import { ICopyOptions } from './interface' +import { copyFileSync } from './copy' +import { buildEntry } from './entry' +import { buildPages } from './page' +import { watchFiles } from './watch' + +const appPath = process.cwd() + +async function checkCliAndFrameworkVersion () { + const { buildAdapter, nodeModulesPath } = getBuildData() + const frameworkName = `@tarojs/taro-${buildAdapter}` + const frameworkVersion = getInstalledNpmPkgVersion(frameworkName, nodeModulesPath) + if (frameworkVersion) { + if (frameworkVersion !== getPkgVersion()) { + printLog(processTypeEnum.ERROR, '版本问题', `Taro CLI 与本地安装的小程序框架 ${frameworkName} 版本不一致,请确保一致`) + console.log(`Taro CLI: ${getPkgVersion()}`) + console.log(`${frameworkName}: ${frameworkVersion}`) + process.exit(1) + } + } else { + printLog(processTypeEnum.WARNING, '依赖安装', chalk.red(`项目依赖 ${frameworkName} 未安装,或安装有误!`)) + } +} + +function buildProjectConfig () { + const { buildAdapter, sourceDir, outputDir, outputDirName } = getBuildData() + let projectConfigFileName = `project.${buildAdapter}.json` + if (buildAdapter === BUILD_TYPES.WEAPP) { + projectConfigFileName = 'project.config.json' + } + let projectConfigPath = path.join(appPath, projectConfigFileName) + + if (!fs.existsSync(projectConfigPath)) { + projectConfigPath = path.join(sourceDir, projectConfigFileName) + if (!fs.existsSync(projectConfigPath)) return + } + + const origProjectConfig = fs.readJSONSync(projectConfigPath) + if (buildAdapter === BUILD_TYPES.TT) { + projectConfigFileName = 'project.config.json' + } + fs.ensureDirSync(outputDir) + fs.writeFileSync( + path.join(outputDir, projectConfigFileName), + JSON.stringify(Object.assign({}, origProjectConfig, { miniprogramRoot: './' }), null, 2) + ) + printLog(processTypeEnum.GENERATE, '工具配置', `${outputDirName}/${projectConfigFileName}`) +} + +async function buildFrameworkInfo () { + // 百度小程序编译出 .frameworkinfo 文件 + const { + buildAdapter, + outputDir, + outputDirName, + nodeModulesPath, + projectConfig + } = getBuildData() + if (buildAdapter === BUILD_TYPES.SWAN) { + const frameworkInfoFileName = '.frameworkinfo' + const frameworkName = `@tarojs/taro-${buildAdapter}` + const frameworkVersion = getInstalledNpmPkgVersion(frameworkName, nodeModulesPath) + if (frameworkVersion) { + const frameworkinfo = { + toolName: 'Taro', + toolCliVersion: getPkgVersion(), + toolFrameworkVersion: frameworkVersion, + createTime: projectConfig.date ? new Date(projectConfig.date).getTime() : Date.now() + } + fs.writeFileSync( + path.join(outputDir, frameworkInfoFileName), + JSON.stringify(frameworkinfo, null, 2) + ) + printLog(processTypeEnum.GENERATE, '框架信息', `${outputDirName}/${frameworkInfoFileName}`) + } else { + printLog(processTypeEnum.WARNING, '依赖安装', chalk.red(`项目依赖 ${frameworkName} 未安装,或安装有误!`)) + } + } +} + +function copyFiles () { + const { projectConfig } = getBuildData() + const copyConfig = projectConfig.copy || { patterns: [], options: {} } + if (copyConfig.patterns && copyConfig.patterns.length) { + copyConfig.options = copyConfig.options || {} + const globalIgnore = copyConfig.options.ignore + const projectDir = appPath + copyConfig.patterns.forEach(pattern => { + if (typeof pattern === 'object' && pattern.from && pattern.to) { + const from = path.join(projectDir, pattern.from) + const to = path.join(projectDir, pattern.to) + let ignore = pattern.ignore || globalIgnore + if (fs.existsSync(from)) { + const copyOptions: ICopyOptions = {} + if (ignore) { + ignore = Array.isArray(ignore) ? ignore : [ignore] + copyOptions.filter = src => { + let isMatch = false + ignore && ignore.forEach(iPa => { + if (minimatch(path.basename(src), iPa)) { + isMatch = true + } + }) + return !isMatch + } + } + copyFileSync(from, to, copyOptions) + } else { + printLog(processTypeEnum.ERROR, '拷贝失败', `${pattern.from} 文件不存在!`) + } + } + }) + } +} + +export async function build ({ watch, adapter = BUILD_TYPES.WEAPP }: IMiniAppBuildConfig) { + process.env.TARO_ENV = adapter + setIsProduction(process.env.NODE_ENV === 'production' || !watch) + setBuildAdapter(adapter) + await checkCliAndFrameworkVersion() + buildProjectConfig() + await buildFrameworkInfo() + copyFiles() + const appConfig = await buildEntry() + setAppConfig(appConfig) + await buildPages() + if (watch) { + watchFiles() + } +} diff --git a/packages/taro-cli/src/mini/interface.ts b/packages/taro-cli/src/mini/interface.ts new file mode 100644 index 000000000000..92fac4df8d16 --- /dev/null +++ b/packages/taro-cli/src/mini/interface.ts @@ -0,0 +1,29 @@ +import { IWxTransformResult } from '../util/types' + +export interface IComponentObj { + name?: string, + path: string | null, + type?: string +} + +export interface IIsFileToBeTaroComponentReturn { + isTaroComponent: boolean, + transformResult: IWxTransformResult +} + +export interface IBuildResult { + js: string, + wxss: string, + wxml: string +} + +export interface IDependency { + style: string[], + script: string[], + json: string[], + media: string[] +} + +export interface ICopyOptions { + filter?: (src: string) => boolean +} diff --git a/packages/taro-cli/src/mini/native.ts b/packages/taro-cli/src/mini/native.ts new file mode 100644 index 000000000000..1cdf243d5a14 --- /dev/null +++ b/packages/taro-cli/src/mini/native.ts @@ -0,0 +1,106 @@ +import * as fs from 'fs-extra' +import * as path from 'path' + +import { Config as IConfig } from '@tarojs/taro' +import chalk from 'chalk' + +import { REG_WXML_IMPORT, processTypeEnum } from '../util/constants' +import { isEmptyObject, printLog, resolveScriptPath } from '../util' + +import { copyFileSync } from './copy' +import { buildDepComponents } from './component' +import { taroJsFramework } from './constants' +import { compileDepScripts } from './compileScript' +import { compileDepStyles } from './compileStyle' +import { getBuildData } from './helper' + +export function processNativeWxml ( + componentWXMLPath: string, + componentWXMLContent: string | null, + outputComponentWXMLPath: string +) { + let wxmlContent + let needCopy = true + const { sourceDir, outputDir } = getBuildData() + if (componentWXMLPath && fs.existsSync(componentWXMLPath)) { + wxmlContent = fs.readFileSync(componentWXMLPath).toString() + } else { + needCopy = false + wxmlContent = componentWXMLContent + } + const importWxmlPathList: string[] = [] + let regResult + while ((regResult = REG_WXML_IMPORT.exec(wxmlContent)) != null) { + importWxmlPathList.push(regResult[2] || regResult[3]) + } + if (importWxmlPathList.length) { + importWxmlPathList.forEach(item => { + const itemPath = path.resolve(componentWXMLPath, '..', item) + if (fs.existsSync(itemPath)) { + const outputItemPath = itemPath.replace(sourceDir, outputDir) + processNativeWxml(itemPath, null, outputItemPath) + } + }) + } + if (componentWXMLPath === outputComponentWXMLPath || !needCopy) { + return + } + copyFileSync(componentWXMLPath, outputComponentWXMLPath) +} + +export function transfromNativeComponents (configFile: string, componentConfig: IConfig) { + const { sourceDir, outputDir, outputFilesTypes } = getBuildData() + const usingComponents = componentConfig.usingComponents + if (usingComponents && !isEmptyObject(usingComponents)) { + Object.keys(usingComponents).map(async item => { + const componentPath = usingComponents[item] + if (/^plugin:\/\//.test(componentPath)) { + // 小程序 plugin + printLog(processTypeEnum.REFERENCE, '插件引用', `使用了插件 ${chalk.bold(componentPath)}`) + return + } + let componentJSPath = resolveScriptPath(path.resolve(path.dirname(configFile), componentPath)) + if (!fs.existsSync(componentJSPath)) { + componentJSPath = resolveScriptPath(path.join(sourceDir, componentPath)) + } + const componentJSONPath = componentJSPath.replace(path.extname(componentJSPath), outputFilesTypes.CONFIG) + const componentWXMLPath = componentJSPath.replace(path.extname(componentJSPath), outputFilesTypes.TEMPL) + const componentWXSSPath = componentJSPath.replace(path.extname(componentJSPath), outputFilesTypes.STYLE) + const outputComponentJSPath = componentJSPath.replace(sourceDir, outputDir).replace(path.extname(componentJSPath), outputFilesTypes.SCRIPT) + if (fs.existsSync(componentJSPath)) { + const componentJSContent = fs.readFileSync(componentJSPath).toString() + if (componentJSContent.indexOf(taroJsFramework) >= 0 && !fs.existsSync(componentWXMLPath)) { + const buildDepComponentsRes = await buildDepComponents([{ path: componentJSPath, name: item, type: 'default'}]) + return buildDepComponentsRes + } + compileDepScripts([componentJSPath]) + } else { + return printLog(processTypeEnum.ERROR, '编译错误', `原生组件文件 ${componentJSPath} 不存在!`) + } + if (fs.existsSync(componentWXMLPath)) { + const outputComponentWXMLPath = outputComponentJSPath.replace(path.extname(outputComponentJSPath), outputFilesTypes.TEMPL) + processNativeWxml(componentWXMLPath, null, outputComponentWXMLPath) + } + if (fs.existsSync(componentWXSSPath)) { + const outputComponentWXSSPath = outputComponentJSPath.replace(path.extname(outputComponentJSPath), outputFilesTypes.STYLE) + await compileDepStyles(outputComponentWXSSPath, [componentWXSSPath]) + } + if (fs.existsSync(componentJSONPath)) { + const componentJSON = require(componentJSONPath) + const outputComponentJSONPath = outputComponentJSPath.replace(path.extname(outputComponentJSPath), outputFilesTypes.CONFIG) + copyFileSync(componentJSONPath, outputComponentJSONPath) + + // 解决组件循环依赖不断编译爆栈的问题 + if (componentJSON && componentJSON.usingComponents) { + Object.keys(componentJSON.usingComponents).forEach(key => { + if (key === item) { + delete componentJSON.usingComponents[key] + } + }) + } + + transfromNativeComponents(componentJSONPath, componentJSON) + } + }) + } +} diff --git a/packages/taro-cli/src/mini/npmExact.ts b/packages/taro-cli/src/mini/npmExact.ts new file mode 100644 index 000000000000..3309c7d7cd5c --- /dev/null +++ b/packages/taro-cli/src/mini/npmExact.ts @@ -0,0 +1,69 @@ +import * as path from 'path' + +import { resolveNpmFilesPath } from '../util/resolve_npm_files' +import { INpmConfig } from '../util/types' +import { BUILD_TYPES, REG_STYLE } from '../util/constants' +import { promoteRelativePath, recursiveFindNodeModules } from '../util' + +import { NODE_MODULES } from './constants' + +interface IArgs { + npmName: string, + filePath: string, + isProduction: boolean, + npmConfig: INpmConfig, + buildAdapter: BUILD_TYPES, + npmOutputDir: string, + compileInclude: string[] +} +const appPath = process.cwd() +const notExistNpmList: Set = new Set() +const nodeModulesPath = recursiveFindNodeModules(path.join(appPath, NODE_MODULES)) + +export function getNpmOutputDir (outputDir: string, configDir: string, npmConfig: INpmConfig): string { + let npmOutputDir + if (!npmConfig.dir) { + npmOutputDir = path.join(outputDir, npmConfig.name) + } else { + npmOutputDir = path.join(path.resolve(configDir, '..', npmConfig.dir), npmConfig.name) + } + return npmOutputDir +} + +export function getExactedNpmFilePath ({ + npmName, + filePath, + isProduction, + npmConfig, + buildAdapter, + npmOutputDir, + compileInclude +}: IArgs) { + try { + const npmInfo = resolveNpmFilesPath(npmName, isProduction, npmConfig, buildAdapter, appPath, compileInclude) + const npmInfoMainPath = npmInfo.main + let outputNpmPath + if (REG_STYLE.test(npmInfoMainPath)) { + outputNpmPath = npmInfoMainPath + } else { + outputNpmPath = npmInfoMainPath.replace(nodeModulesPath, npmOutputDir) + } + if (buildAdapter === BUILD_TYPES.ALIPAY) { + outputNpmPath = outputNpmPath.replace(/@/g, '_') + } + const relativePath = path.relative(filePath, outputNpmPath) + return promoteRelativePath(relativePath) + } catch (err) { + console.log(err) + notExistNpmList.add(npmName) + return npmName + } +} + +export function getNotExistNpmList () { + return notExistNpmList +} + +export function getNodeModulesPath (): string { + return nodeModulesPath +} diff --git a/packages/taro-cli/src/mini/page.ts b/packages/taro-cli/src/mini/page.ts new file mode 100644 index 000000000000..d912dbbf5fc3 --- /dev/null +++ b/packages/taro-cli/src/mini/page.ts @@ -0,0 +1,218 @@ +import * as fs from 'fs-extra' +import * as path from 'path' + +import { Config as IConfig } from '@tarojs/taro' +import * as wxTransformer from '@tarojs/transformer-wx' +import * as _ from 'lodash' + +import { + REG_TYPESCRIPT, + processTypeEnum +} from '../util/constants' +import { + resolveScriptPath, + printLog, + isEmptyObject, + promoteRelativePath, + isDifferentArray +} from '../util' +import { IWxTransformResult } from '../util/types' + +import { IComponentObj } from './interface' +import { PARSE_AST_TYPE, NODE_MODULES_REG, taroJsFramework } from './constants' +import { copyFileSync } from './copy' +import { + getBuildData, + getRealComponentsPathList, + buildUsingComponents, + uglifyJS, + copyFilesFromSrcToOutput, + getDependencyTree, + getComponentExportsMap, + getDepComponents +} from './helper' +import { compileDepScripts, compileScriptFile } from './compileScript' +import { compileDepStyles } from './compileStyle' +import { transfromNativeComponents, processNativeWxml } from './native' +import { buildDepComponents } from './component' +import { parseAst } from './astProcess' + +// 小程序页面编译 +export async function buildSinglePage (page: string) { + const { + buildAdapter, + constantsReplaceList, + outputDir, + sourceDirName, + outputDirName, + sourceDir, + isProduction, + outputFilesTypes, + nodeModulesPath, + npmOutputDir + } = getBuildData() + const pagePath = path.join(sourceDir, `${page}`) + const pageJs = resolveScriptPath(pagePath) + const dependencyTree = getDependencyTree() + const depComponents = getDepComponents() + + printLog(processTypeEnum.COMPILE, '页面文件', `${sourceDirName}/${page}`) + if (!fs.existsSync(pageJs)) { + printLog(processTypeEnum.ERROR, '页面文件', `${sourceDirName}/${page} 不存在!`) + return + } + const pageJsContent = fs.readFileSync(pageJs).toString() + const outputPageJSPath = pageJs.replace(sourceDir, outputDir).replace(path.extname(pageJs), outputFilesTypes.SCRIPT) + const outputPagePath = path.dirname(outputPageJSPath) + const outputPageJSONPath = outputPageJSPath.replace(path.extname(outputPageJSPath), outputFilesTypes.CONFIG) + const outputPageWXMLPath = outputPageJSPath.replace(path.extname(outputPageJSPath), outputFilesTypes.TEMPL) + const outputPageWXSSPath = outputPageJSPath.replace(path.extname(outputPageJSPath), outputFilesTypes.STYLE) + // 判断是不是小程序原生代码页面 + const pageWXMLPath = pageJs.replace(path.extname(pageJs), outputFilesTypes.TEMPL) + if (fs.existsSync(pageWXMLPath) && pageJsContent.indexOf(taroJsFramework) < 0) { + const pageJSONPath = pageJs.replace(path.extname(pageJs), outputFilesTypes.CONFIG) + const pageWXSSPath = pageJs.replace(path.extname(pageJs), outputFilesTypes.STYLE) + if (fs.existsSync(pageJSONPath)) { + const pageJSON = require(pageJSONPath) + copyFileSync(pageJSONPath, outputPageJSONPath) + transfromNativeComponents(pageJSONPath, pageJSON) + } + compileDepScripts([pageJs]) + copyFileSync(pageWXMLPath, outputPageWXMLPath) + if (fs.existsSync(pageWXSSPath)) { + await compileDepStyles(outputPageWXSSPath, [pageWXSSPath]) + } + return + } + try { + const transformResult: IWxTransformResult = wxTransformer({ + code: pageJsContent, + sourcePath: pageJs, + outputPath: outputPageJSPath, + isRoot: true, + isTyped: REG_TYPESCRIPT.test(pageJs), + adapter: buildAdapter, + env: constantsReplaceList + }) + const pageDepComponents = transformResult.components + const pageWXMLContent = isProduction ? transformResult.compressedTemplate : transformResult.template + const res = parseAst(PARSE_AST_TYPE.PAGE, transformResult.ast, pageDepComponents, pageJs, outputPageJSPath) + let resCode = res.code + resCode = await compileScriptFile(resCode, pageJs, outputPageJSPath, buildAdapter) + if (isProduction) { + uglifyJS(resCode, pageJs) + } + fs.ensureDirSync(outputPagePath) + const { usingComponents = {} }: IConfig = res.configObj + if (usingComponents && !isEmptyObject(usingComponents)) { + const keys = Object.keys(usingComponents) + keys.forEach(item => { + pageDepComponents.forEach(component => { + if (_.camelCase(item) === _.camelCase(component.name)) { + delete usingComponents[item] + } + }) + }) + transfromNativeComponents(outputPageJSONPath.replace(outputDir, sourceDir), res.configObj) + } + const fileDep = dependencyTree.get(pageJs) || {} + // 编译依赖的组件文件 + let realComponentsPathList: IComponentObj[] = [] + if (pageDepComponents.length) { + realComponentsPathList = getRealComponentsPathList(pageJs, pageDepComponents) + res.scriptFiles = res.scriptFiles.map(item => { + for (let i = 0; i < realComponentsPathList.length; i++) { + const componentObj = realComponentsPathList[i] + const componentPath = componentObj.path + if (item === componentPath) { + return '' + } + } + return item + }).filter(item => item) + await buildDepComponents(realComponentsPathList) + } + const componentExportsMap = getComponentExportsMap() + if (!isEmptyObject(componentExportsMap) && realComponentsPathList.length) { + const mapKeys = Object.keys(componentExportsMap) + realComponentsPathList.forEach(component => { + if (mapKeys.indexOf(component.path as string) >= 0) { + const componentMap = componentExportsMap.get(component.path as string) + componentMap && componentMap.forEach(component => { + pageDepComponents.forEach(depComponent => { + if (depComponent.name === component.name) { + let componentPath = component.path + let realPath + if (NODE_MODULES_REG.test(componentPath as string)) { + componentPath = (componentPath as string).replace(nodeModulesPath, npmOutputDir) + realPath = promoteRelativePath(path.relative(outputPageJSPath, componentPath)) + } else { + realPath = promoteRelativePath(path.relative(pageJs, componentPath as string)) + } + depComponent.path = realPath.replace(path.extname(realPath), '') + } + }) + }) + } + }) + } + fs.writeFileSync(outputPageJSONPath, JSON.stringify(_.merge({}, buildUsingComponents(pageJs, pageDepComponents), res.configObj), null, 2)) + printLog(processTypeEnum.GENERATE, '页面配置', `${outputDirName}/${page}${outputFilesTypes.CONFIG}`) + fs.writeFileSync(outputPageJSPath, resCode) + printLog(processTypeEnum.GENERATE, '页面逻辑', `${outputDirName}/${page}${outputFilesTypes.SCRIPT}`) + fs.writeFileSync(outputPageWXMLPath, pageWXMLContent) + processNativeWxml(outputPageWXMLPath.replace(outputDir, sourceDir), pageWXMLContent, outputPageWXMLPath) + printLog(processTypeEnum.GENERATE, '页面模板', `${outputDirName}/${page}${outputFilesTypes.TEMPL}`) + // 编译依赖的脚本文件 + if (isDifferentArray(fileDep['script'], res.scriptFiles)) { + compileDepScripts(res.scriptFiles) + } + // 编译样式文件 + if (isDifferentArray(fileDep['style'], res.styleFiles) || isDifferentArray(depComponents.get(pageJs) || [], pageDepComponents)) { + printLog(processTypeEnum.GENERATE, '页面样式', `${outputDirName}/${page}${outputFilesTypes.STYLE}`) + await compileDepStyles(outputPageWXSSPath, res.styleFiles) + } + // 拷贝依赖文件 + if (isDifferentArray(fileDep['json'], res.jsonFiles)) { + copyFilesFromSrcToOutput(res.jsonFiles) + } + if (isDifferentArray(fileDep['media'], res.mediaFiles)) { + copyFilesFromSrcToOutput(res.mediaFiles) + } + depComponents.set(pageJs, pageDepComponents) + fileDep['style'] = res.styleFiles + fileDep['script'] = res.scriptFiles + fileDep['json'] = res.jsonFiles + fileDep['media'] = res.mediaFiles + dependencyTree[pageJs] = fileDep + } catch (err) { + printLog(processTypeEnum.ERROR, '页面编译', `页面${pagePath}编译失败!`) + console.log(err) + } +} + +export async function buildPages () { + printLog(processTypeEnum.COMPILE, '所有页面') + const { appConfig } = getBuildData() + // 支持分包,解析子包页面 + const pages = appConfig.pages || [] + const subPackages = appConfig.subPackages || appConfig.subpackages + if (subPackages && subPackages.length) { + subPackages.forEach(item => { + if (item.pages && item.pages.length) { + const root = item.root + item.pages.forEach(page => { + let pagePath = `${root}/${page}` + pagePath = pagePath.replace(/\/{2,}/g, '/') + if (pages.indexOf(pagePath) < 0) { + pages.push(pagePath) + } + }) + } + }) + } + const pagesPromises = pages.map(async page => { + return buildSinglePage(page) + }) + await Promise.all(pagesPromises) +} diff --git a/packages/taro-cli/src/mini/watch.ts b/packages/taro-cli/src/mini/watch.ts new file mode 100644 index 000000000000..ef6feba9d5fb --- /dev/null +++ b/packages/taro-cli/src/mini/watch.ts @@ -0,0 +1,202 @@ +import * as path from 'path' + +import * as chokidar from 'chokidar' +import chalk from 'chalk' + +import { + REG_TYPESCRIPT, + REG_SCRIPT, + REG_STYLE, + processTypeEnum +} from '../util/constants' +import { + printLog, + checksum +} from '../util' + +import { initCompileStyles, compileDepStyles } from './compileStyle' +import { initCompileScripts, compileDepScripts } from './compileScript' +import { + initCopyFiles, + getBuildData, + setAppConfig, + isComponentHasBeenBuilt, + deleteHasBeenBuiltComponent, + copyFilesFromSrcToOutput, + getDependencyTree, + isFileToBePage +} from './helper' +import { buildEntry } from './entry' +import { buildPages, buildSinglePage } from './page' +import { buildSingleComponent, getComponentsNamedMap } from './component' +import { isWindows, NODE_MODULES_REG } from './constants' + +export function watchFiles () { + const appPath = process.cwd() + console.log() + console.log(chalk.gray('监听文件修改中...')) + console.log() + initCompileStyles() + initCompileScripts() + initCopyFiles() + const { + sourceDir, + outputDir, + sourceDirName, + projectConfig, + outputFilesTypes, + appConfig, + nodeModulesPath, + npmOutputDir, + entryFileName + } = getBuildData() + const dependencyTree = getDependencyTree() + const watcherPaths = [path.join(sourceDir)].concat(projectConfig.watcher || []) + const watcher = chokidar.watch(watcherPaths, { + ignored: /(^|[/\\])\../, + persistent: true, + ignoreInitial: true + }) + watcher + .on('addDir', dirPath => { + console.log(dirPath) + }) + .on('add', filePath => { + console.log(filePath) + }) + .on('change', async filePath => { + const extname = path.extname(filePath) + const componentsNamedMap = getComponentsNamedMap() + // 编译JS文件 + if (REG_SCRIPT.test(extname) || REG_TYPESCRIPT.test(extname)) { + if (filePath.indexOf(entryFileName) >= 0) { + printLog(processTypeEnum.MODIFY, '入口文件', `${sourceDirName}/${entryFileName}.js`) + const config = await buildEntry() + // TODO 此处待优化 + if ((checksum(JSON.stringify(config.pages)) !== checksum(JSON.stringify(appConfig.pages))) || + (checksum(JSON.stringify(config.subPackages || config.subpackages || {})) !== checksum(JSON.stringify(appConfig.subPackages || appConfig.subpackages || {})))) { + setAppConfig(config) + await buildPages() + } + } else { + const filePathWithoutExt = filePath.replace(extname, '') + if (isFileToBePage(filePath)) { // 编译页面 + filePath = filePathWithoutExt + filePath = filePath.replace(path.join(sourceDir) + path.sep, '') + filePath = filePath.split(path.sep).join('/') + printLog(processTypeEnum.MODIFY, '页面文件', `${sourceDirName}/${filePath}`) + await buildSinglePage(filePath) + } else if (isComponentHasBeenBuilt(filePath)) { // 编译组件 + let outoutShowFilePath = filePath.replace(appPath + path.sep, '') + outoutShowFilePath = outoutShowFilePath.split(path.sep).join('/') + printLog(processTypeEnum.MODIFY, '组件文件', outoutShowFilePath) + deleteHasBeenBuiltComponent(filePath) + + if (isWindows) { + await new Promise((resolve, reject) => { + setTimeout(async () => { + await buildSingleComponent(Object.assign({ + path: filePath + }, componentsNamedMap.get(filePath))) + resolve() + }, 300) + }) + } else { + await buildSingleComponent(Object.assign({ + path: filePath + }, componentsNamedMap.get(filePath))) + } + } else { + let isImported = false + for (const key in dependencyTree) { + const dependencyTreeItem = dependencyTree.get(key) + if (dependencyTreeItem) { + const scripts = dependencyTreeItem.script + if (scripts.indexOf(filePath) >= 0) { + isImported = true + } + } + } + let modifySource = filePath.replace(appPath + path.sep, '') + modifySource = modifySource.split(path.sep).join('/') + if (isImported) { + printLog(processTypeEnum.MODIFY, 'JS文件', modifySource) + compileDepScripts([filePath]) + } else { + printLog(processTypeEnum.WARNING, 'JS文件', `${modifySource} 没有被引用到,不会被编译`) + } + } + } + } else if (REG_STYLE.test(extname)) { + const includeStyleJSPath: any[] = [] + for (const key in dependencyTree) { + const styles = dependencyTree[key]['style'] || [] + styles.forEach(item => { + if (item === filePath) { + includeStyleJSPath.push({ + filePath: key, + styles + }) + } + }) + } + if (includeStyleJSPath.length) { + includeStyleJSPath.forEach(async item => { + let outputWXSSPath = item.filePath.replace(path.extname(item.filePath), outputFilesTypes.STYLE) + let modifySource = outputWXSSPath.replace(appPath + path.sep, '') + modifySource = modifySource.split(path.sep).join('/') + printLog(processTypeEnum.MODIFY, '样式文件', modifySource) + if (NODE_MODULES_REG.test(outputWXSSPath)) { + outputWXSSPath = outputWXSSPath.replace(nodeModulesPath, npmOutputDir) + } else { + outputWXSSPath = outputWXSSPath.replace(sourceDir, outputDir) + } + let modifyOutput = outputWXSSPath.replace(appPath + path.sep, '') + modifyOutput = modifyOutput.split(path.sep).join('/') + if (isWindows) { + await new Promise((resolve, reject) => { + setTimeout(async () => { + await compileDepStyles(outputWXSSPath, item.styles) + resolve() + }, 300) + }) + } else { + await compileDepStyles(outputWXSSPath, item.styles) + } + printLog(processTypeEnum.GENERATE, '样式文件', modifyOutput) + }) + } else { + let outputWXSSPath = filePath.replace(path.extname(filePath), outputFilesTypes.STYLE) + let modifySource = outputWXSSPath.replace(appPath + path.sep, '') + modifySource = modifySource.split(path.sep).join('/') + printLog(processTypeEnum.MODIFY, '样式文件', modifySource) + if (NODE_MODULES_REG.test(outputWXSSPath)) { + outputWXSSPath = outputWXSSPath.replace(nodeModulesPath, npmOutputDir) + } else { + outputWXSSPath = outputWXSSPath.replace(sourceDir, outputDir) + } + let modifyOutput = outputWXSSPath.replace(appPath + path.sep, '') + modifyOutput = modifyOutput.split(path.sep).join('/') + if (isWindows) { + await new Promise((resolve, reject) => { + setTimeout(async () => { + await compileDepStyles(outputWXSSPath, [filePath]) + resolve() + }, 300) + }) + } else { + await compileDepStyles(outputWXSSPath, [filePath]) + } + printLog(processTypeEnum.GENERATE, '样式文件', modifyOutput) + } + } else { + let modifySource = filePath.replace(appPath + path.sep, '') + modifySource = modifySource.split(path.sep).join('/') + printLog(processTypeEnum.MODIFY, '文件', modifySource) + copyFilesFromSrcToOutput([filePath]) + } + initCompileStyles() + initCompileScripts() + initCopyFiles() + }) +} diff --git a/packages/taro-cli/src/project.js b/packages/taro-cli/src/project.ts similarity index 83% rename from packages/taro-cli/src/project.js rename to packages/taro-cli/src/project.ts index 1a3ebcc33fe6..cb2f9fad68a4 100644 --- a/packages/taro-cli/src/project.js +++ b/packages/taro-cli/src/project.ts @@ -1,20 +1,33 @@ -const path = require('path') -const fs = require('fs-extra') -const chalk = require('chalk') -const inquirer = require('inquirer') -const semver = require('semver') +import * as path from 'path' +import * as fs from 'fs-extra' +import chalk from 'chalk' +import * as inquirer from 'inquirer' +import * as semver from 'semver' -const Creator = require('./creator') +import Creator from './creator' -const { +import { shouldUseYarn, shouldUseCnpm, getPkgVersion -} = require('./util') -const { SOURCE_DIR } = require('./config') +} from './util' +import CONFIG from './config' + +interface IProjectConf { + projectName: string, + template: 'default' | 'mobx' | 'redux', + description?: string, + typescript?: boolean, + css: 'none' | 'sass' | 'stylus' | 'less', + date?: string, + src?: string +} + +export default class Project extends Creator { + public rootPath: string + public conf: IProjectConf -class Project extends Creator { - constructor (options) { + constructor (options: IProjectConf) { super() const unSupportedVer = semver.lt(process.version, 'v7.6.0') if (unSupportedVer) { @@ -23,8 +36,8 @@ class Project extends Creator { this.rootPath = this._rootPath this.conf = Object.assign({ - projectName: null, - template: null, + projectName: '', + template: '', description: '' }, options) } @@ -46,7 +59,7 @@ class Project extends Creator { } ask () { - const prompts = [] + const prompts: object[] = [] const conf = this.conf if (typeof conf.projectName !== 'string') { prompts.push({ @@ -158,9 +171,9 @@ class Project extends Creator { return inquirer.prompt(prompts) } - write (cb) { + write (cb?: () => void) { const { template } = this.conf - this.conf.src = SOURCE_DIR + this.conf.src = CONFIG.SOURCE_DIR const templateCreate = require(path.join(this.templatePath(), template, 'index.js')) templateCreate(this, this.conf, { shouldUseYarn, @@ -169,5 +182,3 @@ class Project extends Creator { }, cb) } } - -module.exports = Project diff --git a/packages/taro-cli/src/rn.js b/packages/taro-cli/src/rn.ts similarity index 71% rename from packages/taro-cli/src/rn.js rename to packages/taro-cli/src/rn.ts index ac7a699442c6..afe2bd520a33 100644 --- a/packages/taro-cli/src/rn.js +++ b/packages/taro-cli/src/rn.ts @@ -1,22 +1,22 @@ -const fs = require('fs-extra') -const path = require('path') -const {performance} = require('perf_hooks') -const chokidar = require('chokidar') -const chalk = require('chalk') -const ejs = require('ejs') -const _ = require('lodash') -const shelljs = require('shelljs') -const klaw = require('klaw') - -const Util = require('./util') -const npmProcess = require('./util/npm') -const CONFIG = require('./config') -const {getPkgVersion} = require('./util') -const StyleProcess = require('./rn/styleProcess') -const {transformJSCode} = require('./rn/transformJS') +import * as fs from 'fs-extra' +import * as path from 'path' +import { performance } from 'perf_hooks' +import * as chokidar from 'chokidar' +import chalk from 'chalk' +import * as ejs from 'ejs' +import * as _ from 'lodash' +import * as shelljs from 'shelljs' +import * as klaw from 'klaw' + +import * as Util from './util' +import * as npmProcess from './util/npm' +import CONFIG from './config' +import * as StyleProcess from './rn/styleProcess' +import { parseJSCode as transformJSCode } from './rn/transformJS' +import { PROJECT_CONFIG, processTypeEnum, REG_STYLE, REG_SCRIPTS, REG_TYPESCRIPT } from './util/constants' const appPath = process.cwd() -const projectConfig = require(path.join(appPath, Util.PROJECT_CONFIG))(_.merge) +const projectConfig = require(path.join(appPath, PROJECT_CONFIG))(_.merge) const sourceDirName = projectConfig.sourceRoot || CONFIG.SOURCE_DIR const sourceDir = path.join(appPath, sourceDirName) const tempDir = '.rn_temp' @@ -27,7 +27,9 @@ const pluginsConfig = projectConfig.plugins || {} const pkgPath = path.join(__dirname, './rn/pkg') -let depTree = {} +const depTree: { + [key: string]: string[] +} = {} let isBuildingStyles = {} const styleDenpendencyTree = {} @@ -44,16 +46,16 @@ function compileDepStyles (filePath, styleFiles) { return Promise.all(styleFiles.map(async p => { // to css string const filePath = path.join(p) const fileExt = path.extname(filePath) - Util.printLog(Util.pocessTypeEnum.COMPILE, _.camelCase(fileExt).toUpperCase(), filePath) + Util.printLog(processTypeEnum.COMPILE, _.camelCase(fileExt).toUpperCase(), filePath) return StyleProcess.loadStyle({filePath, pluginsConfig}) })).then(resList => { // postcss return Promise.all(resList.map(item => { - return StyleProcess.postCSS({...item, projectConfig}) + return StyleProcess.postCSS({ ...item as { css: string, filePath: string }, projectConfig }) })) }).then(resList => { - let styleObjectEntire = {} + const styleObjectEntire = {} resList.forEach(item => { - let styleObject = StyleProcess.getStyleObject({css: item.css, filePath: item.filePath}) + const styleObject = StyleProcess.getStyleObject({css: item.css, filePath: item.filePath}) // validate styleObject StyleProcess.validateStyle({styleObject, filePath: item.filePath}) @@ -90,7 +92,7 @@ function initProjectFile () { ejs.render( fs.readFileSync(pkgPath, 'utf-8'), { projectName: projectConfig.projectName, - version: getPkgVersion() + version: Util.getPkgVersion() } ).replace(/(\r\n|\n|\r|\s+)/gm, '') ) @@ -100,11 +102,11 @@ function initProjectFile () { const crnaEntryPath = path.join(path.dirname(npmProcess.resolveNpmSync('@tarojs/rn-runner')), 'src/bin/crna-entry.js') fs.writeFileSync(path.join(tempDir, 'app.json'), JSON.stringify(appJsonObject, null, 2)) - Util.printLog(Util.pocessTypeEnum.GENERATE, 'app.json', path.join(tempPath, 'app.json')) + Util.printLog(processTypeEnum.GENERATE, 'app.json', path.join(tempPath, 'app.json')) fs.writeFileSync(path.join(tempDir, 'package.json'), JSON.stringify(pkgTempObj, null, 2)) - Util.printLog(Util.pocessTypeEnum.GENERATE, 'package.json', path.join(tempPath, 'package.json')) + Util.printLog(processTypeEnum.GENERATE, 'package.json', path.join(tempPath, 'package.json')) fs.copySync(crnaEntryPath, path.join(tempDir, 'bin/crna-entry.js')) - Util.printLog(Util.pocessTypeEnum.COPY, 'crna-entry.js', path.join(tempPath, 'bin/crna-entry.js')) + Util.printLog(processTypeEnum.COPY, 'crna-entry.js', path.join(tempPath, 'bin/crna-entry.js')) } async function processFile (filePath) { @@ -115,15 +117,15 @@ async function processFile (filePath) { const distDirname = dirname.replace(sourceDir, tempDir) let distPath = path.format({dir: distDirname, base: path.basename(filePath)}) const code = fs.readFileSync(filePath, 'utf-8') - if (Util.REG_STYLE.test(filePath)) { + if (REG_STYLE.test(filePath)) { // do something - } else if (Util.REG_SCRIPTS.test(filePath)) { - if (Util.REG_TYPESCRIPT.test(filePath)) { + } else if (REG_SCRIPTS.test(filePath)) { + if (REG_TYPESCRIPT.test(filePath)) { distPath = distPath.replace(/\.(tsx|ts)(\?.*)?$/, '.js') } - Util.printLog(Util.pocessTypeEnum.COMPILE, _.camelCase(path.extname(filePath)).toUpperCase(), filePath) + Util.printLog(processTypeEnum.COMPILE, _.camelCase(path.extname(filePath)).toUpperCase(), filePath) // transformJSCode - let transformResult = transformJSCode({code, filePath, isEntryFile: isEntryFile(filePath), projectConfig}) + const transformResult = transformJSCode({code, filePath, isEntryFile: isEntryFile(filePath), projectConfig}) const jsCode = transformResult.code fs.ensureDirSync(distDirname) fs.writeFileSync(distPath, Buffer.from(jsCode)) @@ -134,7 +136,7 @@ async function processFile (filePath) { } else { fs.ensureDirSync(distDirname) fs.copySync(filePath, distPath) - Util.printLog(Util.pocessTypeEnum.COPY, _.camelCase(path.extname(filePath)).toUpperCase(), filePath) + Util.printLog(processTypeEnum.COPY, _.camelCase(path.extname(filePath)).toUpperCase(), filePath) } } @@ -185,13 +187,13 @@ async function buildDist ({watch}) { rnRunner(rnConfig) } -async function perfWrap (callback, args) { +async function perfWrap (callback, args?) { isBuildingStyles = {} // 清空 // 后期可以优化,不编译全部 - let t0 = performance.now() + const t0 = performance.now() await callback(args) - let t1 = performance.now() - Util.printLog(Util.pocessTypeEnum.COMPILE, `编译完成,花费${Math.round(t1 - t0)} ms`) + const t1 = performance.now() + Util.printLog(processTypeEnum.COMPILE, `编译完成,花费${Math.round(t1 - t0)} ms`) } function watchFiles () { @@ -209,16 +211,16 @@ function watchFiles () { }) .on('add', filePath => { const relativePath = path.relative(appPath, filePath) - Util.printLog(Util.pocessTypeEnum.CREATE, '添加文件', relativePath) + Util.printLog(processTypeEnum.CREATE, '添加文件', relativePath) perfWrap(buildTemp) }) .on('change', filePath => { const relativePath = path.relative(appPath, filePath) - Util.printLog(Util.pocessTypeEnum.MODIFY, '文件变动', relativePath) - if (Util.REG_SCRIPTS.test(filePath)) { + Util.printLog(processTypeEnum.MODIFY, '文件变动', relativePath) + if (REG_SCRIPTS.test(filePath)) { perfWrap(processFile, filePath) } - if (Util.REG_STYLE.test(filePath)) { + if (REG_STYLE.test(filePath)) { _.forIn(depTree, (styleFiles, jsFilePath) => { if (styleFiles.indexOf(filePath) > -1) { perfWrap(processFile, jsFilePath) @@ -228,22 +230,20 @@ function watchFiles () { }) .on('unlink', filePath => { const relativePath = path.relative(appPath, filePath) - Util.printLog(Util.pocessTypeEnum.UNLINK, '删除文件', relativePath) + Util.printLog(processTypeEnum.UNLINK, '删除文件', relativePath) perfWrap(buildTemp) }) .on('error', error => console.log(`Watcher error: ${error}`)) } -async function build ({watch}) { +export async function build ({watch}) { fs.ensureDirSync(tempPath) - let t0 = performance.now() + const t0 = performance.now() await buildTemp() - let t1 = performance.now() - Util.printLog(Util.pocessTypeEnum.COMPILE, `编译完成,花费${Math.round(t1 - t0)} ms`) + const t1 = performance.now() + Util.printLog(processTypeEnum.COMPILE, `编译完成,花费${Math.round(t1 - t0)} ms`) await buildDist({watch}) if (watch) { watchFiles() } } - -module.exports = {build} diff --git a/packages/taro-cli/src/rn/StyleSheet/ColorPropType.js b/packages/taro-cli/src/rn/StyleSheet/ColorPropType.ts similarity index 95% rename from packages/taro-cli/src/rn/StyleSheet/ColorPropType.js rename to packages/taro-cli/src/rn/StyleSheet/ColorPropType.ts index 3fecbc400131..c708dbe8c7b7 100644 --- a/packages/taro-cli/src/rn/StyleSheet/ColorPropType.js +++ b/packages/taro-cli/src/rn/StyleSheet/ColorPropType.ts @@ -9,7 +9,7 @@ 'use strict' -const normalizeColor = require('./normalizeColor') +import normalizeColor from './normalizeColor' const colorPropType = function ( isRequired, @@ -73,4 +73,4 @@ const colorPropType = function ( const ColorPropType = colorPropType.bind(null, false /* isRequired */) ColorPropType.isRequired = colorPropType.bind(null, true /* isRequired */) -module.exports = ColorPropType +export default ColorPropType diff --git a/packages/taro-cli/src/rn/StyleSheet/ImageResizeMode.js b/packages/taro-cli/src/rn/StyleSheet/ImageResizeMode.ts similarity index 93% rename from packages/taro-cli/src/rn/StyleSheet/ImageResizeMode.js rename to packages/taro-cli/src/rn/StyleSheet/ImageResizeMode.ts index 50111bcd0fe7..8281f9a598fa 100644 --- a/packages/taro-cli/src/rn/StyleSheet/ImageResizeMode.js +++ b/packages/taro-cli/src/rn/StyleSheet/ImageResizeMode.ts @@ -7,12 +7,10 @@ * * @format */ -'use strict' - /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error * found when Flow v0.54 was deployed. To see the error delete this comment and * run Flow. */ -const keyMirror = require('fbjs/lib/keyMirror') +import keyMirror from 'fbjs/lib/keyMirror' /** * ImageResizeMode - Enum for different image resizing modes, set via @@ -49,4 +47,4 @@ const ImageResizeMode = keyMirror({ repeat: null }) -module.exports = ImageResizeMode +export default ImageResizeMode diff --git a/packages/taro-cli/src/rn/StyleSheet/ImageStylePropTypes.js b/packages/taro-cli/src/rn/StyleSheet/ImageStylePropTypes.ts similarity index 82% rename from packages/taro-cli/src/rn/StyleSheet/ImageStylePropTypes.js rename to packages/taro-cli/src/rn/StyleSheet/ImageStylePropTypes.ts index 4f687539c583..037b289a5c03 100644 --- a/packages/taro-cli/src/rn/StyleSheet/ImageStylePropTypes.js +++ b/packages/taro-cli/src/rn/StyleSheet/ImageStylePropTypes.ts @@ -9,12 +9,12 @@ */ 'use strict' -const ColorPropType = require('./ColorPropType') -const ImageResizeMode = require('./ImageResizeMode') -const LayoutPropTypes = require('./LayoutPropTypes') -const ReactPropTypes = require('prop-types') -const ShadowPropTypesIOS = require('./ShadowPropTypesIOS') -const TransformPropTypes = require('./TransformPropTypes') +import ColorPropType from './ColorPropType' +import ImageResizeMode from './ImageResizeMode' +import LayoutPropTypes from './LayoutPropTypes' +import ReactPropTypes from 'prop-types' +import ShadowPropTypesIOS from './ShadowPropTypesIOS' +import TransformPropTypes from './TransformPropTypes' const ImageStylePropTypes = { ...LayoutPropTypes, @@ -59,4 +59,4 @@ const ImageStylePropTypes = { borderBottomRightRadius: ReactPropTypes.number } -module.exports = ImageStylePropTypes +export default ImageStylePropTypes diff --git a/packages/taro-cli/src/rn/StyleSheet/LayoutPropTypes.js b/packages/taro-cli/src/rn/StyleSheet/LayoutPropTypes.ts similarity index 99% rename from packages/taro-cli/src/rn/StyleSheet/LayoutPropTypes.js rename to packages/taro-cli/src/rn/StyleSheet/LayoutPropTypes.ts index c6192548f6fc..f8c11129e436 100644 --- a/packages/taro-cli/src/rn/StyleSheet/LayoutPropTypes.js +++ b/packages/taro-cli/src/rn/StyleSheet/LayoutPropTypes.ts @@ -8,9 +8,7 @@ * strict */ -'use strict' - -const ReactPropTypes = require('prop-types') +import ReactPropTypes from 'prop-types' /** * React Native's layout system is based on Flexbox and is powered both @@ -558,4 +556,4 @@ const LayoutPropTypes = { direction: ReactPropTypes.oneOf(['inherit', 'ltr', 'rtl']) } -module.exports = LayoutPropTypes +export default LayoutPropTypes diff --git a/packages/taro-cli/src/rn/StyleSheet/ShadowPropTypesIOS.js b/packages/taro-cli/src/rn/StyleSheet/ShadowPropTypesIOS.ts similarity index 89% rename from packages/taro-cli/src/rn/StyleSheet/ShadowPropTypesIOS.js rename to packages/taro-cli/src/rn/StyleSheet/ShadowPropTypesIOS.ts index 538e2c5f6bee..32484e80eb0e 100644 --- a/packages/taro-cli/src/rn/StyleSheet/ShadowPropTypesIOS.js +++ b/packages/taro-cli/src/rn/StyleSheet/ShadowPropTypesIOS.ts @@ -7,10 +7,8 @@ * * @format */ -'use strict' - -const ColorPropType = require('./ColorPropType') -const ReactPropTypes = require('prop-types') +import ColorPropType from './ColorPropType' +import ReactPropTypes from 'prop-types' /** * These props can be used to dynamically generate shadows on views, images, text, etc. @@ -47,4 +45,4 @@ const ShadowPropTypesIOS = { shadowRadius: ReactPropTypes.number } -module.exports = ShadowPropTypesIOS +export default ShadowPropTypesIOS diff --git a/packages/taro-cli/src/rn/StyleSheet/StyleSheetValidation.js b/packages/taro-cli/src/rn/StyleSheet/StyleSheetValidation.ts similarity index 84% rename from packages/taro-cli/src/rn/StyleSheet/StyleSheetValidation.js rename to packages/taro-cli/src/rn/StyleSheet/StyleSheetValidation.ts index 5e38563415aa..0e9ad548371f 100644 --- a/packages/taro-cli/src/rn/StyleSheet/StyleSheetValidation.js +++ b/packages/taro-cli/src/rn/StyleSheet/StyleSheetValidation.ts @@ -8,13 +8,11 @@ * */ -'use strict' +import ImageStylePropTypes from './ImageStylePropTypes' +import TextStylePropTypes from './TextStylePropTypes' +import ViewStylePropTypes from './ViewStylePropTypes' -const ImageStylePropTypes = require('./ImageStylePropTypes') -const TextStylePropTypes = require('./TextStylePropTypes') -const ViewStylePropTypes = require('./ViewStylePropTypes') - -const invariant = require('fbjs/lib/invariant') +import invariant from 'fbjs/lib/invariant' // Hardcoded because this is a legit case but we don't want to load it from // a private API. We might likely want to unify style sheet creation with how it @@ -61,7 +59,7 @@ class StyleSheetValidation { } } -const styleError = function (message1, style, caller, message2) { +const styleError = function (message1, style, caller, message2?) { invariant( false, message1 + @@ -79,4 +77,4 @@ StyleSheetValidation.addValidStylePropTypes(ImageStylePropTypes) StyleSheetValidation.addValidStylePropTypes(TextStylePropTypes) StyleSheetValidation.addValidStylePropTypes(ViewStylePropTypes) -module.exports = StyleSheetValidation +export default StyleSheetValidation diff --git a/packages/taro-cli/src/rn/StyleSheet/TextStylePropTypes.js b/packages/taro-cli/src/rn/StyleSheet/TextStylePropTypes.ts similarity index 93% rename from packages/taro-cli/src/rn/StyleSheet/TextStylePropTypes.js rename to packages/taro-cli/src/rn/StyleSheet/TextStylePropTypes.ts index 1935170cf67f..816a6130e575 100644 --- a/packages/taro-cli/src/rn/StyleSheet/TextStylePropTypes.js +++ b/packages/taro-cli/src/rn/StyleSheet/TextStylePropTypes.ts @@ -10,9 +10,9 @@ 'use strict' -const ColorPropType = require('./ColorPropType') -const ReactPropTypes = require('prop-types') -const ViewStylePropTypes = require('./ViewStylePropTypes') +import ColorPropType from './ColorPropType' +import ReactPropTypes from 'prop-types' +import ViewStylePropTypes from './ViewStylePropTypes' const TextStylePropTypes = { ...ViewStylePropTypes, @@ -120,4 +120,4 @@ const TextStylePropTypes = { writingDirection: ReactPropTypes.oneOf(['auto' /* default */, 'ltr', 'rtl']) } -module.exports = TextStylePropTypes +export default TextStylePropTypes diff --git a/packages/taro-cli/src/rn/StyleSheet/TransformPropTypes.js b/packages/taro-cli/src/rn/StyleSheet/TransformPropTypes.ts similarity index 95% rename from packages/taro-cli/src/rn/StyleSheet/TransformPropTypes.js rename to packages/taro-cli/src/rn/StyleSheet/TransformPropTypes.ts index 21f612aefbbe..7d2f5ac56522 100644 --- a/packages/taro-cli/src/rn/StyleSheet/TransformPropTypes.js +++ b/packages/taro-cli/src/rn/StyleSheet/TransformPropTypes.ts @@ -10,9 +10,9 @@ 'use strict' -const ReactPropTypes = require('prop-types') +import ReactPropTypes from 'prop-types' -const deprecatedPropType = require('./deprecatedPropType') +import deprecatedPropType from './deprecatedPropType' const TransformMatrixPropType = function ( props, @@ -106,4 +106,4 @@ const TransformPropTypes = { ) } -module.exports = TransformPropTypes +export default TransformPropTypes diff --git a/packages/taro-cli/src/rn/StyleSheet/ViewStylePropTypes.js b/packages/taro-cli/src/rn/StyleSheet/ViewStylePropTypes.ts similarity index 86% rename from packages/taro-cli/src/rn/StyleSheet/ViewStylePropTypes.js rename to packages/taro-cli/src/rn/StyleSheet/ViewStylePropTypes.ts index 889c5074023b..ae8e237c5a62 100644 --- a/packages/taro-cli/src/rn/StyleSheet/ViewStylePropTypes.js +++ b/packages/taro-cli/src/rn/StyleSheet/ViewStylePropTypes.ts @@ -10,11 +10,11 @@ 'use strict' -const ColorPropType = require('./ColorPropType') -const LayoutPropTypes = require('./LayoutPropTypes') -const ReactPropTypes = require('prop-types') -const ShadowPropTypesIOS = require('./ShadowPropTypesIOS') -const TransformPropTypes = require('./TransformPropTypes') +import ColorPropType from './ColorPropType' +import LayoutPropTypes from './LayoutPropTypes' +import ReactPropTypes from 'prop-types' +import ShadowPropTypesIOS from './ShadowPropTypesIOS' +import TransformPropTypes from './TransformPropTypes' /** * Warning: Some of these properties may not be supported in all releases. @@ -58,4 +58,4 @@ const ViewStylePropTypes = { elevation: ReactPropTypes.number } -module.exports = ViewStylePropTypes +export default ViewStylePropTypes diff --git a/packages/taro-cli/src/rn/StyleSheet/deprecatedPropType.js b/packages/taro-cli/src/rn/StyleSheet/deprecatedPropType.ts similarity index 90% rename from packages/taro-cli/src/rn/StyleSheet/deprecatedPropType.js rename to packages/taro-cli/src/rn/StyleSheet/deprecatedPropType.ts index 3a62f2d5c22f..88b3e3cef5b0 100644 --- a/packages/taro-cli/src/rn/StyleSheet/deprecatedPropType.js +++ b/packages/taro-cli/src/rn/StyleSheet/deprecatedPropType.ts @@ -8,14 +8,12 @@ * strict-local */ -'use strict' - // const UIManager = require('UIManager') /** * Adds a deprecation warning when the prop is used. */ -function deprecatedPropType ( +export default function deprecatedPropType ( propType, explanation ) { @@ -31,5 +29,3 @@ function deprecatedPropType ( return propType(props, propName, componentName, ...rest) } } - -module.exports = deprecatedPropType diff --git a/packages/taro-cli/src/rn/StyleSheet/index.js b/packages/taro-cli/src/rn/StyleSheet/index.js deleted file mode 100644 index 325863b24d0f..000000000000 --- a/packages/taro-cli/src/rn/StyleSheet/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const StyleSheetValidation = require('./StyleSheetValidation') - -module.exports = {StyleSheetValidation} diff --git a/packages/taro-cli/src/rn/StyleSheet/index.ts b/packages/taro-cli/src/rn/StyleSheet/index.ts new file mode 100644 index 000000000000..26534cc3b7ff --- /dev/null +++ b/packages/taro-cli/src/rn/StyleSheet/index.ts @@ -0,0 +1,5 @@ +import StyleSheetValidation from './StyleSheetValidation' + +export { + StyleSheetValidation +} diff --git a/packages/taro-cli/src/rn/StyleSheet/normalizeColor.js b/packages/taro-cli/src/rn/StyleSheet/normalizeColor.ts similarity index 99% rename from packages/taro-cli/src/rn/StyleSheet/normalizeColor.js rename to packages/taro-cli/src/rn/StyleSheet/normalizeColor.ts index b4a117a04be9..b49b5dfc25c3 100755 --- a/packages/taro-cli/src/rn/StyleSheet/normalizeColor.js +++ b/packages/taro-cli/src/rn/StyleSheet/normalizeColor.ts @@ -9,9 +9,8 @@ */ /* eslint no-bitwise: 0 */ -'use strict' -function normalizeColor (color) { +export default function normalizeColor (color) { const matchers = getMatchers() let match @@ -368,5 +367,3 @@ const names = { yellow: 0xffff00ff, yellowgreen: 0x9acd32ff } - -module.exports = normalizeColor diff --git a/packages/taro-cli/src/rn/styleProcess.js b/packages/taro-cli/src/rn/styleProcess.ts similarity index 69% rename from packages/taro-cli/src/rn/styleProcess.js rename to packages/taro-cli/src/rn/styleProcess.ts index 6539e880eac0..49da0f59dfba 100644 --- a/packages/taro-cli/src/rn/styleProcess.js +++ b/packages/taro-cli/src/rn/styleProcess.ts @@ -1,12 +1,14 @@ -const path = require('path') -const fs = require('fs-extra') -const postcss = require('postcss') -const chalk = require('chalk') -const pxtransform = require('postcss-pxtransform') -const transformCSS = require('css-to-react-native-transform').default -const {StyleSheetValidation} = require('./StyleSheet/index') -const Util = require('../util') -const npmProcess = require('../util/npm') +import path from 'path' +import fs from 'fs-extra' +import postcss from 'postcss' +import chalk from 'chalk' +import pxtransform from 'postcss-pxtransform' +import transformCSS from 'css-to-react-native-transform' + +import { StyleSheetValidation } from './StyleSheet/index' +import * as Util from '../util' +import * as npmProcess from '../util/npm' +import { FILE_PROCESSOR_MAP, processTypeEnum } from '../util/constants' const DEVICE_RATIO = 'deviceRatio' @@ -18,7 +20,7 @@ const DEVICE_RATIO = 'deviceRatio' */ function loadStyle ({filePath, pluginsConfig}) { const fileExt = path.extname(filePath) - const pluginName = Util.FILE_PROCESSOR_MAP[fileExt] + const pluginName = FILE_PROCESSOR_MAP[fileExt] if (pluginName) { return npmProcess.callPlugin(pluginName, null, filePath, pluginsConfig[pluginName] || {}) .then((item) => { @@ -27,7 +29,7 @@ function loadStyle ({filePath, pluginsConfig}) { filePath } }).catch((e) => { - Util.printLog(Util.pocessTypeEnum.ERROR, '样式预处理', filePath) + Util.printLog(processTypeEnum.ERROR, '样式预处理', filePath) console.log(e.stack) }) } @@ -51,8 +53,8 @@ function loadStyle ({filePath, pluginsConfig}) { * @param {object} projectConfig * @returns {Function | any} */ -function postCSS ({css, filePath, projectConfig}) { - let pxTransformConfig = { +function postCSS ({ css, filePath, projectConfig }) { + const pxTransformConfig = { designWidth: projectConfig.designWidth || 750 } if (projectConfig.hasOwnProperty(DEVICE_RATIO)) { @@ -72,22 +74,22 @@ function postCSS ({css, filePath, projectConfig}) { } function getStyleObject ({css, filePath}) { - var styleObject = {} + let styleObject = {} try { styleObject = transformCSS(css) } catch (err) { - Util.printLog(Util.pocessTypeEnum.WARNING, 'css-to-react-native 报错', filePath) + Util.printLog(processTypeEnum.WARNING, 'css-to-react-native 报错', filePath) console.log(chalk.red(err.stack)) } return styleObject } function validateStyle ({styleObject, filePath}) { - for (let name in styleObject) { + for (const name in styleObject) { try { StyleSheetValidation.validateStyle(name, styleObject) } catch (err) { - Util.printLog(Util.pocessTypeEnum.WARNING, '样式不支持', filePath) + Util.printLog(processTypeEnum.WARNING, '样式不支持', filePath) console.log(chalk.red(err.message)) } } @@ -97,10 +99,10 @@ function writeStyleFile ({css, tempFilePath}) { const fileContent = `import { StyleSheet } from 'react-native'\n\nexport default StyleSheet.create(${css})` fs.ensureDirSync(path.dirname(tempFilePath)) fs.writeFileSync(tempFilePath, fileContent) - Util.printLog(Util.pocessTypeEnum.GENERATE, '生成文件', tempFilePath) + Util.printLog(processTypeEnum.GENERATE, '生成文件', tempFilePath) } -module.exports = { +export { loadStyle, postCSS, getStyleObject, diff --git a/packages/taro-cli/src/rn/transformJS.js b/packages/taro-cli/src/rn/transformJS.ts similarity index 81% rename from packages/taro-cli/src/rn/transformJS.js rename to packages/taro-cli/src/rn/transformJS.ts index 173b4b996968..370984917365 100644 --- a/packages/taro-cli/src/rn/transformJS.js +++ b/packages/taro-cli/src/rn/transformJS.ts @@ -1,14 +1,16 @@ -const path = require('path') -const babel = require('babel-core') -const traverse = require('babel-traverse').default -const t = require('babel-types') -const _ = require('lodash') -const generate = require('babel-generator').default +import * as path from 'path' +import * as babel from 'babel-core' +import traverse from 'babel-traverse' +import * as t from 'babel-types' +import * as _ from 'lodash' +import generate from 'babel-generator' +import * as wxTransformer from '@tarojs/transformer-wx' +import * as Util from '../util' +import babylonConfig from '../config/babylon' +import { convertSourceStringToAstExpression as toAst } from '../util/astConvert' +import { REG_STYLE, REG_TYPESCRIPT, BUILD_TYPES } from '../util/constants' + const template = require('babel-template') -const wxTransformer = require('@tarojs/transformer-wx') -const Util = require('../util') -const babylonConfig = require('../config/babylon') -const {source: toAst} = require('../util/ast_convert') const reactImportDefaultName = 'React' let taroImportDefaultName // import default from @tarojs/taro @@ -42,7 +44,7 @@ const PACKAGES = { } function getInitPxTransformNode (projectConfig) { - let pxTransformConfig = {designWidth: projectConfig.designWidth || 750} + const pxTransformConfig = {designWidth: projectConfig.designWidth || 750} if (projectConfig.hasOwnProperty(DEVICE_RATIO)) { pxTransformConfig[DEVICE_RATIO] = projectConfig.deviceRatio @@ -75,7 +77,7 @@ function getClassPropertyVisitor ({filePath, pages, iconPaths, isEntryFile}) { root = rootNode ? rootNode.value.value : '' value.elements.forEach(v => { - const pagePath = `${root}/${v.value}`.replace(/\/{2,}/g, '/') + const pagePath = `${root}/${(v as t.StringLiteral).value}`.replace(/\/{2,}/g, '/') pages.push(pagePath.replace(/^\//, '')) }) astPath.remove() @@ -87,15 +89,15 @@ function getClassPropertyVisitor ({filePath, pages, iconPaths, isEntryFile}) { if (key.name === 'tabBar' && t.isObjectExpression(value)) { astPath.traverse({ ObjectProperty (astPath) { - let node = astPath.node - let value = node.value.value + const node = astPath.node as any + const value = node.value.value if (node.key.name === 'iconPath' || node.key.value === 'iconPath' || node.key.name === 'selectedIconPath' || node.key.value === 'selectedIconPath' ) { if (typeof value !== 'string') return - let iconName = _.camelCase(value.split('/')) + const iconName = _.camelCase(value) if (iconPaths.indexOf(value) === -1) { iconPaths.push(value) } @@ -120,7 +122,7 @@ function getJSAst (code, filePath) { code, sourcePath: filePath, isNormal: true, - isTyped: Util.REG_TYPESCRIPT.test(filePath), + isTyped: REG_TYPESCRIPT.test(filePath), adapter: 'rn' }).ast } @@ -202,16 +204,16 @@ const ClassDeclarationOrExpression = { } } -function parseJSCode ({code, filePath, isEntryFile, projectConfig}) { +export function parseJSCode ({ code, filePath, isEntryFile, projectConfig }) { let ast try { ast = getJSAst(code, filePath) } catch (e) { throw e } - const styleFiles = [] - let pages = [] // app.js 里面的config 配置里面的 pages - let iconPaths = [] // app.js 里面的config 配置里面的需要引入的 iconPath + const styleFiles: string[] = [] + const pages: string[] = [] // app.js 里面的config 配置里面的 pages + const iconPaths: string[] = [] // app.js 里面的config 配置里面的需要引入的 iconPath let hasAddReactImportDefaultName = false let providorImportName let storeName @@ -222,7 +224,7 @@ function parseJSCode ({code, filePath, isEntryFile, projectConfig}) { ClassExpression: ClassDeclarationOrExpression, ClassDeclaration: ClassDeclarationOrExpression, ImportDeclaration (astPath) { - const node = astPath.node + const node = astPath.node as t.ImportDeclaration const source = node.source let value = source.value const valueExtname = path.extname(value) @@ -234,7 +236,7 @@ function parseJSCode ({code, filePath, isEntryFile, projectConfig}) { // 引入的包为 npm 包 if (!Util.isNpmPkg(value)) { // import 样式处理 - if (Util.REG_STYLE.test(valueExtname)) { + if (REG_STYLE.test(valueExtname)) { const stylePath = path.resolve(path.dirname(filePath), value) if (styleFiles.indexOf(stylePath) < 0) { styleFiles.push(stylePath) @@ -243,7 +245,7 @@ function parseJSCode ({code, filePath, isEntryFile, projectConfig}) { return } if (value === PACKAGES['@tarojs/taro']) { - let specifier = specifiers.find(item => item.type === 'ImportDefaultSpecifier') + const specifier = specifiers.find(item => item.type === 'ImportDefaultSpecifier') if (specifier) { hasAddReactImportDefaultName = true taroImportDefaultName = specifier.local.name @@ -260,16 +262,16 @@ function parseJSCode ({code, filePath, isEntryFile, projectConfig}) { specifiers.splice(index, 1) } }) - const taroApisSpecifiers = [] + const taroApisSpecifiers: t.ImportSpecifier[] = [] specifiers.forEach((item, index) => { - if (item.imported && taroApis.indexOf(item.imported.name) >= 0) { - taroApisSpecifiers.push(t.importSpecifier(t.identifier(item.local.name), t.identifier(item.imported.name))) + if ((item as t.ImportSpecifier).imported && taroApis.indexOf((item as t.ImportSpecifier).imported.name) >= 0) { + taroApisSpecifiers.push(t.importSpecifier(t.identifier((item as t.ImportSpecifier).local.name), t.identifier((item as t.ImportSpecifier).imported.name))) specifiers.splice(index, 1) } }) source.value = PACKAGES['@tarojs/taro-rn'] // insert React - astPath.insertBefore(template(`import React from 'react'`, babylonConfig)()) + astPath.insertBefore(template(`import React from 'react'`, babylonConfig as any)()) if (taroApisSpecifiers.length) { astPath.insertBefore(t.importDeclaration(taroApisSpecifiers, t.stringLiteral(PACKAGES['@tarojs/taro-rn']))) @@ -306,13 +308,13 @@ function parseJSCode ({code, filePath, isEntryFile, projectConfig}) { ClassProperty: getClassPropertyVisitor({filePath, pages, iconPaths, isEntryFile}), // 获取 classRenderReturnJSX ClassMethod (astPath) { - let node = astPath.node - const key = node.key + const node = astPath.node as t.ClassMethod + const key = node.key as t.Identifier if (key.name !== 'render' || !isEntryFile) return astPath.traverse({ BlockStatement (astPath) { if (astPath.parent === node) { - node = astPath.node + const node = astPath.node astPath.traverse({ ReturnStatement (astPath) { if (astPath.parent === node) { @@ -336,10 +338,11 @@ function parseJSCode ({code, filePath, isEntryFile, projectConfig}) { }, JSXOpeningElement: { enter (astPath) { - if (astPath.node.name.name === 'Provider') { - for (let v of astPath.node.attributes) { + const node = astPath.node as t.JSXOpeningElement + if ((node.name as any).name === 'Provider') { + for (const v of node.attributes) { if (v.name.name !== 'store') continue - storeName = v.value.expression.name + storeName = (v.value as any).expression.name break } } @@ -347,11 +350,11 @@ function parseJSCode ({code, filePath, isEntryFile, projectConfig}) { }, Program: { exit (astPath) { - const node = astPath.node + const node = astPath.node as t.Program astPath.traverse({ ClassMethod (astPath) { const node = astPath.node - const key = node.key + const key = node.key as t.Identifier if (key.name !== 'render' || !isEntryFile) return let funcBody = classRenderReturnJSX if (pages.length > 0) { @@ -364,17 +367,19 @@ function parseJSCode ({code, filePath, isEntryFile, projectConfig}) { ${funcBody} ` } - node.body = template(`{return (${funcBody});}`, babylonConfig)() + node.body = template(`{return (${funcBody});}`, babylonConfig as any)() as any }, CallExpression (astPath) { const node = astPath.node - const callee = node.callee + const callee = node.callee as t.Identifier const calleeName = callee.name const parentPath = astPath.parentPath if (t.isMemberExpression(callee)) { - if (callee.object.name === taroImportDefaultName && callee.property.name === 'render') { + const object = callee.object as t.Identifier + const property = callee.property as t.Identifier + if (object.name === taroImportDefaultName && property.name === 'render') { astPath.remove() } } else { @@ -392,36 +397,36 @@ function parseJSCode ({code, filePath, isEntryFile, projectConfig}) { if (taroImportDefaultName) { const importTaro = template( `import ${taroImportDefaultName} from '${PACKAGES['@tarojs/taro-rn']}'`, - babylonConfig + babylonConfig as any )() - node.body.unshift(importTaro) + node.body.unshift(importTaro as any) } if (isEntryFile) { // 注入 import page from 'XXX' pages.forEach(item => { const pagePath = item.startsWith('/') ? item : `/${item}` - const screenName = _.camelCase(pagePath.split('/'), {pascalCase: true}) + const screenName = _.camelCase(pagePath) const importScreen = template( `import ${screenName} from '.${pagePath}'`, - babylonConfig + babylonConfig as any )() - node.body.unshift(importScreen) + node.body.unshift(importScreen as any) }) iconPaths.forEach(item => { const iconPath = item.startsWith('/') ? item : `/${item}` - const iconName = _.camelCase(iconPath.split('/')) + const iconName = _.camelCase(iconPath) const importIcon = template( `import ${iconName} from '.${iconPath}'`, - babylonConfig + babylonConfig as any )() - node.body.unshift(importIcon) + node.body.unshift(importIcon as any) }) // Taro.initRouter 生成 RootStack const routerPages = pages .map(item => { const pagePath = item.startsWith('/') ? item : `/${item}` - const screenName = _.camelCase(pagePath.split('/'), {pascalCase: true}) + const screenName = _.camelCase(pagePath) return `['${item}',${screenName}]` }) .join(',') @@ -431,32 +436,32 @@ function parseJSCode ({code, filePath, isEntryFile, projectConfig}) { ${taroImportDefaultName}, App.config )`, - babylonConfig - )()) + babylonConfig as any + )() as any) // initNativeApi const initNativeApi = template( `${taroImportDefaultName}.initNativeApi(${taroImportDefaultName})`, - babylonConfig + babylonConfig as any )() - node.body.push(initNativeApi) + node.body.push(initNativeApi as any) // import @tarojs/taro-router-rn const importTaroRouter = template( `import TaroRouter from '${PACKAGES['@tarojs/taro-router-rn']}'`, - babylonConfig + babylonConfig as any )() - node.body.unshift(importTaroRouter) + node.body.unshift(importTaroRouter as any) // Taro.initPxTransform - node.body.push(getInitPxTransformNode(projectConfig)) + node.body.push(getInitPxTransformNode(projectConfig) as any) // export default App if (!hasAppExportDefault) { const appExportDefault = template( `export default ${componentClassName}`, - babylonConfig + babylonConfig as any )() - node.body.push(appExportDefault) + node.body.push(appExportDefault as any) } } } @@ -464,7 +469,7 @@ function parseJSCode ({code, filePath, isEntryFile, projectConfig}) { }) try { const constantsReplaceList = Object.assign({ - 'process.env.TARO_ENV': Util.BUILD_TYPES.RN + 'process.env.TARO_ENV': BUILD_TYPES.RN }, Util.generateEnvList(projectConfig.env || {}), Util.generateConstantsList(projectConfig.defineConstants || {})) // TODO 使用 babel-plugin-transform-jsx-to-stylesheet 处理 JSX 里面样式的处理,删除无效的样式引入待优化 ast = babel.transformFromAst(ast, code, { @@ -485,5 +490,3 @@ function parseJSCode ({code, filePath, isEntryFile, projectConfig}) { styleFiles } } - -module.exports = {transformJSCode: parseJSCode} diff --git a/packages/taro-cli/src/ui.js b/packages/taro-cli/src/ui.ts similarity index 87% rename from packages/taro-cli/src/ui.js rename to packages/taro-cli/src/ui.ts index 9dfa042f93a5..67930d648cf9 100644 --- a/packages/taro-cli/src/ui.js +++ b/packages/taro-cli/src/ui.ts @@ -1,28 +1,32 @@ -const fs = require('fs-extra') -const path = require('path') -const chokidar = require('chokidar') -const chalk = require('chalk') -const wxTransformer = require('@tarojs/transformer-wx') -const traverse = require('babel-traverse').default -const t = require('babel-types') -const generate = require('babel-generator').default -const _ = require('lodash') +import * as fs from 'fs-extra' +import * as path from 'path' -const { processFiles } = require('./h5') -const npmProcess = require('./util/npm') +import * as chokidar from 'chokidar' +import chalk from 'chalk' +import wxTransformer from '@tarojs/transformer-wx' +import traverse from 'babel-traverse' +import * as t from 'babel-types' +import generate from 'babel-generator' +import _ from 'lodash' -const CONFIG = require('./config') -const { +import { processFiles } from './h5' +import * as npmProcess from './util/npm' + +import CONFIG from './config' +import { resolveScriptPath, resolveStylePath, printLog, - pocessTypeEnum, + cssImports +} from './util' +import { + processTypeEnum, PROJECT_CONFIG, BUILD_TYPES, REG_STYLE, - REG_TYPESCRIPT, - cssImports -} = require('./util') + REG_TYPESCRIPT +} from './util/constants' +import { IComponentObj } from './mini/interface' const appPath = process.cwd() const configDir = path.join(appPath, PROJECT_CONFIG) @@ -74,14 +78,14 @@ async function buildH5Lib () { }) const { styleFiles, components, code: generateCode } = parseEntryAst(transformResult.ast, tempEntryFilePath) const relativePath = path.relative(appPath, tempEntryFilePath) - printLog(pocessTypeEnum.COPY, '发现文件', relativePath) + printLog(processTypeEnum.COPY, '发现文件', relativePath) fs.ensureDirSync(path.dirname(outputEntryFilePath)) fs.writeFileSync(outputEntryFilePath, generateCode) if (components.length) { components.forEach(item => { - copyFileToDist(item.path, tempPath, outputDir) + copyFileToDist(item.path as string, tempPath, outputDir) }) - analyzeFiles(components.map(item => item.path), tempPath, outputDir) + analyzeFiles(components.map(item => item.path as string), tempPath, outputDir) } if (styleFiles.length) { styleFiles.forEach(item => { @@ -94,14 +98,14 @@ async function buildH5Lib () { } } -function copyFileToDist (filePath, sourceDir, outputDir) { - if (!path.isAbsolute(filePath)) { +function copyFileToDist (filePath: string, sourceDir: string, outputDir: string) { + if (!filePath && !path.isAbsolute(filePath)) { return } const dirname = path.dirname(filePath) const distDirname = dirname.replace(sourceDir, outputDir) const relativePath = path.relative(appPath, filePath) - printLog(pocessTypeEnum.COPY, '发现文件', relativePath) + printLog(processTypeEnum.COPY, '发现文件', relativePath) fs.ensureDirSync(distDirname) fs.copyFileSync(filePath, path.format({ dir: distDirname, @@ -109,11 +113,11 @@ function copyFileToDist (filePath, sourceDir, outputDir) { })) } -function parseEntryAst (ast, relativeFile) { - const styleFiles = [] - const components = [] - const importExportName = [] - let exportDefaultName = null +function parseEntryAst (ast: t.File, relativeFile: string) { + const styleFiles: string[] = [] + const components: IComponentObj[] = [] + const importExportName: string[] = [] + let exportDefaultName: string | null = null traverse(ast, { ExportNamedDeclaration (astPath) { @@ -198,7 +202,7 @@ function parseEntryAst (ast, relativeFile) { } } -function analyzeFiles (files, sourceDir, outputDir) { +function analyzeFiles (files: string[], sourceDir: string, outputDir: string) { const { parseAst } = require('./weapp') files.forEach(file => { if (fs.existsSync(file)) { @@ -285,7 +289,7 @@ async function buildForWeapp () { await compileDepStyles(outputStylePath, styleFiles, false) } const relativePath = path.relative(appPath, entryFilePath) - printLog(pocessTypeEnum.COPY, '发现文件', relativePath) + printLog(processTypeEnum.COPY, '发现文件', relativePath) fs.ensureDirSync(path.dirname(outputEntryFilePath)) fs.copyFileSync(entryFilePath, path.format({ dir: path.dirname(outputEntryFilePath), @@ -293,20 +297,20 @@ async function buildForWeapp () { })) if (components.length) { components.forEach(item => { - copyFileToDist(item.path, sourceDir, outputDir) + copyFileToDist(item.path as string, sourceDir, outputDir) }) - analyzeFiles(components.map(item => item.path), sourceDir, outputDir) + analyzeFiles(components.map(item => item.path as string), sourceDir, outputDir) } } catch (err) { console.log(err) } } -async function buildForH5 (buildConfig) { +async function buildForH5 () { const { buildTemp } = require('./h5') console.log() console.log(chalk.green('开始编译 H5 端组件库!')) - await buildTemp(buildConfig) + await buildTemp() if (process.env.TARO_BUILD_TYPE === 'script') { await buildH5Script() } else { @@ -397,15 +401,15 @@ function watchFiles () { } watcher - .on('add', filePath => handleChange(filePath, pocessTypeEnum.CREATE, '添加文件')) - .on('change', filePath => handleChange(filePath, pocessTypeEnum.MODIFY, '文件变动')) + .on('add', filePath => handleChange(filePath, processTypeEnum.CREATE, '添加文件')) + .on('change', filePath => handleChange(filePath, processTypeEnum.MODIFY, '文件变动')) .on('unlink', filePath => { for (const path in extraWatchFiles) { if (filePath.indexOf(path.substr(2)) > -1) return } const relativePath = path.relative(appPath, filePath) - printLog(pocessTypeEnum.UNLINK, '删除文件', relativePath) + printLog(processTypeEnum.UNLINK, '删除文件', relativePath) const weappOutputPath = path.join(appPath, outputDirName, weappOutputName) const h5OutputPath = path.join(appPath, outputDirName, h5OutputName) const fileTempPath = filePath.replace(sourceDir, tempPath) @@ -417,7 +421,7 @@ function watchFiles () { }) } -async function build ({ watch }) { +export async function build ({ watch }) { buildEntry() await buildForWeapp() await buildForH5() @@ -425,7 +429,3 @@ async function build ({ watch }) { watchFiles() } } - -module.exports = { - build -} diff --git a/packages/taro-cli/src/util/ast_convert.js b/packages/taro-cli/src/util/astConvert.ts similarity index 64% rename from packages/taro-cli/src/util/ast_convert.js rename to packages/taro-cli/src/util/astConvert.ts index 5c37bcf0a82f..554ec26e5f9f 100644 --- a/packages/taro-cli/src/util/ast_convert.js +++ b/packages/taro-cli/src/util/astConvert.ts @@ -1,9 +1,11 @@ -const t = require('babel-types') -const babylonConfig = require('../config/babylon') +import * as t from 'babel-types' +import generate from 'better-babel-generator' + +import babylonConfig from '../config/babylon' + const template = require('babel-template') -const generate = require('better-babel-generator').default -function convertObjectToAstExpression (obj) { +export function convertObjectToAstExpression (obj: object): t.ObjectProperty[] { const objArr = Object.keys(obj).map(key => { const value = obj[key] if (typeof value === 'string') { @@ -16,20 +18,18 @@ function convertObjectToAstExpression (obj) { return t.objectProperty(t.stringLiteral(key), t.booleanLiteral(value)) } if (Array.isArray(value)) { - return t.objectProperty(t.stringLiteral(key), t.arrayExpression(convertArrayToAstExpression(value))) - } - if (value == null) { - return t.objectProperty(t.stringLiteral(key), t.nullLiteral()) + return t.objectProperty(t.stringLiteral(key), t.arrayExpression(convertArrayToAstExpression(value as []))) } if (typeof value === 'object') { return t.objectProperty(t.stringLiteral(key), t.objectExpression(convertObjectToAstExpression(value))) } + return t.objectProperty(t.stringLiteral(key), t.nullLiteral()) }) return objArr } // 最低限度的转义: https://github.com/mathiasbynens/jsesc#minimal -function generateMinimalEscapeCode (ast) { +export function generateMinimalEscapeCode (ast: t.File) { return generate(ast, { jsescOption: { minimal: true @@ -37,7 +37,7 @@ function generateMinimalEscapeCode (ast) { }).code } -function convertArrayToAstExpression (arr) { +export function convertArrayToAstExpression (arr: any[]): any[] { return arr.map(value => { if (typeof value === 'string') { return t.stringLiteral(value) @@ -51,20 +51,18 @@ function convertArrayToAstExpression (arr) { if (Array.isArray(value)) { return convertArrayToAstExpression(value) } - if (value == null) { - return t.nullLiteral() - } if (typeof value === 'object') { return t.objectExpression(convertObjectToAstExpression(value)) } + return t.nullLiteral() }) } -function convertSourceStringToAstExpression (str, opts = {}) { +export function convertSourceStringToAstExpression (str: string, opts: object = {}) { return template(str, Object.assign({}, babylonConfig, opts))() } -const getObjKey = (node) => { +export const getObjKey = (node) => { if (t.isIdentifier(node)) { return node.name } else { @@ -72,8 +70,8 @@ const getObjKey = (node) => { } } -exports.obj = convertObjectToAstExpression -exports.array = convertArrayToAstExpression -exports.source = convertSourceStringToAstExpression -exports.getObjKey = getObjKey -exports.generateMinimalEscapeCode = generateMinimalEscapeCode +// exports.obj = convertObjectToAstExpression +// exports.array = convertArrayToAstExpression +// exports.source = convertSourceStringToAstExpression +// exports.getObjKey = getObjKey +// exports.generateMinimalEscapeCode = generateMinimalEscapeCode diff --git a/packages/taro-cli/src/util/constants.ts b/packages/taro-cli/src/util/constants.ts new file mode 100644 index 000000000000..724b9d630cc6 --- /dev/null +++ b/packages/taro-cli/src/util/constants.ts @@ -0,0 +1,254 @@ +import chalk, { Chalk } from 'chalk' + +export const enum processTypeEnum { + START = 'start', + CREATE = 'create', + COMPILE = 'compile', + CONVERT = 'convert', + COPY = 'copy', + GENERATE = 'generate', + MODIFY = 'modify', + ERROR = 'error', + WARNING = 'warning', + UNLINK = 'unlink', + REFERENCE = 'reference' +} + +export interface IProcessTypeMap { + [key: string] : { + name: string, + color: string | Chalk + } +} + +export const processTypeMap: IProcessTypeMap = { + [processTypeEnum.CREATE]: { + name: '创建', + color: 'cyan' + }, + [processTypeEnum.COMPILE]: { + name: '编译', + color: 'green' + }, + [processTypeEnum.CONVERT]: { + name: '转换', + color: chalk.rgb(255, 136, 0) + }, + [processTypeEnum.COPY]: { + name: '拷贝', + color: 'magenta' + }, + [processTypeEnum.GENERATE]: { + name: '生成', + color: 'blue' + }, + [processTypeEnum.MODIFY]: { + name: '修改', + color: 'yellow' + }, + [processTypeEnum.ERROR]: { + name: '错误', + color: 'red' + }, + [processTypeEnum.WARNING]: { + name: '警告', + color: 'yellow' + }, + [processTypeEnum.UNLINK]: { + name: '删除', + color: 'magenta' + }, + [processTypeEnum.START]: { + name: '启动', + color: 'green' + }, + [processTypeEnum.REFERENCE]: { + name: '引用', + color: 'blue' + } +} + +export const CSS_EXT: string[] = ['.css', '.scss', '.sass', '.less', '.styl', '.wxss', '.acss'] +export const SCSS_EXT: string[] = ['.scss'] +export const JS_EXT: string[] = ['.js', '.jsx'] +export const TS_EXT: string[] = ['.ts', '.tsx'] + +export const REG_JS: RegExp = /\.js(\?.*)?$/ +export const REG_SCRIPT: RegExp = /\.(js|jsx)(\?.*)?$/ +export const REG_TYPESCRIPT: RegExp = /\.(tsx|ts)(\?.*)?$/ +export const REG_SCRIPTS: RegExp = /\.[tj]sx?$/i +export const REG_STYLE: RegExp = /\.(css|scss|sass|less|styl|wxss)(\?.*)?$/ +export const REG_MEDIA: RegExp = /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/ +export const REG_IMAGE: RegExp = /\.(png|jpe?g|gif|bpm|svg|webp)(\?.*)?$/ +export const REG_FONT: RegExp = /\.(woff2?|eot|ttf|otf)(\?.*)?$/ +export const REG_JSON: RegExp = /\.json(\?.*)?$/ +export const REG_WXML_IMPORT: RegExp = / { - if (item.indexOf('..') >= 0) { - dotCount++ - } - }) - if (dotCount === 1) { - fPathArr.splice(0, 1, '.') - return fPathArr.join('/') - } - if (dotCount > 1) { - fPathArr.splice(0, 1) - return fPathArr.join('/') - } - return fPath.replace(/\\/g, '/') -} - -exports.replaceAsync = async function (str, regex, asyncFn) { - const promises = [] - str.replace(regex, (match, ...args) => { - const promise = asyncFn(match, ...args) - promises.push(promise) - }) - const data = await Promise.all(promises) - return str.replace(regex, () => data.shift()) -} - -exports.homedir = (function () { - let homedir = null - const env = process.env - const home = env.HOME - const user = env.LOGNAME || env.USER || env.LNAME || env.USERNAME - if (process.platform === 'win32') { - homedir = env.USERPROFILE || env.HOMEDRIVE + env.HOMEPATH || home || null - } else if (process.platform === 'darwin') { - homedir = home || (user ? `/Users/${user}` : null) - } else if (process.platform === 'linux') { - homedir = home || (process.getuid() === 0 ? '/root' : (user ? `/home/${user}` : null)) - } - return typeof os.homedir === 'function' ? os.homedir : function () { - return homedir - } -})() - -exports.getRootPath = function () { - return path.resolve(__dirname, '../../') -} - -exports.getTaroPath = function () { - const taroPath = path.join(exports.homedir(), '.taro') - if (!fs.existsSync(taroPath)) { - fs.mkdirSync(taroPath) - } - return taroPath -} - -exports.setConfig = function (config) { - const taroPath = exports.getTaroPath() - if (typeof config === 'object') { - const oldConfig = exports.getConfig() - config = Object.assign({}, oldConfig, config) - fs.writeFileSync(path.join(taroPath, 'config.json'), JSON.stringify(config, null, 2)) - } -} - -exports.getConfig = function () { - const configPath = path.join(exports.getTaroPath(), 'config.json') - if (fs.existsSync(configPath)) { - return require(configPath) - } - return {} -} - -exports.getSystemUsername = function () { - const userHome = exports.homedir() - const systemUsername = process.env.USER || path.basename(userHome) - return systemUsername -} - -exports.getPkgVersion = function () { - return require(path.join(exports.getRootPath(), 'package.json')).version -} - -exports.getPkgItemByKey = function (key) { - const packageMap = require(path.join(exports.getRootPath(), 'package.json')) - if (Object.keys(packageMap).indexOf(key) === -1) { - return {} - } else { - return packageMap[key] - } -} - -exports.printPkgVersion = function () { - const taroVersion = exports.getPkgVersion() - console.log(`👽 Taro v${taroVersion}`) - console.log() -} - -exports.shouldUseYarn = function () { - try { - execSync('yarn --version', { stdio: 'ignore' }) - return true - } catch (e) { - return false - } -} - -exports.shouldUseCnpm = function () { - try { - execSync('cnpm --version', { stdio: 'ignore' }) - return true - } catch (e) { - return false - } -} - -exports.isPublic = function isPublic (addr) { - return !exports.isPrivate(addr) -} - -exports.isEmptyObject = function (obj) { - if (obj == null) { - return true - } - for (const key in obj) { - if (obj.hasOwnProperty(key)) { - return false - } - } - return true -} - -exports.urlJoin = function () { - function normalize (str) { - return str - .replace(/([/]+)/g, '/') - .replace(/\/\?(?!\?)/g, '?') - .replace(/\/#/g, '#') - .replace(/:\//g, '://') - } - - const joined = [].slice.call(arguments, 0).join('/') - return normalize(joined) -} - -exports.resolveScriptPath = function (p) { - let realPath = p - const SCRIPT_EXT = exports.JS_EXT.concat(exports.TS_EXT) - for (let i = 0; i < SCRIPT_EXT.length; i++) { - const item = SCRIPT_EXT[i] - if (fs.existsSync(`${p}${item}`)) { - return `${p}${item}` - } - if (fs.existsSync(`${p}${path.sep}index${item}`)) { - return `${p}${path.sep}index${item}` - } - } - return realPath -} - -exports.resolveStylePath = function (p) { - let realPath = p - const CSS_EXT = exports.CSS_EXT - for (let i = 0; i < CSS_EXT.length; i++) { - const item = CSS_EXT[i] - if (fs.existsSync(`${p}${item}`)) { - return `${p}${item}` - } - } - return realPath -} - -exports.isDifferentArray = function (a, b) { - if (!Array.isArray(a) || !Array.isArray(b)) { - return true - } - if (a.length !== b.length) { - return true - } - a = a.sort() - b = b.sort() - for (let i = 0; i < a.length; i++) { - if (a[i] !== b[i]) { - return true - } - } - return false -} - -exports.checksum = function (buf, length) { - if (!Buffer.isBuffer(buf)) { - buf = Buffer.from(buf) - } - return crypto.createHash('md5').update(buf).digest('hex').slice(0, length || 8) -} - -exports.printLog = function (type, tag, filePath) { - const typeShow = processTypeMap[type] - const tagLen = tag.replace(/[\u0391-\uFFE5]/g, 'aa').length - const tagFormatLen = 8 - if (tagLen < tagFormatLen) { - const rightPadding = new Array(tagFormatLen - tagLen + 1).join(' ') - tag += rightPadding - } - const padding = '' - filePath = filePath || '' - if (typeof typeShow.color === 'string') { - console.log(chalk[typeShow.color](typeShow.name), padding, tag, padding, filePath) - } else { - console.log(typeShow.color(typeShow.name), padding, tag, padding, filePath) - } -} - -exports.replaceContentEnv = function (content, env) { - if (env && !exports.isEmptyObject(env)) { - for (const key in env) { - const reg = new RegExp(`process.env.${key}`, 'g') - content = content.replace(reg, env[key]) - } - return content - } - return content -} - -exports.generateEnvList = function (env) { - const res = { } - if (env && !exports.isEmptyObject(env)) { - for (const key in env) { - try { - res[`process.env.${key}`] = JSON.parse(env[key]) - } catch (err) { - res[`process.env.${key}`] = env[key] - } - } - } - return res -} - -exports.replaceContentConstants = function (content, constants) { - if (constants && !exports.isEmptyObject(constants)) { - for (const key in constants) { - const reg = new RegExp(key, 'g') - content = content.replace(reg, constants[key]) - } - return content - } - return content -} - -exports.generateConstantsList = function (constants) { - const res = { } - if (constants && !exports.isEmptyObject(constants)) { - for (const key in constants) { - try { - res[key] = JSON.parse(constants[key]) - } catch (err) { - res[key] = constants[key] - } - } - } - return res -} - -exports.cssImports = function (content) { - let match = {} - const results = [] - content = String(content).replace(/\/\*.+?\*\/|\/\/.*(?=[\n\r])/g, '') - while ((match = exports.CSS_IMPORT_REG.exec(content))) { - results.push(match[2]) - } - return results -} - -exports.processStyleImports = function (content, adapter, process) { - const style = [] - const imports = [] - const styleReg = new RegExp(`\\${exports.MINI_APP_FILES[adapter].STYLE}`) - content = content.replace(exports.CSS_IMPORT_REG, (m, $1, $2) => { - if (styleReg.test($2)) { - style.push(m) - imports.push($2) - if (process && typeof process === 'function') { - return process(m, $2) - } - return '' - } - if (process && typeof process === 'function') { - return process(m, $2) - } - return m - }) - return { - content, - style, - imports - } -} -/*eslint-disable*/ -const retries = (process.platform === 'win32') ? 100 : 1 -exports.emptyDirectory = function (dirPath, opts = { excludes: [] }) { - if (fs.existsSync(dirPath)) { - fs.readdirSync(dirPath).forEach(file => { - const curPath = path.join(dirPath, file) - if (fs.lstatSync(curPath).isDirectory()) { - let removed = false - let i = 0 // retry counter - - do { - try { - if (!opts.excludes.length || !opts.excludes.some(item => curPath.indexOf(item) >= 0)) { - exports.emptyDirectory(curPath) - fs.rmdirSync(curPath) - } - removed = true - } catch (e) { - } finally { - if (++i < retries) { - continue - } - } - } while (!removed) - } else { - fs.unlinkSync(curPath) - } - }) - } -} -/* eslint-enable */ - -exports.recursiveFindNodeModules = function (filePath) { - const dirname = path.dirname(filePath) - const nodeModules = path.join(dirname, 'node_modules') - if (fs.existsSync(nodeModules)) { - return nodeModules - } - return exports.recursiveFindNodeModules(dirname) -} - -exports.UPDATE_PACKAGE_LIST = [ - '@tarojs/taro', - '@tarojs/async-await', - '@tarojs/cli', - '@tarojs/components', - '@tarojs/components-rn', - '@tarojs/taro-h5', - '@tarojs/taro-swan', - '@tarojs/taro-alipay', - '@tarojs/taro-tt', - '@tarojs/plugin-babel', - '@tarojs/plugin-csso', - '@tarojs/plugin-sass', - '@tarojs/plugin-less', - '@tarojs/plugin-stylus', - '@tarojs/plugin-uglifyjs', - '@tarojs/redux', - '@tarojs/redux-h5', - '@tarojs/taro-redux-rn', - '@tarojs/taro-router-rn', - '@tarojs/taro-rn', - '@tarojs/rn-runner', - '@tarojs/router', - '@tarojs/taro-weapp', - '@tarojs/webpack-runner', - 'postcss-plugin-constparse', - 'eslint-config-taro', - 'eslint-plugin-taro', - 'taro-transformer-wx', - 'postcss-pxtransform', - 'babel-plugin-transform-jsx-to-stylesheet', - '@tarojs/mobx', - '@tarojs/mobx-h5', - '@tarojs/mobx-rn', - '@tarojs/mobx-common', - '@tarojs/mobx-prop-types' -] - -exports.pascalCase = (str) => str.charAt(0).toUpperCase() + _.camelCase(str.substr(1)) - -exports.getInstalledNpmPkgVersion = function (pkgName, basedir) { - const resolvePath = require('resolve') - try { - const pkg = resolvePath.sync(`${pkgName}/package.json`, { basedir }) - const pkgJson = fs.readJSONSync(pkg) - return pkgJson.version - } catch (err) { - return null - } -} diff --git a/packages/taro-cli/src/util/index.ts b/packages/taro-cli/src/util/index.ts new file mode 100644 index 000000000000..70aaa8662674 --- /dev/null +++ b/packages/taro-cli/src/util/index.ts @@ -0,0 +1,390 @@ +import * as fs from 'fs-extra' +import * as path from 'path' +import * as crypto from 'crypto' +import * as os from 'os' +import * as child_process from 'child_process' +import * as chalk from 'chalk' +import * as _ from 'lodash' + +import { + TS_EXT, + JS_EXT, + CSS_EXT, + CSS_IMPORT_REG, + processTypeMap, + processTypeEnum, + MINI_APP_FILES, + BUILD_TYPES +} from './constants' + +const execSync = child_process.execSync + +export function isNpmPkg (name: string): boolean { + if (/^(\.|\/)/.test(name)) { + return false + } + return true +} + +export function isAliasPath (name: string, pathAlias: object = {}): boolean { + const prefixs = Object.keys(pathAlias) + if (prefixs.length === 0) { + return false + } + return prefixs.includes(name) || (new RegExp(`^(${prefixs.join('|')})/`).test(name)) +} + +export function replaceAliasPath (filePath: string, name: string, pathAlias: object = {}) { + // 后续的 path.join 在遇到符号链接时将会解析为真实路径,如果 + // 这里的 filePath 没有做同样的处理,可能会导致 import 指向 + // 源代码文件,导致文件被意外修改 + filePath = fs.realpathSync(filePath) + + const prefixs = Object.keys(pathAlias) + if (prefixs.includes(name)) { + return promoteRelativePath(path.relative(filePath, fs.realpathSync(pathAlias[name]))) + } + const reg = new RegExp(`^(${prefixs.join('|')})/(.*)`) + name = name.replace(reg, function (m, $1, $2) { + return promoteRelativePath(path.relative(filePath, path.join(pathAlias[$1], $2))) + }) + return name +} + +export function promoteRelativePath (fPath: string): string { + const fPathArr = fPath.split(path.sep) + let dotCount = 0 + fPathArr.forEach(item => { + if (item.indexOf('..') >= 0) { + dotCount++ + } + }) + if (dotCount === 1) { + fPathArr.splice(0, 1, '.') + return fPathArr.join('/') + } + if (dotCount > 1) { + fPathArr.splice(0, 1) + return fPathArr.join('/') + } + return fPath.replace(/\\/g, '/') +} + +export const homedir = (function () { + let homedir: any + const env: NodeJS.ProcessEnv = process.env + const home = env.HOME + const user = env.LOGNAME || env.USER || env.LNAME || env.USERNAME + if (process.platform === 'win32') { + homedir = env.USERPROFILE || (env.HOMEDRIVE as string) + (env.HOMEPATH as string) || home || null + } else if (process.platform === 'darwin') { + homedir = home || (user ? `/Users/${user}` : null) + } else if (process.platform === 'linux') { + homedir = home || (process.getuid() === 0 ? '/root' : (user ? `/home/${user}` : null)) + } + return typeof os.homedir === 'function' ? os.homedir : function () { + return homedir + } +})() + +export function getRootPath (): string { + return path.resolve(__dirname, '../../') +} + +export function getTaroPath (): string { + const taroPath = path.join(homedir(), '.taro') + if (!fs.existsSync(taroPath)) { + fs.mkdirSync(taroPath) + } + return taroPath +} + +export function setConfig (config: object): void { + const taroPath = getTaroPath() + if (typeof config === 'object') { + const oldConfig = getConfig() + config = Object.assign({}, oldConfig, config) + fs.writeFileSync(path.join(taroPath, 'config.json'), JSON.stringify(config, null, 2)) + } +} + +export function getConfig (): object { + const configPath = path.join(getTaroPath(), 'config.json') + if (fs.existsSync(configPath)) { + return require(configPath) + } + return {} +} + +export function getSystemUsername (): string { + const userHome = homedir() + const systemUsername = process.env.USER || path.basename(userHome) + return systemUsername +} + +export function getPkgVersion (): string { + return require(path.join(getRootPath(), 'package.json')).version +} + +export function getPkgItemByKey (key: string) { + const packageMap = require(path.join(getRootPath(), 'package.json')) + if (Object.keys(packageMap).indexOf(key) === -1) { + return {} + } else { + return packageMap[key] + } +} + +export function printPkgVersion () { + const taroVersion = getPkgVersion() + console.log(`👽 Taro v${taroVersion}`) + console.log() +} + +export function shouldUseYarn (): boolean { + try { + execSync('yarn --version', { stdio: 'ignore' }) + return true + } catch (e) { + return false + } +} + +export function shouldUseCnpm (): boolean { + try { + execSync('cnpm --version', { stdio: 'ignore' }) + return true + } catch (e) { + return false + } +} + +export function isEmptyObject (obj: any): boolean { + if (obj == null) { + return true + } + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + return false + } + } + return true +} + +export function urlJoin (...agrs: string[]): string { + function normalize (str) { + return str + .replace(/([/]+)/g, '/') + .replace(/\/\?(?!\?)/g, '?') + .replace(/\/#/g, '#') + .replace(/:\//g, '://') + } + + const joined = [].slice.call(agrs, 0).join('/') + return normalize(joined) +} + +export function resolveScriptPath (p: string): string { + const realPath = p + const SCRIPT_EXT = JS_EXT.concat(TS_EXT) + for (let i = 0; i < SCRIPT_EXT.length; i++) { + const item = SCRIPT_EXT[i] + if (fs.existsSync(`${p}${item}`)) { + return `${p}${item}` + } + if (fs.existsSync(`${p}${path.sep}index${item}`)) { + return `${p}${path.sep}index${item}` + } + } + return realPath +} + +export function resolveStylePath (p: string): string { + const realPath = p + for (let i = 0; i < CSS_EXT.length; i++) { + const item = CSS_EXT[i] + if (fs.existsSync(`${p}${item}`)) { + return `${p}${item}` + } + } + return realPath +} + +export function isDifferentArray (a: any[], b: any[]): boolean { + if (!Array.isArray(a) || !Array.isArray(b)) { + return true + } + if (a.length !== b.length) { + return true + } + a = a.sort() + b = b.sort() + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i]) { + return true + } + } + return false +} + +export function checksum (buf: Buffer | string, length?): string { + if (!Buffer.isBuffer(buf)) { + buf = Buffer.from(buf) + } + return crypto.createHash('md5').update(buf).digest('hex').slice(0, length || 8) +} + +export function printLog (type: processTypeEnum, tag: string, filePath?: string) { + const typeShow = processTypeMap[type] + const tagLen = tag.replace(/[\u0391-\uFFE5]/g, 'aa').length + const tagFormatLen = 8 + if (tagLen < tagFormatLen) { + const rightPadding = new Array(tagFormatLen - tagLen + 1).join(' ') + tag += rightPadding + } + const padding = '' + filePath = filePath || '' + if (typeof typeShow.color === 'string') { + console.log(chalk[typeShow.color](typeShow.name), padding, tag, padding, filePath) + } else { + console.log(typeShow.color(typeShow.name), padding, tag, padding, filePath) + } +} + +export function replaceContentEnv (content: string, env: object): string { + if (env && !isEmptyObject(env)) { + for (const key in env) { + const reg = new RegExp(`process.env.${key}`, 'g') + content = content.replace(reg, env[key]) + } + return content + } + return content +} + +export function generateEnvList (env: object): object { + const res = { } + if (env && !isEmptyObject(env)) { + for (const key in env) { + try { + res[`process.env.${key}`] = JSON.parse(env[key]) + } catch (err) { + res[`process.env.${key}`] = env[key] + } + } + } + return res +} + +export function replaceContentConstants (content: string, constants: object): string { + if (constants && !isEmptyObject(constants)) { + for (const key in constants) { + const reg = new RegExp(key, 'g') + content = content.replace(reg, constants[key]) + } + return content + } + return content +} + +export function generateConstantsList (constants: object): object { + const res = { } + if (constants && !isEmptyObject(constants)) { + for (const key in constants) { + try { + res[key] = JSON.parse(constants[key]) + } catch (err) { + res[key] = constants[key] + } + } + } + return res +} + +export function cssImports (content: string): string[] { + let match: RegExpExecArray | null + const results: string[] = [] + content = String(content).replace(/\/\*.+?\*\/|\/\/.*(?=[\n\r])/g, '') + while ((match = CSS_IMPORT_REG.exec(content))) { + results.push(match[2]) + } + return results +} + +export function processStyleImports (content: string, adapter: BUILD_TYPES, processFn: (a: string, b: string) => string) { + const style: string[] = [] + const imports: string[] = [] + const styleReg = new RegExp(`\\${MINI_APP_FILES[adapter].STYLE}`) + content = content.replace(CSS_IMPORT_REG, (m, $1, $2) => { + if (styleReg.test($2)) { + style.push(m) + imports.push($2) + if (processFn && typeof processFn === 'function') { + return processFn(m, $2) + } + return '' + } + if (processFn && typeof processFn === 'function') { + return processFn(m, $2) + } + return m + }) + return { + content, + style, + imports + } +} +/*eslint-disable*/ +const retries = (process.platform === 'win32') ? 100 : 1 +export function emptyDirectory (dirPath: string, opts: { excludes: string[] } = { excludes: [] }) { + if (fs.existsSync(dirPath)) { + fs.readdirSync(dirPath).forEach(file => { + const curPath = path.join(dirPath, file) + if (fs.lstatSync(curPath).isDirectory()) { + let removed = false + let i = 0 // retry counter + do { + try { + if (!opts.excludes.length || !opts.excludes.some(item => curPath.indexOf(item) >= 0)) { + emptyDirectory(curPath) + fs.rmdirSync(curPath) + } + removed = true + } catch (e) { + } finally { + if (++i < retries) { + continue + } + } + } while (!removed) + } else { + fs.unlinkSync(curPath) + } + }) + } +} +/* eslint-enable */ + +export function recursiveFindNodeModules (filePath: string): string { + const dirname = path.dirname(filePath) + const nodeModules = path.join(dirname, 'node_modules') + if (fs.existsSync(nodeModules)) { + return nodeModules + } + return recursiveFindNodeModules(dirname) +} + +export const pascalCase: (str: string) => string + = (str: string): string => str.charAt(0).toUpperCase() + _.camelCase(str.substr(1)) + +export function getInstalledNpmPkgVersion (pkgName: string, basedir: string): string | null { + const resolvePath = require('resolve') + try { + const pkg = resolvePath.sync(`${pkgName}/package.json`, { basedir }) + const pkgJson = fs.readJSONSync(pkg) + return pkgJson.version + } catch (err) { + return null + } +} diff --git a/packages/taro-cli/src/util/npm.js b/packages/taro-cli/src/util/npm.ts similarity index 71% rename from packages/taro-cli/src/util/npm.js rename to packages/taro-cli/src/util/npm.ts index 05821fb90436..accb12051e75 100644 --- a/packages/taro-cli/src/util/npm.js +++ b/packages/taro-cli/src/util/npm.ts @@ -1,20 +1,26 @@ -const resolvePath = require('resolve') -const spawn = require('cross-spawn') -const chalk = require('chalk') +import * as resolvePath from 'resolve' +import * as spawn from 'cross-spawn' +import chalk from 'chalk' -const Util = require('./') +import * as Util from './' +import { IInstallOptions } from './types' const basedir = process.cwd() -const taroPluginPrefix = '@tarojs/plugin-' const PEERS = /UNMET PEER DEPENDENCY ([a-z\-0-9.]+)@(.+)/gm const npmCached = {} -const erroneous = [] -const defaultInstallOptions = { + +const erroneous: string[] = [] + +type pluginFunction = (pluginName: string, content: string | null, file: string, config: object) => any + +const defaultInstallOptions: IInstallOptions = { dev: false, peerDependencies: true } -function resolveNpm (pluginName) { +export const taroPluginPrefix = '@tarojs/plugin-' + +export function resolveNpm (pluginName: string): Promise { if (!npmCached[pluginName]) { return new Promise((resolve, reject) => { resolvePath(`${pluginName}`, {basedir}, (err, res) => { @@ -29,7 +35,7 @@ function resolveNpm (pluginName) { return Promise.resolve(npmCached[pluginName]) } -function resolveNpmSync (pluginName) { +export function resolveNpmSync (pluginName: string): string { try { if (!npmCached[pluginName]) { const res = resolvePath.sync(pluginName, {basedir}) @@ -39,17 +45,20 @@ function resolveNpmSync (pluginName) { } catch (err) { if (err.code === 'MODULE_NOT_FOUND') { console.log(chalk.cyan(`缺少npm包${pluginName},开始安装...`)) - const installOptions = {} + const installOptions: IInstallOptions = { + dev: false + } if (pluginName.indexOf(taroPluginPrefix) >= 0) { installOptions.dev = true } installNpmPkg(pluginName, installOptions) return resolveNpmSync(pluginName) } + return '' } } -function installNpmPkg (pkgList, options) { +export function installNpmPkg (pkgList: string[] | string, options: IInstallOptions) { if (!pkgList) { return } @@ -65,7 +74,7 @@ function installNpmPkg (pkgList, options) { } options = Object.assign({}, defaultInstallOptions, options) let installer = '' - let args = [] + let args: string[] = [] if (Util.shouldUseYarn()) { installer = 'yarn' @@ -98,8 +107,8 @@ function installNpmPkg (pkgList, options) { erroneous.push(dep) }) } - let matches = null - const peers = [] + let matches: RegExpExecArray | null = null + const peers: string[] = [] while ((matches = PEERS.exec(output.stdout))) { const pkg = matches[1] @@ -117,30 +126,32 @@ function installNpmPkg (pkgList, options) { return output } -async function callPlugin (pluginName, content, file, config) { +export const callPlugin: pluginFunction = async (pluginName: string, content: string | null, file: string, config: object) => { const pluginFn = await getNpmPkg(`${taroPluginPrefix}${pluginName}`) return pluginFn(content, file, config) } -function callPluginSync (pluginName, content, file, config) { +export const callPluginSync: pluginFunction = (pluginName: string, content: string | null, file: string, config: object) => { const pluginFn = getNpmPkgSync(`${taroPluginPrefix}${pluginName}`) return pluginFn(content, file, config) } -function getNpmPkgSync (npmName) { +export function getNpmPkgSync (npmName: string) { const npmPath = resolveNpmSync(npmName) const npmFn = require(npmPath) return npmFn } -async function getNpmPkg (npmName) { +export async function getNpmPkg (npmName: string) { let npmPath try { npmPath = resolveNpmSync(npmName) } catch (err) { if (err.code === 'MODULE_NOT_FOUND') { console.log(chalk.cyan(`缺少npm包${npmName},开始安装...`)) - const installOptions = {} + const installOptions: IInstallOptions = { + dev: false + } if (npmName.indexOf(taroPluginPrefix) >= 0) { installOptions.dev = true } @@ -151,14 +162,3 @@ async function getNpmPkg (npmName) { const npmFn = require(npmPath) return npmFn } - -module.exports = { - taroPluginPrefix, - installNpmPkg, - resolveNpm, - resolveNpmSync, - callPlugin, - callPluginSync, - getNpmPkg, - getNpmPkgSync -} diff --git a/packages/taro-cli/src/util/resolve_npm_files.js b/packages/taro-cli/src/util/resolve_npm_files.ts similarity index 70% rename from packages/taro-cli/src/util/resolve_npm_files.js rename to packages/taro-cli/src/util/resolve_npm_files.ts index b7f06688103d..0bba2c0698b0 100644 --- a/packages/taro-cli/src/util/resolve_npm_files.js +++ b/packages/taro-cli/src/util/resolve_npm_files.ts @@ -1,36 +1,39 @@ -const fs = require('fs-extra') -const path = require('path') -const resolvePath = require('resolve') -const wxTransformer = require('@tarojs/transformer-wx') -const babel = require('babel-core') -const traverse = require('babel-traverse').default -const t = require('babel-types') -const generate = require('babel-generator').default -const _ = require('lodash') +import * as fs from 'fs-extra' +import * as path from 'path' +import * as resolvePath from 'resolve' +import * as wxTransformer from '@tarojs/transformer-wx' +import * as babel from 'babel-core' +import * as t from 'babel-types' +import traverse from 'babel-traverse' +import generate from 'babel-generator' +import * as _ from 'lodash' -const defaultUglifyConfig = require('../config/uglify') - -const { +import { isNpmPkg, promoteRelativePath, printLog, - pocessTypeEnum, + recursiveFindNodeModules, + generateEnvList +} from './index' + +import { + processTypeEnum, PROJECT_CONFIG, - generateEnvList, REG_TYPESCRIPT, BUILD_TYPES, - REG_STYLE, - recursiveFindNodeModules -} = require('./index') + REG_STYLE +} from './constants' -const CONFIG = require('../config') -const defaultBabelConfig = require('../config/babel') +import defaultUglifyConfig from '../config/uglify' +import defaultBabelConfig from '../config/babel' +import CONFIG from '../config' -const npmProcess = require('./npm') +import * as npmProcess from './npm' +import { IInstallOptions, INpmConfig, IResolvedCache } from './types' const excludeNpmPkgs = ['ReactPropTypes'] -const resolvedCache = {} +const resolvedCache: IResolvedCache = {} const copyedFiles = {} const basedir = process.cwd() @@ -45,13 +48,21 @@ const babelConfig = _.mergeWith({}, defaultBabelConfig, pluginsConfig.babel, (ob } }) -function resolveNpmPkgMainPath (pkgName, isProduction, npmConfig, buildAdapter = BUILD_TYPES.WEAPP, root = basedir) { +export function resolveNpmPkgMainPath ( + pkgName: string, + isProduction: boolean, + npmConfig: INpmConfig, + buildAdapter: BUILD_TYPES = BUILD_TYPES.WEAPP, + root: string = basedir +) { try { return resolvePath.sync(pkgName, { basedir: root }) } catch (err) { if (err.code === 'MODULE_NOT_FOUND') { console.log(`缺少npm包${pkgName},开始安装...`) - const installOptions = {} + const installOptions: IInstallOptions = { + dev: false + } if (pkgName.indexOf(npmProcess.taroPluginPrefix) >= 0) { installOptions.dev = true } @@ -61,7 +72,14 @@ function resolveNpmPkgMainPath (pkgName, isProduction, npmConfig, buildAdapter = } } -function resolveNpmFilesPath (pkgName, isProduction, npmConfig, buildAdapter = BUILD_TYPES.WEAPP, root = basedir, compileInclude = []) { +export function resolveNpmFilesPath ( + pkgName: string, + isProduction: boolean, + npmConfig: INpmConfig, + buildAdapter: BUILD_TYPES = BUILD_TYPES.WEAPP, + root: string = basedir, + compileInclude: string[] = [] +) { if (!resolvedCache[pkgName]) { const res = resolveNpmPkgMainPath(pkgName, isProduction, npmConfig, buildAdapter, root) resolvedCache[pkgName] = { @@ -74,27 +92,38 @@ function resolveNpmFilesPath (pkgName, isProduction, npmConfig, buildAdapter = B return resolvedCache[pkgName] } -function parseAst (ast, filePath, files, isProduction, npmConfig, buildAdapter = BUILD_TYPES.WEAPP, compileInclude) { - const excludeRequire = [] +function parseAst ( + ast: t.File, + filePath: string, + files: string[], + isProduction: boolean, + npmConfig: INpmConfig, + buildAdapter: BUILD_TYPES = BUILD_TYPES.WEAPP, + compileInclude: string[] = [] +) { + const excludeRequire: string[] = [] traverse(ast, { IfStatement (astPath) { astPath.traverse({ BinaryExpression (astPath) { const node = astPath.node const left = node.left - if (generate(left).code === 'process.env.TARO_ENV' && - node.right.value !== buildAdapter) { - const consequentSibling = astPath.getSibling('consequent') - consequentSibling.traverse({ - CallExpression (astPath) { - if (astPath.get('callee').isIdentifier({ name: 'require' })) { - const arg = astPath.get('arguments')[0] - if (t.isStringLiteral(arg.node)) { - excludeRequire.push(arg.node.value) + const right = node.right + if (t.isMemberExpression(left) && t.isStringLiteral(right)) { + if (generate(left).code === 'process.env.TARO_ENV' && + (node.right as t.StringLiteral).value !== buildAdapter) { + const consequentSibling = astPath.getSibling('consequent') + consequentSibling.traverse({ + CallExpression (astPath) { + if (astPath.get('callee').isIdentifier({ name: 'require' })) { + const arg = astPath.get('arguments')[0] + if (t.isStringLiteral(arg.node)) { + excludeRequire.push(arg.node.value) + } } } - } - }) + }) + } } } }) @@ -104,9 +133,9 @@ function parseAst (ast, filePath, files, isProduction, npmConfig, buildAdapter = astPath.traverse({ CallExpression (astPath) { const node = astPath.node - const callee = node.callee + const callee = node.callee as t.Identifier if (callee.name === 'require') { - const args = node.arguments + const args = node.arguments as Array let requirePath = args[0].value if (excludeRequire.indexOf(requirePath) < 0) { if (isNpmPkg(requirePath)) { @@ -121,8 +150,8 @@ function parseAst (ast, filePath, files, isProduction, npmConfig, buildAdapter = } } else { let realRequirePath = path.resolve(path.dirname(filePath), requirePath) - let tempPathWithJS = `${realRequirePath}.js` - let tempPathWithIndexJS = `${realRequirePath}${path.sep}index.js` + const tempPathWithJS = `${realRequirePath}.js` + const tempPathWithIndexJS = `${realRequirePath}${path.sep}index.js` if (fs.existsSync(tempPathWithJS)) { realRequirePath = tempPathWithJS requirePath += '.js' @@ -146,7 +175,14 @@ function parseAst (ast, filePath, files, isProduction, npmConfig, buildAdapter = return generate(ast).code } -async function recursiveRequire (filePath, files, isProduction, npmConfig = {}, buildAdapter, compileInclude = []) { +async function recursiveRequire ( + filePath: string, + files: string[], + isProduction: boolean, + npmConfig: INpmConfig, + buildAdapter: BUILD_TYPES, + compileInclude: string[] = [] +) { let fileContent = fs.readFileSync(filePath).toString() let outputNpmPath if (!npmConfig.dir) { @@ -157,9 +193,12 @@ async function recursiveRequire (filePath, files, isProduction, npmConfig = {}, outputNpmPath = filePath.replace('node_modules', path.join(cwdRelate2Npm, outputDirName, npmConfig.name)) outputNpmPath = outputNpmPath.replace(/node_modules/g, npmConfig.name) } else { - let npmFilePath = filePath.match(/(?=(node_modules)).*/)[0] - npmFilePath = npmFilePath.replace(/node_modules/g, npmConfig.name) - outputNpmPath = path.join(path.resolve(configDir, '..', npmConfig.dir), npmFilePath) + const matches = filePath.match(/(?=(node_modules)).*/) + if (matches) { + let npmFilePath = matches[0] + npmFilePath = npmFilePath.replace(/node_modules/g, npmConfig.name) + outputNpmPath = path.join(path.resolve(configDir, '..', npmConfig.dir), npmFilePath) + } } if (buildAdapter === BUILD_TYPES.ALIPAY) { outputNpmPath = outputNpmPath.replace(/@/g, '_') @@ -185,7 +224,7 @@ async function recursiveRequire (filePath, files, isProduction, npmConfig = {}, plugins: [ [require('babel-plugin-transform-define').default, constantsReplaceList] ] - }).ast + }).ast as t.File fileContent = parseAst(ast, filePath, files, isProduction, npmConfig, buildAdapter, compileInclude) } catch (err) { console.log(err) @@ -206,7 +245,7 @@ async function recursiveRequire (filePath, files, isProduction, npmConfig = {}, const uglifyConfig = Object.assign(defaultUglifyConfig, uglifyPluginConfig.config || {}) const uglifyResult = npmProcess.callPluginSync('uglifyjs', fileContent, outputNpmPath, uglifyConfig) if (uglifyResult.error) { - printLog(pocessTypeEnum.ERROR, '压缩错误', `文件${filePath}`) + printLog(processTypeEnum.ERROR, '压缩错误', `文件${filePath}`) console.log(uglifyResult.error) } else { fileContent = uglifyResult.code @@ -217,12 +256,12 @@ async function recursiveRequire (filePath, files, isProduction, npmConfig = {}, fs.writeFileSync(outputNpmPath, fileContent) let modifyOutput = outputNpmPath.replace(basedir + path.sep, '') modifyOutput = modifyOutput.split(path.sep).join('/') - printLog(pocessTypeEnum.COPY, 'NPM文件', modifyOutput) + printLog(processTypeEnum.COPY, 'NPM文件', modifyOutput) copyedFiles[outputNpmPath] = true } } -function npmCodeHack (filePath, content, buildAdapter) { +function npmCodeHack (filePath: string, content: string, buildAdapter: BUILD_TYPES): string { const basename = path.basename(filePath) switch (basename) { case 'lodash.js': @@ -259,12 +298,6 @@ function npmCodeHack (filePath, content, buildAdapter) { return content } -function getResolvedCache () { +export function getResolvedCache (): IResolvedCache { return resolvedCache } - -module.exports = { - getResolvedCache, - resolveNpmFilesPath, - resolveNpmPkgMainPath -} diff --git a/packages/taro-cli/src/util/types.ts b/packages/taro-cli/src/util/types.ts new file mode 100644 index 000000000000..08cd658b4541 --- /dev/null +++ b/packages/taro-cli/src/util/types.ts @@ -0,0 +1,180 @@ +import * as webpack from 'webpack' +import * as webpackDevServer from 'webpack-dev-server' +import * as t from 'babel-types' + +import { BUILD_TYPES } from './constants' +import { IBabelOptions } from '../config/babel' + +export interface IInstallOptions { + dev: boolean, + peerDependencies?: boolean +} + +export interface INpmConfig { + dir: string, + name: string +} + +export interface IResolvedCache { + [key: string]: { + main: string, + files: string[] + } +} + +export interface IPrettierConfig { + printWidth?: number, + tabWidth?: number, + useTabs?: boolean, + semi?: boolean, + singleQuote?: boolean, + jsxSingleQuote?: boolean, + trailingComma?: 'none' | 'es5' | 'all', + bracketSpacing?: boolean, + jsxBracketSameLine?: boolean, + arrowParens?: 'avoid' | 'always', + rangeStart?: number, + rangeEnd?: number, + parser?: 'babylon' | 'flow' | 'typescript' | 'css' | 'scss' | 'less' | 'json' | 'json5' | 'json-stringify' | 'graphql' | 'markdown' | 'mdx' | 'html' | 'vue' | 'angular' | 'yaml', + filepath?: string, + requirePragma?: boolean, + insertPragma?: boolean, + proseWrap?: 'always' | 'never' | 'preserve', + htmlWhitespaceSensitivity?: 'css' | 'strict' | 'ignore', + endOfLine?: 'auto' | 'lf' | 'crlf' | 'cr' +} + +export interface IBuildConfig { + type?: BUILD_TYPES, + watch?: boolean +} + +export interface IMiniAppBuildConfig { + adapter: BUILD_TYPES, + watch?: boolean +} + +export interface IOption { + [key: string]: any +} + +export interface ICopyOptions { + patterns: { + from: string, + to: string, + ignore?: string[] + }[], + options: { + ignore?: string[] + } +} + +export interface IWxTransformResult { + code: string, + ast: t.File, + template: string, + compressedTemplate: string, + components: { + name: string, + path: string, + type: string + }[], + componentProperies: string[] +} + +export namespace PostcssOption { + export type cssModules = TogglableOptions<{ + namingPattern: 'global' | string + generateScopedName: string + }> + export type url = TogglableOptions<{ + limit: number + }> +} + +export interface IPostcssOption { + autoprefixer?: TogglableOptions, + pxtransform?: TogglableOptions, + cssModules?: PostcssOption.cssModules, + url?: PostcssOption.url, + [key: string]: any +} + +export interface ICompileOption { + exclude?: string[], + include?: string[] +} + +export interface IMiniAppConfig { + appOutput: boolean, + module?: { + postcss?: IPostcssOption + }, + compile?: ICompileOption +} + +type TogglableOptions = { + enable?: boolean, + config?: T +} + +export interface IH5Config { + webpack: ((webpackConfig: webpack.Configuration, webpack) => webpack.Configuration) | webpack.Configuration, + webpackChain: (chain: any, webpack: any) => void, + dllWebpackChain: (chain: any, webpack: any) => void, + + alias: IOption, + entry: webpack.Entry, + output: webpack.Output, + router?: { + mode?: 'hash' | 'browser', + custouRoutes?: IOption + }, + devServer: webpackDevServer.Configuration, + enableSourceMap: boolean, + enableExtract: boolean, + enableDll: boolean, + + cssLoaderOption: IOption, + styleLoaderOption: IOption, + sassLoaderOption: IOption, + lessLoaderOption: IOption, + stylusLoaderOption: IOption, + mediaUrlLoaderOption: IOption, + fontUrlLoaderOption: IOption, + imageUrlLoaderOption: IOption, + miniCssExtractPluginOption: IOption, + dllDirectory: string, + dllFilename: string, + dllEntry: { + [key: string]: string[] + }, + esnextModules: string[], + + module?: { + postcss?: IPostcssOption + } +} + +export interface IProjectConfig { + projectName?: string, + date?: string, + designWidth?: number, + watcher?: [], + deviceRatio?: { + [key: string]: number + }, + sourceRoot?: string, + outputRoot?: string, + plugins?: { + babel?: IBabelOptions, + csso?: TogglableOptions, + uglify?: TogglableOptions + }, + env?: IOption, + alias?: IOption, + defineConstants?: IOption, + copy?: ICopyOptions, + weapp?: IMiniAppConfig, + h5?: IH5Config +} diff --git a/packages/taro-cli/src/weapp.js b/packages/taro-cli/src/weapp.js deleted file mode 100644 index 36807fc75b3a..000000000000 --- a/packages/taro-cli/src/weapp.js +++ /dev/null @@ -1,2218 +0,0 @@ -const fs = require('fs-extra') -const os = require('os') -const path = require('path') -const chalk = require('chalk') -const chokidar = require('chokidar') -const wxTransformer = require('@tarojs/transformer-wx') -const babel = require('babel-core') -const traverse = require('babel-traverse').default -const t = require('babel-types') -const generate = require('babel-generator').default -const template = require('babel-template') -const autoprefixer = require('autoprefixer') -const minimatch = require('minimatch') -const _ = require('lodash') - -const postcss = require('postcss') -const pxtransform = require('postcss-pxtransform') -const cssUrlParse = require('postcss-url') -const Scope = require('postcss-modules-scope') -const Values = require('postcss-modules-values') -const genericNames = require('generic-names') -const LocalByDefault = require('postcss-modules-local-by-default') -const ExtractImports = require('postcss-modules-extract-imports') -const ResolveImports = require('postcss-modules-resolve-imports') - -const Util = require('./util') -const CONFIG = require('./config') -const npmProcess = require('./util/npm') -const { resolveNpmFilesPath, resolveNpmPkgMainPath } = require('./util/resolve_npm_files') -const babylonConfig = require('./config/babylon') -const browserList = require('./config/browser_list') -const defaultUglifyConfig = require('./config/uglify') -const defaultBabelConfig = require('./config/babel') -const astConvert = require('./util/ast_convert') - -const appPath = process.cwd() -const configDir = path.join(appPath, Util.PROJECT_CONFIG) -const projectConfig = require(configDir)(_.merge) -const sourceDirName = projectConfig.sourceRoot || CONFIG.SOURCE_DIR -const outputDirName = projectConfig.outputRoot || CONFIG.OUTPUT_DIR -const sourceDir = path.join(appPath, sourceDirName) -const outputDir = path.join(appPath, outputDirName) -const entryFilePath = Util.resolveScriptPath(path.join(sourceDir, CONFIG.ENTRY)) -const entryFileName = path.basename(entryFilePath) -const outputEntryFilePath = path.join(outputDir, entryFileName) -const watcherDirs = projectConfig.watcher || [] -const pathAlias = projectConfig.alias || {} - -const pluginsConfig = projectConfig.plugins || {} -const weappConf = projectConfig.weapp || {} -const weappNpmConfig = Object.assign({ - name: CONFIG.NPM_DIR, - dir: null -}, weappConf.npm) -const appOutput = typeof weappConf.appOutput === 'boolean' ? weappConf.appOutput : true -const useCompileConf = Object.assign({}, weappConf.compile) -const compileInclude = useCompileConf.include || [] - -const notExistNpmList = [] -const taroJsFramework = '@tarojs/taro' -const taroJsComponents = '@tarojs/components' -const taroJsRedux = '@tarojs/redux' -let appConfig = {} -const dependencyTree = {} -const depComponents = {} -const hasBeenBuiltComponents = [] -const componentsBuildResult = {} -const componentsNamedMap = {} -const componentExportsMap = {} -const wxssDepTree = {} -let isBuildingScripts = {} -let isBuildingStyles = {} -let isCopyingFiles = {} -let isProduction = false -let buildAdapter = Util.BUILD_TYPES.WEAPP -let outputFilesTypes = Util.MINI_APP_FILES[buildAdapter] -let notTaroComponents = [] - -const NODE_MODULES = 'node_modules' -const NODE_MODULES_REG = /(.*)node_modules/ - -const nodeModulesPath = Util.recursiveFindNodeModules(path.join(appPath, NODE_MODULES)) -let npmOutputDir - -if (!weappNpmConfig.dir) { - npmOutputDir = path.join(outputDir, weappNpmConfig.name) -} else { - npmOutputDir = path.join(path.resolve(configDir, '..', weappNpmConfig.dir), weappNpmConfig.name) -} - -const PARSE_AST_TYPE = { - ENTRY: 'ENTRY', - PAGE: 'PAGE', - COMPONENT: 'COMPONENT', - NORMAL: 'NORMAL' -} - -const DEVICE_RATIO = 'deviceRatio' - -const isWindows = os.platform() === 'win32' - -let constantsReplaceList = Object.assign({}, Util.generateEnvList(projectConfig.env || {}), Util.generateConstantsList(projectConfig.defineConstants || {})) - -function getExactedNpmFilePath (npmName, filePath) { - try { - const npmInfo = resolveNpmFilesPath(npmName, isProduction, weappNpmConfig, buildAdapter, appPath, compileInclude) - const npmInfoMainPath = npmInfo.main - let outputNpmPath - if (Util.REG_STYLE.test(npmInfoMainPath)) { - outputNpmPath = npmInfoMainPath - } else { - if (!weappNpmConfig.dir) { - const cwdRelate2Npm = path.relative(npmInfoMainPath.slice(0, npmInfoMainPath.search('node_modules')), process.cwd()) - outputNpmPath = npmInfoMainPath.replace(NODE_MODULES, path.join(cwdRelate2Npm, outputDirName, weappNpmConfig.name)) - outputNpmPath = outputNpmPath.replace(/node_modules/g, weappNpmConfig.name) - } else { - let npmFilePath = npmInfoMainPath.match(/(?=(node_modules)).*/)[0] - npmFilePath = npmFilePath.replace(/node_modules/g, weappNpmConfig.name) - outputNpmPath = path.join(path.resolve(configDir, '..', weappNpmConfig.dir), npmFilePath) - } - } - if (buildAdapter === Util.BUILD_TYPES.ALIPAY) { - outputNpmPath = outputNpmPath.replace(/@/g, '_') - } - const relativePath = path.relative(filePath, outputNpmPath) - return Util.promoteRelativePath(relativePath) - } catch (err) { - console.log(err) - if (notExistNpmList.indexOf(npmName) < 0) { - notExistNpmList.push(npmName) - } - return npmName - } -} - -function traverseObjectNode (node, obj) { - if (node.type === 'ClassProperty' || node.type === 'ObjectProperty') { - const properties = node.value.properties - obj = {} - properties.forEach(p => { - let key = t.isIdentifier(p.key) ? p.key.name : p.key.value - if (Util.CONFIG_MAP[buildAdapter][key]) { - key = Util.CONFIG_MAP[buildAdapter][key] - } - obj[key] = traverseObjectNode(p.value) - }) - return obj - } - if (node.type === 'ObjectExpression') { - const properties = node.properties - obj = {} - properties.forEach(p => { - let key = t.isIdentifier(p.key) ? p.key.name : p.key.value - if (Util.CONFIG_MAP[buildAdapter][key]) { - key = Util.CONFIG_MAP[buildAdapter][key] - } - obj[key] = traverseObjectNode(p.value) - }) - return obj - } - if (node.type === 'ArrayExpression') { - return node.elements.map(item => traverseObjectNode(item)) - } - if (node.type === 'NullLiteral') { - return null - } - return node.value -} - -function analyzeImportUrl ({ astPath, value, depComponents, sourceFilePath, filePath, styleFiles, scriptFiles, jsonFiles, mediaFiles }) { - const valueExtname = path.extname(value) - const node = astPath.node - if (value.indexOf('.') === 0) { - let importPath = path.resolve(path.dirname(sourceFilePath), value) - importPath = Util.resolveScriptPath(importPath) - if (isFileToBePage(importPath)) { - astPath.remove() - } else { - if (Util.REG_SCRIPT.test(valueExtname) || Util.REG_TYPESCRIPT.test(valueExtname)) { - const vpath = path.resolve(sourceFilePath, '..', value) - let fPath = value - if (fs.existsSync(vpath) && vpath !== sourceFilePath) { - fPath = vpath - } - if (scriptFiles.indexOf(fPath) < 0) { - scriptFiles.push(fPath) - } - } else if (Util.REG_JSON.test(valueExtname)) { - const vpath = path.resolve(sourceFilePath, '..', value) - if (jsonFiles.indexOf(vpath) < 0) { - jsonFiles.push(vpath) - } - if (fs.existsSync(vpath)) { - const obj = JSON.parse(fs.readFileSync(vpath).toString()) - const specifiers = node.specifiers - let defaultSpecifier = null - specifiers.forEach(item => { - if (item.type === 'ImportDefaultSpecifier') { - defaultSpecifier = item.local.name - } - }) - if (defaultSpecifier) { - let objArr = [t.nullLiteral()] - if (Array.isArray(obj)) { - objArr = t.arrayExpression(astConvert.array(obj)) - } else { - objArr = t.objectExpression(astConvert.obj(obj)) - } - astPath.replaceWith(t.variableDeclaration('const', [t.variableDeclarator(t.identifier(defaultSpecifier), objArr)])) - } - } - } else if (Util.REG_FONT.test(valueExtname) || Util.REG_IMAGE.test(valueExtname) || Util.REG_MEDIA.test(valueExtname)) { - const vpath = path.resolve(sourceFilePath, '..', value) - if (!fs.existsSync(vpath)) { - Util.printLog(Util.pocessTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 不存在!`) - return - } - if (mediaFiles.indexOf(vpath) < 0) { - mediaFiles.push(vpath) - } - const specifiers = node.specifiers - let defaultSpecifier = null - specifiers.forEach(item => { - if (item.type === 'ImportDefaultSpecifier') { - defaultSpecifier = item.local.name - } - }) - let sourceDirPath = sourceDir - if (NODE_MODULES_REG.test(vpath)) { - sourceDirPath = nodeModulesPath - } - - if (defaultSpecifier) { - astPath.replaceWith(t.variableDeclaration('const', [t.variableDeclarator(t.identifier(defaultSpecifier), t.stringLiteral(vpath.replace(sourceDirPath, '').replace(/\\/g, '/')))])) - } else { - astPath.remove() - } - } else if (Util.REG_STYLE.test(valueExtname)) { - const stylePath = path.resolve(path.dirname(sourceFilePath), value) - if (styleFiles.indexOf(stylePath) < 0) { - styleFiles.push(stylePath) - } - astPath.remove() - } else { - let vpath = Util.resolveScriptPath(path.resolve(sourceFilePath, '..', value)) - let outputVpath - if (NODE_MODULES_REG.test(vpath)) { - outputVpath = vpath.replace(nodeModulesPath, npmOutputDir) - } else { - outputVpath = vpath.replace(sourceDir, outputDir) - } - let relativePath = path.relative(filePath, outputVpath) - if (vpath && vpath !== sourceFilePath) { - if (!fs.existsSync(vpath)) { - Util.printLog(Util.pocessTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 不存在!`) - } else { - if (fs.lstatSync(vpath).isDirectory()) { - if (fs.existsSync(path.join(vpath, 'index.js'))) { - vpath = path.join(vpath, 'index.js') - relativePath = path.join(relativePath, 'index.js') - } else { - Util.printLog(Util.pocessTypeEnum.ERROR, '引用目录', `文件 ${sourceFilePath} 中引用了目录 ${value}!`) - return - } - } - if (scriptFiles.indexOf(vpath) < 0) { - scriptFiles.push(vpath) - } - relativePath = Util.promoteRelativePath(relativePath) - relativePath = relativePath.replace(path.extname(relativePath), '.js') - node.source.value = relativePath - } - } - } - } - } -} - -function parseAst (type, ast, depComponents, sourceFilePath, filePath, npmSkip = false) { - const styleFiles = [] - const scriptFiles = [] - const jsonFiles = [] - const mediaFiles = [] - let configObj = {} - let componentClassName = null - let taroJsReduxConnect = null - let taroMiniAppFramework = `@tarojs/taro-${buildAdapter}` - let taroImportDefaultName - let needExportDefault = false - let exportTaroReduxConnected = null - ast = babel.transformFromAst(ast, '', { - plugins: [ - [require('babel-plugin-danger-remove-unused-import'), { ignore: ['@tarojs/taro', 'react', 'nervjs'] }], - [require('babel-plugin-transform-define').default, constantsReplaceList] - ] - }).ast - traverse(ast, { - ClassDeclaration (astPath) { - const node = astPath.node - let hasCreateData = false - if (node.superClass) { - astPath.traverse({ - ClassMethod (astPath) { - if (astPath.get('key').isIdentifier({ name: '_createData' })) { - hasCreateData = true - } - } - }) - if (hasCreateData) { - needExportDefault = true - astPath.traverse({ - ClassMethod (astPath) { - const node = astPath.node - if (node.kind === 'constructor') { - astPath.traverse({ - ExpressionStatement (astPath) { - const node = astPath.node - if (node.expression && - node.expression.type === 'AssignmentExpression' && - node.expression.operator === '=') { - const left = node.expression.left - if (left.type === 'MemberExpression' && - left.object.type === 'ThisExpression' && - left.property.type === 'Identifier' && - left.property.name === 'config') { - configObj = traverseObjectNode(node.expression.right) - } - } - } - }) - } - } - }) - if (node.id === null) { - componentClassName = '_TaroComponentClass' - astPath.replaceWith(t.classDeclaration(t.identifier(componentClassName), node.superClass, node.body, node.decorators || [])) - } else if (node.id.name === 'App') { - componentClassName = '_App' - astPath.replaceWith(t.classDeclaration(t.identifier(componentClassName), node.superClass, node.body, node.decorators || [])) - } else { - componentClassName = node.id.name - } - } - } - }, - - ClassExpression (astPath) { - const node = astPath.node - if (node.superClass) { - let hasCreateData = false - astPath.traverse({ - ClassMethod (astPath) { - if (astPath.get('key').isIdentifier({ name: '_createData' })) { - hasCreateData = true - } - } - }) - if (hasCreateData) { - needExportDefault = true - if (node.id === null) { - const parentNode = astPath.parentPath.node - if (t.isVariableDeclarator(astPath.parentPath)) { - componentClassName = parentNode.id.name - } else { - componentClassName = '_TaroComponentClass' - } - astPath.replaceWith(t.ClassExpression(t.identifier(componentClassName), node.superClass, node.body, node.decorators || [])) - } else if (node.id.name === 'App') { - componentClassName = '_App' - astPath.replaceWith(t.ClassExpression(t.identifier(componentClassName), node.superClass, node.body, node.decorators || [])) - } else { - componentClassName = node.id.name - } - } - } - }, - - ClassProperty (astPath) { - const node = astPath.node - if (node.key.name === 'config') { - configObj = traverseObjectNode(node) - } - }, - - ImportDeclaration (astPath) { - const node = astPath.node - const source = node.source - let value = source.value - const specifiers = node.specifiers - // alias 替换 - if (Util.isAliasPath(value, pathAlias)) { - value = Util.replaceAliasPath(sourceFilePath, value, pathAlias) - source.value = value - } - if (Util.isNpmPkg(value) && notExistNpmList.indexOf(value) < 0) { - if (value === taroJsComponents) { - astPath.remove() - } else { - let isDepComponent = false - if (depComponents && depComponents.length) { - depComponents.forEach(item => { - if (item.path === value) { - isDepComponent = true - } - }) - } - if (isDepComponent) { - astPath.remove() - } else { - const specifiers = node.specifiers - if (value === taroJsFramework) { - let defaultSpecifier = null - specifiers.forEach(item => { - if (item.type === 'ImportDefaultSpecifier') { - defaultSpecifier = item.local.name - } - }) - if (defaultSpecifier) { - taroImportDefaultName = defaultSpecifier - } - value = taroMiniAppFramework - } else if (value === taroJsRedux) { - specifiers.forEach(item => { - if (item.type === 'ImportSpecifier') { - const local = item.local - if (local.type === 'Identifier' && local.name === 'connect') { - taroJsReduxConnect = item.imported.name - } - } - }) - } - if (!npmSkip) { - source.value = getExactedNpmFilePath(value, filePath) - } else { - source.value = value - } - } - } - } else if (Util.CSS_EXT.indexOf(path.extname(value)) !== -1 && specifiers.length > 0) { // 对 使用 import style from './style.css' 语法引入的做转化处理 - Util.printLog(Util.pocessTypeEnum.GENERATE, '替换代码', `为文件 ${sourceFilePath} 生成 css modules`) - const styleFilePath = path.join(path.dirname(sourceFilePath), value) - const styleCode = fs.readFileSync(styleFilePath).toString() - const result = processStyleUseCssModule({ - css: styleCode, - filePath: styleFilePath - }) - const tokens = result.root.exports || {} - const objectPropperties = [] - for (const key in tokens) { - if (tokens.hasOwnProperty(key)) { - let keyPath = key - if (key.indexOf('-') >= 0) { - keyPath = `'${key}'` - } - objectPropperties.push(t.objectProperty(t.identifier(keyPath), t.stringLiteral(tokens[key]))) - } - } - let defaultDeclator = null - let normalDeclator = null - let importItems = [] - specifiers.forEach(s => { - if (t.isImportDefaultSpecifier(s)) { - defaultDeclator = [t.variableDeclarator(t.identifier(s.local.name), t.objectExpression(objectPropperties))] - } else { - importItems.push(t.objectProperty(t.identifier(s.local.name), t.identifier(s.local.name))) - } - }) - normalDeclator = [t.variableDeclarator(t.objectPattern(importItems), t.objectExpression(objectPropperties))] - if (defaultDeclator) { - astPath.insertBefore(t.variableDeclaration('const', defaultDeclator)) - } - if (normalDeclator) { - astPath.insertBefore(t.variableDeclaration('const', normalDeclator)) - } - astPath.remove() - if (styleFiles.indexOf(styleFilePath) < 0) { // add this css file to queue - styleFiles.push(styleFilePath) - } - } else if (path.isAbsolute(value)) { - Util.printLog(Util.pocessTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 是绝对路径!`) - } - }, - - CallExpression (astPath) { - const node = astPath.node - const callee = node.callee - if (t.isMemberExpression(callee)) { - if (taroImportDefaultName && callee.object.name === taroImportDefaultName && callee.property.name === 'render') { - astPath.remove() - } - } else if (callee.name === 'require') { - const args = node.arguments - let value = args[0].value - if (Util.isAliasPath(value, pathAlias)) { - value = Util.replaceAliasPath(sourceFilePath, value, pathAlias) - args[0].value = value - } - if (Util.isNpmPkg(value) && notExistNpmList.indexOf(value) < 0) { - if (value === taroJsComponents) { - astPath.remove() - } else { - let isDepComponent = false - if (depComponents && depComponents.length) { - depComponents.forEach(item => { - if (item.path === value) { - isDepComponent = true - } - }) - } - if (isDepComponent) { - astPath.remove() - } else { - if (t.isVariableDeclaration(astPath.parentPath.parentPath)) { - const parentNode = astPath.parentPath.parentPath.node - if (parentNode.declarations.length === 1 && parentNode.declarations[0].init) { - const id = parentNode.declarations[0].id - if (value === taroJsFramework && id.type === 'Identifier') { - taroImportDefaultName = id.name - value = taroMiniAppFramework - } else if (value === taroJsRedux) { - const declarations = parentNode.declarations - declarations.forEach(item => { - const id = item.id - if (id.type === 'ObjectPattern') { - const properties = id.properties - properties.forEach(p => { - if (p.type === 'ObjectProperty') { - if (p.value.type === 'Identifier' && p.value.name === 'connect') { - taroJsReduxConnect = p.key.name - } - } - }) - } - }) - } - } - } - if (!npmSkip) { - args[0].value = getExactedNpmFilePath(value, filePath) - } else { - args[0].value = value - } - } - } - } else if (Util.CSS_EXT.indexOf(path.extname(value)) !== -1 && t.isVariableDeclarator(astPath.parentPath)) { // 对 使用 const style = require('./style.css') 语法引入的做转化处理 - Util.printLog(Util.pocessTypeEnum.GENERATE, '替换代码', `为文件 ${sourceFilePath} 生成 css modules`) - const styleFilePath = path.join(path.dirname(sourceFilePath), value) - const styleCode = fs.readFileSync(styleFilePath).toString() - const result = processStyleUseCssModule({ - css: styleCode, - filePath: styleFilePath - }) - const tokens = result.root.exports || {} - const objectPropperties = [] - for (const key in tokens) { - if (tokens.hasOwnProperty(key)) { - objectPropperties.push(t.objectProperty(t.identifier(key), t.stringLiteral(tokens[key]))) - } - } - astPath.replaceWith(t.objectExpression(objectPropperties)) - if (styleFiles.indexOf(styleFilePath) < 0) { // add this css file to queue - styleFiles.push(styleFilePath) - } - } else if (path.isAbsolute(value)) { - Util.printLog(Util.pocessTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 是绝对路径!`) - } - } - }, - - ExportDefaultDeclaration (astPath) { - const node = astPath.node - const declaration = node.declaration - needExportDefault = false - if ( - declaration && - (declaration.type === 'ClassDeclaration' || declaration.type === 'ClassExpression') - ) { - const superClass = declaration.superClass - if (superClass) { - let hasCreateData = false - astPath.traverse({ - ClassMethod (astPath) { - if (astPath.get('key').isIdentifier({ name: '_createData' })) { - hasCreateData = true - } - } - }) - if (hasCreateData) { - needExportDefault = true - if (declaration.id === null) { - componentClassName = '_TaroComponentClass' - } else if (declaration.id.name === 'App') { - componentClassName = '_App' - } else { - componentClassName = declaration.id.name - } - const isClassDcl = declaration.type === 'ClassDeclaration' - const classDclProps = [t.identifier(componentClassName), superClass, declaration.body, declaration.decorators || []] - astPath.replaceWith(isClassDcl ? t.classDeclaration.apply(null, classDclProps) : t.classExpression.apply(null, classDclProps)) - } - } - } else if (declaration.type === 'CallExpression') { - const callee = declaration.callee - if (callee && callee.type === 'CallExpression') { - const subCallee = callee.callee - if (subCallee.type === 'Identifier' && subCallee.name === taroJsReduxConnect) { - const args = declaration.arguments - if (args.length === 1 && args[0].name === componentClassName) { - needExportDefault = true - exportTaroReduxConnected = `${componentClassName}__Connected` - astPath.replaceWith(t.variableDeclaration('const', [t.variableDeclarator(t.identifier(`${componentClassName}__Connected`), t.CallExpression(declaration.callee, declaration.arguments))])) - } - } - } - } - }, - - ExportNamedDeclaration (astPath) { - const node = astPath.node - const source = node.source - if (source && source.type === 'StringLiteral') { - const value = source.value - analyzeImportUrl({ astPath, value, depComponents, sourceFilePath, filePath, styleFiles, scriptFiles, jsonFiles, mediaFiles }) - } - }, - - ExportAllDeclaration (astPath) { - const node = astPath.node - const source = node.source - if (source && source.type === 'StringLiteral') { - const value = source.value - analyzeImportUrl({ astPath, value, depComponents, sourceFilePath, filePath, styleFiles, scriptFiles, jsonFiles, mediaFiles }) - } - }, - - Program: { - exit (astPath) { - astPath.traverse({ - ImportDeclaration (astPath) { - const node = astPath.node - const source = node.source - let value = source.value - analyzeImportUrl({ astPath, value, depComponents, sourceFilePath, filePath, styleFiles, scriptFiles, jsonFiles, mediaFiles }) - }, - CallExpression (astPath) { - const node = astPath.node - const callee = node.callee - if (callee.name === 'require') { - const args = node.arguments - let value = args[0].value - const valueExtname = path.extname(value) - if (value.indexOf('.') === 0) { - let importPath = path.resolve(path.dirname(sourceFilePath), value) - importPath = Util.resolveScriptPath(importPath) - if (isFileToBePage(importPath)) { - if (astPath.parent.type === 'AssignmentExpression' || 'ExpressionStatement') { - astPath.parentPath.remove() - } else if (astPath.parent.type === 'VariableDeclarator') { - astPath.parentPath.parentPath.remove() - } else { - astPath.remove() - } - } else { - if (Util.REG_STYLE.test(valueExtname)) { - const stylePath = path.resolve(path.dirname(sourceFilePath), value) - if (styleFiles.indexOf(stylePath) < 0) { - styleFiles.push(stylePath) - } - if (astPath.parent.type === 'AssignmentExpression' || 'ExpressionStatement') { - astPath.parentPath.remove() - } else if (astPath.parent.type === 'VariableDeclarator') { - astPath.parentPath.parentPath.remove() - } else { - astPath.remove() - } - } else if (Util.REG_JSON.test(valueExtname)) { - const vpath = path.resolve(sourceFilePath, '..', value) - if (jsonFiles.indexOf(vpath) < 0) { - jsonFiles.push(vpath) - } - if (fs.existsSync(vpath)) { - const obj = JSON.parse(fs.readFileSync(vpath).toString()) - let objArr = [t.nullLiteral()] - if (Array.isArray(obj)) { - objArr = t.arrayExpression(astConvert.array(obj)) - } else { - objArr = t.objectExpression(astConvert.obj(obj)) - } - astPath.replaceWith(t.objectExpression(objArr)) - } - } else if (Util.REG_SCRIPT.test(valueExtname) || Util.REG_TYPESCRIPT.test(valueExtname)) { - const vpath = path.resolve(sourceFilePath, '..', value) - let fPath = value - if (fs.existsSync(vpath) && vpath !== sourceFilePath) { - fPath = vpath - } - if (scriptFiles.indexOf(fPath) < 0) { - scriptFiles.push(fPath) - } - } else if (Util.REG_FONT.test(valueExtname) || Util.REG_IMAGE.test(valueExtname) || Util.REG_MEDIA.test(valueExtname)) { - const vpath = path.resolve(sourceFilePath, '..', value) - if (mediaFiles.indexOf(vpath) < 0) { - mediaFiles.push(vpath) - } - let sourceDirPath = sourceDir - if (NODE_MODULES_REG.test(vpath)) { - sourceDirPath = nodeModulesPath - } - astPath.replaceWith(t.stringLiteral(vpath.replace(sourceDirPath, '').replace(/\\/g, '/'))) - } else { - let vpath = Util.resolveScriptPath(path.resolve(sourceFilePath, '..', value)) - let outputVpath - if (NODE_MODULES_REG.test(vpath)) { - outputVpath = vpath.replace(nodeModulesPath, npmOutputDir) - } else { - outputVpath = vpath.replace(sourceDir, outputDir) - } - let relativePath = path.relative(filePath, outputVpath) - if (vpath) { - if (!fs.existsSync(vpath)) { - Util.printLog(Util.pocessTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 不存在!`) - } else { - if (fs.lstatSync(vpath).isDirectory()) { - if (fs.existsSync(path.join(vpath, 'index.js'))) { - vpath = path.join(vpath, 'index.js') - relativePath = path.join(relativePath, 'index.js') - } else { - Util.printLog(Util.pocessTypeEnum.ERROR, '引用目录', `文件 ${sourceFilePath} 中引用了目录 ${value}!`) - return - } - } - if (scriptFiles.indexOf(vpath) < 0) { - scriptFiles.push(vpath) - } - relativePath = Util.promoteRelativePath(relativePath) - relativePath = relativePath.replace(path.extname(relativePath), '.js') - args[0].value = relativePath - } - } - } - } - } - } - } - }) - const node = astPath.node - const exportVariableName = exportTaroReduxConnected || componentClassName - if (needExportDefault) { - const exportDefault = template(`export default ${exportVariableName}`, babylonConfig)() - node.body.push(exportDefault) - } - const taroMiniAppFrameworkPath = !npmSkip ? getExactedNpmFilePath(taroMiniAppFramework, filePath) : taroMiniAppFramework - switch (type) { - case PARSE_AST_TYPE.ENTRY: - const pxTransformConfig = { - designWidth: projectConfig.designWidth || 750 - } - if (projectConfig.hasOwnProperty(DEVICE_RATIO)) { - pxTransformConfig[DEVICE_RATIO] = projectConfig.deviceRatio - } - node.body.push(template(`App(require('${taroMiniAppFrameworkPath}').default.createApp(${exportVariableName}))`, babylonConfig)()) - node.body.push(template(`Taro.initPxTransform(${JSON.stringify(pxTransformConfig)})`, babylonConfig)()) - break - case PARSE_AST_TYPE.PAGE: - if (buildAdapter === Util.BUILD_TYPES.WEAPP) { - node.body.push(template(`Component(require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}, true))`, babylonConfig)()) - } else { - node.body.push(template(`Page(require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}, true))`, babylonConfig)()) - } - break - case PARSE_AST_TYPE.COMPONENT: - node.body.push(template(`Component(require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}))`, babylonConfig)()) - break - default: - break - } - } - } - }) - return { - code: generate(ast).code, - styleFiles, - scriptFiles, - jsonFiles, - configObj, - mediaFiles, - componentClassName - } -} - -function parseComponentExportAst (ast, componentName, componentPath, componentType) { - let componentRealPath = null - let importExportName - ast = babel.transformFromAst(ast, '', { - plugins: [ - [require('babel-plugin-transform-define').default, constantsReplaceList] - ] - }).ast - traverse(ast, { - ExportNamedDeclaration (astPath) { - const node = astPath.node - const specifiers = node.specifiers - const source = node.source - if (source && source.type === 'StringLiteral') { - specifiers.forEach(specifier => { - const exported = specifier.exported - if (_.kebabCase(exported.name) === componentName) { - componentRealPath = Util.resolveScriptPath(path.resolve(path.dirname(componentPath), source.value)) - } - }) - } else { - specifiers.forEach(specifier => { - const exported = specifier.exported - if (_.kebabCase(exported.name) === componentName) { - importExportName = exported.name - } - }) - } - }, - - ExportDefaultDeclaration (astPath) { - const node = astPath.node - const declaration = node.declaration - if (componentType === 'default') { - importExportName = declaration.name - } - }, - - CallExpression (astPath) { - if (astPath.get('callee').isIdentifier({ name: 'require' })) { - const arg = astPath.get('arguments')[0] - if (t.isStringLiteral(arg.node)) { - componentRealPath = Util.resolveScriptPath(path.resolve(path.dirname(componentPath), arg.node.value)) - } - } - }, - - Program: { - exit (astPath) { - astPath.traverse({ - ImportDeclaration (astPath) { - const node = astPath.node - const specifiers = node.specifiers - const source = node.source - if (importExportName) { - specifiers.forEach(specifier => { - const local = specifier.local - if (local.name === importExportName) { - componentRealPath = Util.resolveScriptPath(path.resolve(path.dirname(componentPath), source.value)) - } - }) - } - } - }) - } - } - }) - return componentRealPath -} - -function isFileToBeTaroComponent (code, sourcePath, outputPath) { - const transformResult = wxTransformer({ - code, - sourcePath: sourcePath, - outputPath: outputPath, - isNormal: true, - isTyped: Util.REG_TYPESCRIPT.test(sourcePath), - adapter: buildAdapter, - env: constantsReplaceList - }) - const { ast } = transformResult - let isTaroComponent = false - - traverse(ast, { - ClassDeclaration (astPath) { - astPath.traverse({ - ClassMethod (astPath) { - if (astPath.get('key').isIdentifier({ name: 'render' })) { - astPath.traverse({ - JSXElement () { - isTaroComponent = true - } - }) - } - } - }) - }, - - ClassExpression (astPath) { - astPath.traverse({ - ClassMethod (astPath) { - if (astPath.get('key').isIdentifier({ name: 'render' })) { - astPath.traverse({ - JSXElement () { - isTaroComponent = true - } - }) - } - } - }) - } - }) - - return { - isTaroComponent, - transformResult - } -} - -function isFileToBePage (filePath) { - let isPage = false - const extname = path.extname(filePath) - const pages = appConfig.pages || [] - const filePathWithoutExt = filePath.replace(extname, '') - pages.forEach(page => { - if (filePathWithoutExt === path.join(sourceDir, page)) { - isPage = true - } - }) - return isPage && Util.REG_SCRIPTS.test(extname) -} - -function copyFilesFromSrcToOutput (files) { - files.forEach(file => { - let outputFilePath - if (NODE_MODULES_REG.test(file)) { - outputFilePath = file.replace(nodeModulesPath, npmOutputDir) - } else { - outputFilePath = file.replace(sourceDir, outputDir) - } - if (isCopyingFiles[outputFilePath]) { - return - } - isCopyingFiles[outputFilePath] = true - let modifySrc = file.replace(appPath + path.sep, '') - modifySrc = modifySrc.split(path.sep).join('/') - let modifyOutput = outputFilePath.replace(appPath + path.sep, '') - modifyOutput = modifyOutput.split(path.sep).join('/') - Util.printLog(Util.pocessTypeEnum.COPY, '文件', modifyOutput) - if (!fs.existsSync(file)) { - Util.printLog(Util.pocessTypeEnum.ERROR, '文件', `${modifySrc} 不存在`) - } else { - fs.ensureDir(path.dirname(outputFilePath)) - if (file === outputFilePath) { - return - } - fs.copySync(file, outputFilePath) - } - }) -} - -const babelConfig = _.mergeWith({}, defaultBabelConfig, pluginsConfig.babel, (objValue, srcValue) => { - if (Array.isArray(objValue)) { - return Array.from(new Set(srcValue.concat(objValue))) - } -}) - -const shouldTransformAgain = (function () { - const pluginsStr = JSON.stringify(babelConfig.plugins) - if (/transform-runtime/.test(pluginsStr)) { - return true - } - return false -})() - -async function compileScriptFile (content, sourceFilePath, outputFilePath, adapter) { - const compileScriptRes = await npmProcess.callPlugin('babel', content, sourceFilePath, babelConfig) - const code = compileScriptRes.code - if (!shouldTransformAgain) { - return code - } - const transformResult = wxTransformer({ - code, - sourcePath: sourceFilePath, - outputPath: outputFilePath, - isNormal: true, - isTyped: false, - adapter, - env: constantsReplaceList - }) - const res = parseAst(PARSE_AST_TYPE.NORMAL, transformResult.ast, [], sourceFilePath, outputFilePath) - return res.code -} - -async function checkCliAndFrameworkVersion () { - const frameworkName = `@tarojs/taro-${buildAdapter}` - const frameworkVersion = Util.getInstalledNpmPkgVersion(frameworkName, nodeModulesPath) - if (frameworkVersion) { - if (frameworkVersion !== Util.getPkgVersion()) { - Util.printLog(Util.pocessTypeEnum.ERROR, '版本问题', `Taro CLI 与本地安装的小程序框架 ${frameworkName} 版本不一致,请确保一致`) - console.log(`Taro CLI: ${Util.getPkgVersion()}`) - console.log(`${frameworkName}: ${frameworkVersion}`) - process.exit(1) - } - } else { - Util.printLog(Util.pocessTypeEnum.WARNING, '依赖安装', chalk.red(`项目依赖 ${frameworkName} 未安装,或安装有误!`)) - } -} - -function buildProjectConfig () { - let projectConfigFileName = `project.${buildAdapter}.json` - if (buildAdapter === Util.BUILD_TYPES.WEAPP) { - projectConfigFileName = 'project.config.json' - } - let projectConfigPath = path.join(appPath, projectConfigFileName) - - if (!fs.existsSync(projectConfigPath)) { - projectConfigPath = path.join(sourceDir, projectConfigFileName) - if (!fs.existsSync(projectConfigPath)) return - } - - const origProjectConfig = fs.readJSONSync(projectConfigPath) - if (buildAdapter === Util.BUILD_TYPES.TT) { - projectConfigFileName = 'project.config.json' - } - fs.ensureDirSync(outputDir) - fs.writeFileSync( - path.join(outputDir, projectConfigFileName), - JSON.stringify(Object.assign({}, origProjectConfig, { miniprogramRoot: './' }), null, 2) - ) - Util.printLog(Util.pocessTypeEnum.GENERATE, '工具配置', `${outputDirName}/${projectConfigFileName}`) -} - -async function buildFrameworkInfo () { - // 百度小程序编译出 .frameworkinfo 文件 - if (buildAdapter === Util.BUILD_TYPES.SWAN) { - const frameworkInfoFileName = '.frameworkinfo' - const frameworkName = `@tarojs/taro-${buildAdapter}` - const frameworkVersion = Util.getInstalledNpmPkgVersion(frameworkName, nodeModulesPath) - if (frameworkVersion) { - const frameworkinfo = { - toolName: 'Taro', - toolCliVersion: Util.getPkgVersion(), - toolFrameworkVersion: frameworkVersion, - createTime: new Date(projectConfig.date).getTime() - } - fs.writeFileSync( - path.join(outputDir, frameworkInfoFileName), - JSON.stringify(frameworkinfo, null, 2) - ) - Util.printLog(Util.pocessTypeEnum.GENERATE, '框架信息', `${outputDirName}/${frameworkInfoFileName}`) - } else { - Util.printLog(Util.pocessTypeEnum.WARNING, '依赖安装', chalk.red(`项目依赖 ${frameworkName} 未安装,或安装有误!`)) - } - } -} - -function buildWorkers (worker) { - Util.printLog(Util.pocessTypeEnum.COMPILE, 'Workers', '编译 worker 相关文件') - const workerDir = path.join(sourceDir, worker) - function fileRecursiveSearch (fileDir) { - fs.readdir(fileDir, (err, files) => { - if (err) { - console.warn(err) - } else { - files.forEach(filename => { - const filePath = path.join(fileDir, filename) - fs.stat(filePath, (err, stats) => { - if (err) { - console.warn(err) - } else { - const isFile = stats.isFile() - const isDir = stats.isDirectory() - if (isFile) { - if (Util.REG_SCRIPTS.test(filePath)) { - compileDepScripts([filePath]) - } else { - copyFilesFromSrcToOutput([filePath]) - } - } else if (isDir) { - fileRecursiveSearch(filePath) - } - } - }) - }) - } - }) - } - fileRecursiveSearch(workerDir) -} - -async function buildCustomTabbar () { - const customTabbarPath = path.join(sourceDir, 'custom-tab-bar') - const customTabbarJSPath = Util.resolveScriptPath(customTabbarPath) - await buildSingleComponent({ - path: customTabbarJSPath, - name: 'custom-tab-bar' - }) -} - -async function buildEntry () { - Util.printLog(Util.pocessTypeEnum.COMPILE, '入口文件', `${sourceDirName}/${entryFileName}`) - const entryFileCode = fs.readFileSync(entryFilePath).toString() - try { - const transformResult = wxTransformer({ - code: entryFileCode, - sourcePath: entryFilePath, - outputPath: outputEntryFilePath, - isApp: true, - isTyped: Util.REG_TYPESCRIPT.test(entryFilePath), - adapter: buildAdapter, - env: constantsReplaceList - }) - // app.js的template忽略 - const res = parseAst(PARSE_AST_TYPE.ENTRY, transformResult.ast, [], entryFilePath, outputEntryFilePath) - let resCode = res.code - resCode = await compileScriptFile(resCode, entryFilePath, outputEntryFilePath, buildAdapter) - if (isProduction) { - const uglifyPluginConfig = pluginsConfig.uglify || { enable: true } - if (uglifyPluginConfig.enable) { - const uglifyConfig = Object.assign(defaultUglifyConfig, uglifyPluginConfig.config || {}) - const uglifyResult = npmProcess.callPluginSync('uglifyjs', resCode, entryFilePath, uglifyConfig) - if (uglifyResult.error) { - Util.printLog(Util.pocessTypeEnum.ERROR, '压缩错误', `文件${entryFilePath}`) - console.log(uglifyResult.error) - } else { - resCode = uglifyResult.code - } - } - } - if (appOutput) { - fs.writeFileSync(path.join(outputDir, 'app.json'), JSON.stringify(res.configObj, null, 2)) - Util.printLog(Util.pocessTypeEnum.GENERATE, '入口配置', `${outputDirName}/app.json`) - fs.writeFileSync(path.join(outputDir, 'app.js'), resCode) - Util.printLog(Util.pocessTypeEnum.GENERATE, '入口文件', `${outputDirName}/app.js`) - } - if (res.configObj.workers) { - buildWorkers(res.configObj.workers) - } - if (res.configObj.tabBar && res.configObj.tabBar.custom) { - await buildCustomTabbar() - } - const fileDep = dependencyTree[entryFilePath] || {} - // 编译依赖的脚本文件 - if (Util.isDifferentArray(fileDep['script'], res.scriptFiles)) { - compileDepScripts(res.scriptFiles) - } - // 编译样式文件 - if (Util.isDifferentArray(fileDep['style'], res.styleFiles) && appOutput) { - await compileDepStyles(path.join(outputDir, `app${outputFilesTypes.STYLE}`), res.styleFiles, false) - Util.printLog(Util.pocessTypeEnum.GENERATE, '入口样式', `${outputDirName}/app${outputFilesTypes.STYLE}`) - } - // 拷贝依赖文件 - if (Util.isDifferentArray(fileDep['json'], res.jsonFiles)) { - copyFilesFromSrcToOutput(res.jsonFiles) - } - - // 处理res.configObj 中的tabBar配置 - const tabBar = res.configObj.tabBar - if (tabBar && typeof tabBar === 'object' && !Util.isEmptyObject(tabBar)) { - const { - list: listConfig, - iconPath: pathConfig, - selectedIconPath: selectedPathConfig - } = Util.CONFIG_MAP[buildAdapter] - const list = tabBar[listConfig] || [] - let tabBarIcons = [] - list.forEach(item => { - item[pathConfig] && tabBarIcons.push(item[pathConfig]) - item[selectedPathConfig] && tabBarIcons.push(item[selectedPathConfig]) - }) - tabBarIcons = tabBarIcons.map(item => path.resolve(sourceDir, item)) - if (tabBarIcons && tabBarIcons.length) { - res.mediaFiles = res.mediaFiles.concat(tabBarIcons) - } - } - if (Util.isDifferentArray(fileDep['media'], res.mediaFiles)) { - copyFilesFromSrcToOutput(res.mediaFiles) - } - fileDep['style'] = res.styleFiles - fileDep['script'] = res.scriptFiles - fileDep['json'] = res.jsonFiles - fileDep['media'] = res.mediaFiles - dependencyTree[entryFilePath] = fileDep - return res.configObj - } catch (err) { - console.log(err) - } -} - -async function buildPages () { - Util.printLog(Util.pocessTypeEnum.COMPILE, '所有页面') - // 支持分包,解析子包页面 - const pages = appConfig.pages || [] - const subPackages = appConfig.subPackages || appConfig.subpackages - if (subPackages && subPackages.length) { - subPackages.forEach(item => { - if (item.pages && item.pages.length) { - const root = item.root - item.pages.forEach(page => { - let pagePath = `${root}/${page}` - pagePath = pagePath.replace(/\/{2,}/g, '/') - if (pages.indexOf(pagePath) < 0) { - pages.push(pagePath) - } - }) - } - }) - } - const pagesPromises = pages.map(async page => { - return buildSinglePage(page) - }) - await Promise.all(pagesPromises) -} - -function processNativeWxml (componentWXMLPath, componentWXMLContent, outputComponentWXMLPath) { - let wxmlContent - let needCopy = true - if (componentWXMLPath && fs.existsSync(componentWXMLPath)) { - wxmlContent = fs.readFileSync(componentWXMLPath).toString() - } else { - needCopy = false - wxmlContent = componentWXMLContent - } - const importWxmlPathList = [] - let regResult - while ((regResult = Util.REG_WXML_IMPORT.exec(wxmlContent)) != null) { - importWxmlPathList.push(regResult[2] || regResult[3]) - } - if (importWxmlPathList.length) { - importWxmlPathList.forEach(item => { - const itemPath = path.resolve(componentWXMLPath, '..', item) - if (fs.existsSync(itemPath)) { - const outputItemPath = itemPath.replace(sourceDir, outputDir) - processNativeWxml(itemPath, null, outputItemPath) - } - }) - } - if (componentWXMLPath === outputComponentWXMLPath || !needCopy) { - return - } - copyFileSync(componentWXMLPath, outputComponentWXMLPath) -} - -function transfromNativeComponents (configFile, componentConfig) { - const usingComponents = componentConfig.usingComponents - if (usingComponents && !Util.isEmptyObject(usingComponents)) { - Object.keys(usingComponents).map(async item => { - let componentPath = usingComponents[item] - - if (Util.isAliasPath(componentPath, pathAlias)) { - componentPath = Util.replaceAliasPath(configFile, componentPath, pathAlias) - usingComponents[item] = componentPath - } - - if (/^plugin:\/\//.test(componentPath)) { - // 小程序 plugin - Util.printLog(Util.pocessTypeEnum.REFERENCE, '插件引用', `使用了插件 ${chalk.bold(componentPath)}`) - return - } - let componentJSPath = Util.resolveScriptPath(path.resolve(path.dirname(configFile), componentPath)) - if (!fs.existsSync(componentJSPath)) { - componentJSPath = Util.resolveScriptPath(path.join(sourceDir, componentPath)) - } - const componentJSONPath = componentJSPath.replace(path.extname(componentJSPath), outputFilesTypes.CONFIG) - const componentWXMLPath = componentJSPath.replace(path.extname(componentJSPath), outputFilesTypes.TEMPL) - const componentWXSSPath = componentJSPath.replace(path.extname(componentJSPath), outputFilesTypes.STYLE) - const outputComponentJSPath = componentJSPath.replace(sourceDir, outputDir).replace(path.extname(componentJSPath), outputFilesTypes.SCRIPT) - if (fs.existsSync(componentJSPath)) { - const componentJSContent = fs.readFileSync(componentJSPath).toString() - if (componentJSContent.indexOf(taroJsFramework) >= 0 && !fs.existsSync(componentWXMLPath)) { - const buildDepComponentsRes = await buildDepComponents([componentJSPath]) - return buildDepComponentsRes - } - compileDepScripts([componentJSPath]) - } else { - return Util.printLog(Util.pocessTypeEnum.ERROR, '编译错误', `原生组件文件 ${componentJSPath} 不存在!`) - } - if (fs.existsSync(componentWXMLPath)) { - const outputComponentWXMLPath = outputComponentJSPath.replace(path.extname(outputComponentJSPath), outputFilesTypes.TEMPL) - processNativeWxml(componentWXMLPath, null, outputComponentWXMLPath) - } - if (fs.existsSync(componentWXSSPath)) { - const outputComponentWXSSPath = outputComponentJSPath.replace(path.extname(outputComponentJSPath), outputFilesTypes.STYLE) - await compileDepStyles(outputComponentWXSSPath, [componentWXSSPath], true) - } - if (fs.existsSync(componentJSONPath)) { - const componentJSON = require(componentJSONPath) - const outputComponentJSONPath = outputComponentJSPath.replace(path.extname(outputComponentJSPath), outputFilesTypes.CONFIG) - copyFileSync(componentJSONPath, outputComponentJSONPath) - - // 解决组件循环依赖不断编译爆栈的问题 - if (componentJSON && componentJSON.usingComponents) { - Object.keys(componentJSON.usingComponents).forEach(key => { - if (key === item) { - delete componentJSON.usingComponents[key] - } - }) - } - - transfromNativeComponents(componentJSONPath, componentJSON) - } - }) - } -} - -// 小程序页面编译 -async function buildSinglePage (page) { - Util.printLog(Util.pocessTypeEnum.COMPILE, '页面文件', `${sourceDirName}/${page}`) - const pagePath = path.join(sourceDir, `${page}`) - let pageJs = Util.resolveScriptPath(pagePath) - if (!fs.existsSync(pageJs)) { - Util.printLog(Util.pocessTypeEnum.ERROR, '页面文件', `${sourceDirName}/${page} 不存在!`) - return - } - const pageJsContent = fs.readFileSync(pageJs).toString() - const outputPageJSPath = pageJs.replace(sourceDir, outputDir).replace(path.extname(pageJs), outputFilesTypes.SCRIPT) - const outputPagePath = path.dirname(outputPageJSPath) - const outputPageJSONPath = outputPageJSPath.replace(path.extname(outputPageJSPath), outputFilesTypes.CONFIG) - const outputPageWXMLPath = outputPageJSPath.replace(path.extname(outputPageJSPath), outputFilesTypes.TEMPL) - const outputPageWXSSPath = outputPageJSPath.replace(path.extname(outputPageJSPath), outputFilesTypes.STYLE) - // 判断是不是小程序原生代码页面 - const pageWXMLPath = pageJs.replace(path.extname(pageJs), outputFilesTypes.TEMPL) - if (fs.existsSync(pageWXMLPath) && pageJsContent.indexOf(taroJsFramework) < 0) { - const pageJSONPath = pageJs.replace(path.extname(pageJs), outputFilesTypes.CONFIG) - const pageWXSSPath = pageJs.replace(path.extname(pageJs), outputFilesTypes.STYLE) - if (fs.existsSync(pageJSONPath)) { - const pageJSON = require(pageJSONPath) - copyFileSync(pageJSONPath, outputPageJSONPath) - transfromNativeComponents(pageJSONPath, pageJSON) - } - compileDepScripts([pageJs]) - copyFileSync(pageWXMLPath, outputPageWXMLPath) - if (fs.existsSync(pageWXSSPath)) { - await compileDepStyles(outputPageWXSSPath, [pageWXSSPath], false) - } - return - } - try { - const transformResult = wxTransformer({ - code: pageJsContent, - sourcePath: pageJs, - outputPath: outputPageJSPath, - isRoot: true, - isTyped: Util.REG_TYPESCRIPT.test(pageJs), - adapter: buildAdapter, - env: constantsReplaceList - }) - const pageDepComponents = transformResult.components - const compressTemplate = useCompileConf.compressTemplate - const pageWXMLContent = (isProduction && compressTemplate) ? transformResult.compressedTemplate : transformResult.template - const res = parseAst(PARSE_AST_TYPE.PAGE, transformResult.ast, pageDepComponents, pageJs, outputPageJSPath) - let resCode = res.code - resCode = await compileScriptFile(resCode, pageJs, outputPageJSPath, buildAdapter) - if (isProduction) { - const uglifyPluginConfig = pluginsConfig.uglify || { enable: true } - if (uglifyPluginConfig.enable) { - const uglifyConfig = Object.assign(defaultUglifyConfig, uglifyPluginConfig.config || {}) - const uglifyResult = npmProcess.callPluginSync('uglifyjs', resCode, outputPageJSPath, uglifyConfig) - if (uglifyResult.error) { - Util.printLog(Util.pocessTypeEnum.ERROR, '压缩错误', `文件${pageJs}`) - console.log(uglifyResult.error) - } else { - resCode = uglifyResult.code - } - } - } - fs.ensureDirSync(outputPagePath) - const { usingComponents = {} } = res.configObj - if (usingComponents && !Util.isEmptyObject(usingComponents)) { - const keys = Object.keys(usingComponents) - keys.forEach(item => { - pageDepComponents.forEach(component => { - if (_.camelCase(item) === _.camelCase(component.name)) { - delete usingComponents[item] - } - }) - }) - transfromNativeComponents(outputPageJSONPath.replace(outputDir, sourceDir), res.configObj) - } - const fileDep = dependencyTree[pageJs] || {} - // 编译依赖的组件文件 - let buildDepComponentsResult = [] - let realComponentsPathList = [] - if (pageDepComponents.length) { - realComponentsPathList = getRealComponentsPathList(pageJs, pageDepComponents) - res.scriptFiles = res.scriptFiles.map(item => { - for (let i = 0; i < realComponentsPathList.length; i++) { - const componentObj = realComponentsPathList[i] - const componentPath = componentObj.path - if (item === componentPath) { - return null - } - } - return item - }).filter(item => item) - buildDepComponentsResult = await buildDepComponents(realComponentsPathList) - } - if (!Util.isEmptyObject(componentExportsMap) && realComponentsPathList.length) { - const mapKeys = Object.keys(componentExportsMap) - realComponentsPathList.forEach(component => { - if (mapKeys.indexOf(component.path) >= 0) { - const componentMap = componentExportsMap[component.path] - componentMap.forEach(component => { - pageDepComponents.forEach(depComponent => { - if (depComponent.name === component.name) { - let componentPath = component.path - let realPath - if (NODE_MODULES_REG.test(componentPath)) { - componentPath = componentPath.replace(nodeModulesPath, npmOutputDir) - realPath = Util.promoteRelativePath(path.relative(outputPageJSPath, componentPath)) - } else { - realPath = Util.promoteRelativePath(path.relative(pageJs, componentPath)) - } - depComponent.path = realPath.replace(path.extname(realPath), '') - } - }) - }) - } - }) - } - fs.writeFileSync(outputPageJSONPath, JSON.stringify(_.merge({}, buildUsingComponents(pageJs, pageDepComponents), res.configObj), null, 2)) - Util.printLog(Util.pocessTypeEnum.GENERATE, '页面配置', `${outputDirName}/${page}${outputFilesTypes.CONFIG}`) - fs.writeFileSync(outputPageJSPath, resCode) - Util.printLog(Util.pocessTypeEnum.GENERATE, '页面逻辑', `${outputDirName}/${page}${outputFilesTypes.SCRIPT}`) - fs.writeFileSync(outputPageWXMLPath, pageWXMLContent) - processNativeWxml(outputPageWXMLPath.replace(outputDir, sourceDir), pageWXMLContent, outputPageWXMLPath) - Util.printLog(Util.pocessTypeEnum.GENERATE, '页面模板', `${outputDirName}/${page}${outputFilesTypes.TEMPL}`) - // 编译依赖的脚本文件 - if (Util.isDifferentArray(fileDep['script'], res.scriptFiles)) { - compileDepScripts(res.scriptFiles) - } - // 编译样式文件 - if (Util.isDifferentArray(fileDep['style'], res.styleFiles) || Util.isDifferentArray(depComponents[pageJs], pageDepComponents)) { - Util.printLog(Util.pocessTypeEnum.GENERATE, '页面样式', `${outputDirName}/${page}${outputFilesTypes.STYLE}`) - const depStyleList = getDepStyleList(outputPageWXSSPath, buildDepComponentsResult) - wxssDepTree[outputPageWXSSPath] = depStyleList - await compileDepStyles(outputPageWXSSPath, res.styleFiles, false) - } - // 拷贝依赖文件 - if (Util.isDifferentArray(fileDep['json'], res.jsonFiles)) { - copyFilesFromSrcToOutput(res.jsonFiles) - } - if (Util.isDifferentArray(fileDep['media'], res.mediaFiles)) { - copyFilesFromSrcToOutput(res.mediaFiles) - } - depComponents[pageJs] = pageDepComponents - fileDep['style'] = res.styleFiles - fileDep['script'] = res.scriptFiles - fileDep['json'] = res.jsonFiles - fileDep['media'] = res.mediaFiles - dependencyTree[pageJs] = fileDep - } catch (err) { - Util.printLog(Util.pocessTypeEnum.ERROR, '页面编译', `页面${pagePath}编译失败!`) - console.log(err) - } -} - -/** - * css module processor - * @param styleObj { css: string, filePath: '' } - * @returns postcss.process() - */ -function processStyleUseCssModule (styleObj) { - const useModuleConf = weappConf.module || {} - const customPostcssConf = useModuleConf.postcss || {} - const customCssModulesConf = Object.assign({ - enable: false, - config: { - generateScopedName: '[name]__[local]___[hash:base64:5]', - namingPattern: 'global' - } - }, customPostcssConf.cssModules || {}) - if (!customCssModulesConf.enable) { - return styleObj - } - const namingPattern = customCssModulesConf.config.namingPattern - if (namingPattern === 'module') { - // 只对 xxx.module.[css|scss|less|styl] 等样式文件做处理 - const DO_USE_CSS_MODULE_REGEX = /^(.*\.module).*\.(css|scss|less|styl)$/ - if (!DO_USE_CSS_MODULE_REGEX.test(styleObj.filePath)) return styleObj - } else { - // 对 xxx.global.[css|scss|less|styl] 等样式文件不做处理 - const DO_NOT_USE_CSS_MODULE_REGEX = /^(.*\.global).*\.(css|scss|less|styl)$/ - if (DO_NOT_USE_CSS_MODULE_REGEX.test(styleObj.filePath)) return styleObj - } - const generateScopedName = customCssModulesConf.config.generateScopedName - const context = process.cwd() - let scopedName - if (generateScopedName) { - scopedName = genericNames(generateScopedName, { context }) - } else { - scopedName = (local, filename) => Scope.generateScopedName(local, path.relative(context, filename)) - } - const postcssPlugins = [ - Values, - LocalByDefault, - ExtractImports, - new Scope({ generateScopedName: scopedName }), - new ResolveImports({ resolve: Object.assign({}, { extensions: Util.CSS_EXT }) }) - ] - const runner = postcss(postcssPlugins) - const result = runner.process(styleObj.css, Object.assign({}, { from: styleObj.filePath })) - return result -} - -async function processStyleWithPostCSS (styleObj) { - const useModuleConf = weappConf.module || {} - const customPostcssConf = useModuleConf.postcss || {} - const customCssModulesConf = Object.assign({ - enable: false, - config: { - generateScopedName: '[name]__[local]___[hash:base64:5]' - } - }, customPostcssConf.cssModules || {}) - const customPxtransformConf = Object.assign({ - enable: true, - config: {} - }, customPostcssConf.pxtransform || {}) - const customUrlConf = Object.assign({ - enable: true, - config: { - limit: 10240 - } - }, customPostcssConf.url || {}) - const customAutoprefixerConf = Object.assign({ - enable: true, - config: { - browsers: browserList - } - }, customPostcssConf.autoprefixer || {}) - const postcssPxtransformOption = { - designWidth: projectConfig.designWidth || 750, - platform: 'weapp' - } - - if (projectConfig.hasOwnProperty(DEVICE_RATIO)) { - postcssPxtransformOption[DEVICE_RATIO] = projectConfig.deviceRatio - } - const cssUrlConf = Object.assign({ limit: 10240 }, customUrlConf) - const maxSize = Math.round((customUrlConf.config.limit || cssUrlConf.limit) / 1024) - const postcssPxtransformConf = Object.assign({}, postcssPxtransformOption, customPxtransformConf, customPxtransformConf.config) - const processors = [] - if (customAutoprefixerConf.enable) { - processors.push(autoprefixer(customAutoprefixerConf.config)) - } - if (customPxtransformConf.enable) { - processors.push(pxtransform(postcssPxtransformConf)) - } - if (cssUrlConf.enable) { - processors.push(cssUrlParse({ - url: 'inline', - maxSize, - encodeType: 'base64' - })) - } - - const defaultPostCSSPluginNames = ['autoprefixer', 'pxtransform', 'url', 'cssModules'] - Object.keys(customPostcssConf).forEach(pluginName => { - if (defaultPostCSSPluginNames.indexOf(pluginName) < 0) { - const pluginConf = customPostcssConf[pluginName] - if (pluginConf && pluginConf.enable) { - if (!Util.isNpmPkg(pluginName)) { // local plugin - pluginName = path.join(appPath, pluginName) - } - processors.push(require(resolveNpmPkgMainPath(pluginName, isProduction, weappNpmConfig, buildAdapter))(pluginConf.config || {})) - } - } - }) - let css = styleObj.css - if (customCssModulesConf.enable) { - css = processStyleUseCssModule(styleObj).css - } - const postcssResult = await postcss(processors).process(css, { - from: styleObj.filePath - }) - return postcssResult.css -} - -function compileImportStyles (filePath, importStyles) { - if (importStyles.length) { - importStyles.forEach(async importItem => { - const importFilePath = path.resolve(filePath, '..', importItem) - if (fs.existsSync(importFilePath)) { - await compileDepStyles(importFilePath.replace(sourceDir, outputDir), [importFilePath]) - } - }) - } -} - -function compileDepStyles (outputFilePath, styleFiles, isComponent) { - if (isBuildingStyles[outputFilePath]) { - return Promise.resolve({}) - } - isBuildingStyles[outputFilePath] = true - return Promise.all(styleFiles.map(async p => { - const filePath = path.join(p) - const fileExt = path.extname(filePath) - const pluginName = Util.FILE_PROCESSOR_MAP[fileExt] - const fileContent = fs.readFileSync(filePath).toString() - const cssImportsRes = Util.processStyleImports(fileContent, buildAdapter, (str, stylePath) => { - if (stylePath.indexOf('~') === 0) { - let newStylePath = stylePath - newStylePath = stylePath.replace('~', '') - const npmInfo = resolveNpmFilesPath(newStylePath, isProduction, weappNpmConfig, buildAdapter, appPath, compileInclude) - const importRelativePath = Util.promoteRelativePath(path.relative(filePath, npmInfo.main)) - return str.replace(stylePath, importRelativePath) - } - return str - }) - compileImportStyles(filePath, cssImportsRes.imports) - if (pluginName) { - return npmProcess.callPlugin(pluginName, cssImportsRes.content, filePath, pluginsConfig[pluginName] || {}) - .then(res => ({ - css: cssImportsRes.style.join('\n') + '\n' + res.css, - filePath - })) - } - return new Promise(resolve => { - resolve({ - css: cssImportsRes.style.join('\n') + '\n' + cssImportsRes.content, - filePath - }) - }) - })).then(async resList => { - Promise.all(resList.map(res => processStyleWithPostCSS(res))) - .then(cssList => { - let resContent = cssList.map(res => res).join('\n') - if (isProduction) { - const cssoPuginConfig = pluginsConfig.csso || { enable: true } - if (cssoPuginConfig.enable) { - const cssoConfig = cssoPuginConfig.config || {} - const cssoResult = npmProcess.callPluginSync('csso', resContent, outputFilePath, cssoConfig) - resContent = cssoResult.css - } - } - fs.ensureDirSync(path.dirname(outputFilePath)) - fs.writeFileSync(outputFilePath, resContent) - }) - }) -} - -function getRealComponentsPathList (filePath, components) { - return components.map(component => { - let componentPath = component.path - if (Util.isAliasPath(componentPath, pathAlias)) { - componentPath = Util.replaceAliasPath(filePath, componentPath, pathAlias) - } - if (Util.isNpmPkg(componentPath)) { - try { - componentPath = resolveNpmPkgMainPath(componentPath, isProduction, weappNpmConfig, buildAdapter) - } catch (err) { - console.log(err) - } - } else { - componentPath = path.resolve(path.dirname(filePath), componentPath) - componentPath = Util.resolveScriptPath(componentPath) - } - if (isFileToBePage(componentPath)) { - Util.printLog(Util.pocessTypeEnum.ERROR, '组件引用', `文件${component.path}已经在 app.js 中被指定为页面,不能再作为组件来引用!`) - } - return { - path: componentPath, - name: component.name, - type: component.type - } - }) -} - -function buildDepComponents (componentPathList, buildConfig) { - return Promise.all(componentPathList.map(componentObj => buildSingleComponent(componentObj, buildConfig))) -} - -function getDepStyleList (outputFilePath, buildDepComponentsResult) { - let depWXSSList = [] - if (buildDepComponentsResult.length) { - depWXSSList = buildDepComponentsResult.map(item => { - let wxss = item.wxss - wxss = wxss.replace(sourceDir, outputDir) - wxss = Util.promoteRelativePath(path.relative(outputFilePath, wxss)) - return wxss - }) - } - return depWXSSList -} - -function buildUsingComponents (filePath, components, isComponent) { - const usingComponents = Object.create(null) - for (const component of components) { - let componentPath = component.path - if (Util.isAliasPath(componentPath, pathAlias)) { - componentPath = Util.replaceAliasPath(filePath, componentPath, pathAlias) - } - componentPath = Util.resolveScriptPath(path.resolve(filePath, '..', componentPath)) - if (fs.existsSync(componentPath)) { - componentPath = Util.promoteRelativePath(path.relative(filePath, componentPath)) - } else { - componentPath = component.path - } - usingComponents[component.name] = componentPath.replace(path.extname(componentPath), '') - } - return Object.assign({}, isComponent ? { component: true } : { usingComponents: {} }, components.length ? { - usingComponents - } : {}) -} - -async function buildSingleComponent (componentObj, buildConfig = {}) { - if (hasBeenBuiltComponents.indexOf(componentObj.path) >= 0 && componentsBuildResult[componentObj.path]) { - return componentsBuildResult[componentObj.path] - } - componentsNamedMap[componentObj.path] = { - name: componentObj.name, - type: componentObj.type - } - const component = componentObj.path - if (!component) { - Util.printLog(Util.pocessTypeEnum.ERROR, '组件错误', `组件${_.upperFirst(_.camelCase(componentObj.name))}路径错误,请检查!(可能原因是导出的组件名不正确)`) - return { - js: null, - wxss: null, - wxml: null - } - } - let componentShowPath = component.replace(appPath + path.sep, '') - componentShowPath = componentShowPath.split(path.sep).join('/') - let isComponentFromNodeModules = false - let sourceDirPath = sourceDir - let buildOutputDir = outputDir - // 来自 node_modules 的组件 - if (NODE_MODULES_REG.test(componentShowPath)) { - isComponentFromNodeModules = true - sourceDirPath = nodeModulesPath - buildOutputDir = npmOutputDir - } - let outputComponentShowPath = componentShowPath.replace(isComponentFromNodeModules ? NODE_MODULES : sourceDirName, buildConfig.outputDirName || outputDirName) - outputComponentShowPath = outputComponentShowPath.replace(path.extname(outputComponentShowPath), '') - Util.printLog(Util.pocessTypeEnum.COMPILE, '组件文件', componentShowPath) - const componentContent = fs.readFileSync(component).toString() - const outputComponentJSPath = component.replace(sourceDirPath, buildConfig.outputDir || buildOutputDir).replace(path.extname(component), outputFilesTypes.SCRIPT) - const outputComponentWXMLPath = outputComponentJSPath.replace(path.extname(outputComponentJSPath), outputFilesTypes.TEMPL) - const outputComponentWXSSPath = outputComponentJSPath.replace(path.extname(outputComponentJSPath), outputFilesTypes.STYLE) - const outputComponentJSONPath = outputComponentJSPath.replace(path.extname(outputComponentJSPath), outputFilesTypes.CONFIG) - if (hasBeenBuiltComponents.indexOf(component) < 0) { - hasBeenBuiltComponents.push(component) - } - try { - let isTaroComponentRes = isFileToBeTaroComponent(componentContent, component, outputComponentJSPath) - if (!isTaroComponentRes.isTaroComponent) { - const transformResult = isTaroComponentRes.transformResult - const componentRealPath = parseComponentExportAst(transformResult.ast, componentObj.name, component, componentObj.type) - const realComponentObj = { - path: componentRealPath, - name: componentObj.name, - type: componentObj.type - } - let isInMap = false - if (notTaroComponents.indexOf(component) < 0) { - notTaroComponents.push(component) - } - if (!Util.isEmptyObject(componentExportsMap)) { - Object.keys(componentExportsMap).forEach(key => { - componentExportsMap[key].forEach(item => { - if (item.path === component) { - isInMap = true - item.path = componentRealPath - } - }) - }) - } - if (!isInMap) { - componentExportsMap[component] = componentExportsMap[component] || [] - componentExportsMap[component].push(realComponentObj) - } - return await buildSingleComponent(realComponentObj, buildConfig) - } - const transformResult = wxTransformer({ - code: componentContent, - sourcePath: component, - outputPath: outputComponentJSPath, - isRoot: false, - isTyped: Util.REG_TYPESCRIPT.test(component), - isNormal: false, - adapter: buildAdapter, - env: constantsReplaceList - }) - const compressTemplate = useCompileConf.compressTemplate - const componentWXMLContent = (isProduction && compressTemplate) ? transformResult.compressedTemplate : transformResult.template - const componentDepComponents = transformResult.components - const res = parseAst(PARSE_AST_TYPE.COMPONENT, transformResult.ast, componentDepComponents, component, outputComponentJSPath, buildConfig.npmSkip) - let resCode = res.code - resCode = await compileScriptFile(resCode, component, outputComponentJSPath, buildAdapter) - fs.ensureDirSync(path.dirname(outputComponentJSPath)) - if (isProduction) { - const uglifyPluginConfig = pluginsConfig.uglify || { enable: true } - if (uglifyPluginConfig.enable) { - const uglifyConfig = Object.assign(defaultUglifyConfig, uglifyPluginConfig.config || {}) - const uglifyResult = npmProcess.callPluginSync('uglifyjs', resCode, outputComponentJSPath, uglifyConfig) - if (uglifyResult.error) { - Util.printLog(Util.pocessTypeEnum.ERROR, '压缩错误', `文件${component}`) - console.log(uglifyResult.error) - } else { - resCode = uglifyResult.code - } - } - } - const { usingComponents = {} } = res.configObj - if (usingComponents && !Util.isEmptyObject(usingComponents)) { - const keys = Object.keys(usingComponents) - keys.forEach(item => { - componentDepComponents.forEach(component => { - if (_.camelCase(item) === _.camelCase(component.name)) { - delete usingComponents[item] - } - }) - }) - transfromNativeComponents(outputComponentJSONPath.replace(buildConfig.outputDir || buildOutputDir, sourceDirPath), res.configObj) - } - - const fileDep = dependencyTree[component] || {} - // 编译依赖的组件文件 - let buildDepComponentsResult = [] - let realComponentsPathList = [] - if (componentDepComponents.length) { - realComponentsPathList = getRealComponentsPathList(component, componentDepComponents) - res.scriptFiles = res.scriptFiles.map(item => { - for (let i = 0; i < realComponentsPathList.length; i++) { - const componentObj = realComponentsPathList[i] - const componentPath = componentObj.path - if (item === componentPath) { - return null - } - } - return item - }).filter(item => item) - realComponentsPathList = realComponentsPathList.filter(item => hasBeenBuiltComponents.indexOf(item.path) < 0 || notTaroComponents.indexOf(item.path) >= 0) - buildDepComponentsResult = await buildDepComponents(realComponentsPathList) - } - if (!Util.isEmptyObject(componentExportsMap) && realComponentsPathList.length) { - const mapKeys = Object.keys(componentExportsMap) - realComponentsPathList.forEach(componentObj => { - if (mapKeys.indexOf(componentObj.path) >= 0) { - const componentMap = componentExportsMap[componentObj.path] - componentMap.forEach(componentObj => { - componentDepComponents.forEach(depComponent => { - if (depComponent.name === componentObj.name) { - let componentPath = componentObj.path - let realPath - if (NODE_MODULES_REG.test(componentPath)) { - componentPath = componentPath.replace(nodeModulesPath, npmOutputDir) - realPath = Util.promoteRelativePath(path.relative(outputComponentJSPath, componentPath)) - } else { - realPath = Util.promoteRelativePath(path.relative(component, componentPath)) - } - depComponent.path = realPath.replace(path.extname(realPath), '') - } - }) - }) - } - }) - } - fs.writeFileSync(outputComponentJSONPath, JSON.stringify(_.merge({}, buildUsingComponents(component, componentDepComponents, true), res.configObj), null, 2)) - Util.printLog(Util.pocessTypeEnum.GENERATE, '组件配置', `${outputDirName}/${outputComponentShowPath}${outputFilesTypes.CONFIG}`) - fs.writeFileSync(outputComponentJSPath, resCode) - Util.printLog(Util.pocessTypeEnum.GENERATE, '组件逻辑', `${outputDirName}/${outputComponentShowPath}${outputFilesTypes.SCRIPT}`) - fs.writeFileSync(outputComponentWXMLPath, componentWXMLContent) - processNativeWxml(outputComponentWXMLPath.replace(outputDir, sourceDir), componentWXMLContent, outputComponentWXMLPath) - Util.printLog(Util.pocessTypeEnum.GENERATE, '组件模板', `${outputDirName}/${outputComponentShowPath}${outputFilesTypes.TEMPL}`) - // 编译依赖的脚本文件 - if (Util.isDifferentArray(fileDep['script'], res.scriptFiles)) { - compileDepScripts(res.scriptFiles) - } - // 编译样式文件 - if (Util.isDifferentArray(fileDep['style'], res.styleFiles) || Util.isDifferentArray(depComponents[component], componentDepComponents)) { - Util.printLog(Util.pocessTypeEnum.GENERATE, '组件样式', `${outputDirName}/${outputComponentShowPath}${outputFilesTypes.STYLE}`) - const depStyleList = getDepStyleList(outputComponentWXSSPath, buildDepComponentsResult) - wxssDepTree[outputComponentWXSSPath] = depStyleList - await compileDepStyles(outputComponentWXSSPath, res.styleFiles, true) - } - // 拷贝依赖文件 - if (Util.isDifferentArray(fileDep['json'], res.jsonFiles)) { - copyFilesFromSrcToOutput(res.jsonFiles) - } - if (Util.isDifferentArray(fileDep['media'], res.mediaFiles)) { - copyFilesFromSrcToOutput(res.mediaFiles) - } - fileDep['style'] = res.styleFiles - fileDep['script'] = res.scriptFiles - fileDep['json'] = res.jsonFiles - fileDep['media'] = res.mediaFiles - dependencyTree[component] = fileDep - depComponents[component] = componentDepComponents - componentsBuildResult[component] = { - js: outputComponentJSPath, - wxss: outputComponentWXSSPath, - wxml: outputComponentWXMLPath - } - return componentsBuildResult[component] - } catch (err) { - Util.printLog(Util.pocessTypeEnum.ERROR, '组件编译', `组件${componentShowPath}编译失败!`) - console.log(err) - } -} - -function compileDepScripts (scriptFiles) { - scriptFiles.forEach(async item => { - if (path.isAbsolute(item)) { - let outputItem - if (NODE_MODULES_REG.test(item)) { - outputItem = item.replace(nodeModulesPath, npmOutputDir).replace(path.extname(item), '.js') - } else { - outputItem = item.replace(path.join(sourceDir), path.join(outputDir)).replace(path.extname(item), '.js') - } - const useCompileConf = Object.assign({}, weappConf.compile) - const compileExclude = useCompileConf.exclude || [] - let isInCompileExclude = false - compileExclude.forEach(excludeItem => { - if (item.indexOf(path.join(appPath, excludeItem)) >= 0) { - isInCompileExclude = true - } - }) - if (isInCompileExclude) { - copyFileSync(item, outputItem) - return - } - if (!isBuildingScripts[outputItem]) { - isBuildingScripts[outputItem] = true - try { - const code = fs.readFileSync(item).toString() - const transformResult = wxTransformer({ - code, - sourcePath: item, - outputPath: outputItem, - isNormal: true, - isTyped: Util.REG_TYPESCRIPT.test(item), - adapter: buildAdapter, - env: constantsReplaceList - }) - const ast = transformResult.ast - const res = parseAst(PARSE_AST_TYPE.NORMAL, ast, [], item, outputItem) - const fileDep = dependencyTree[item] || {} - let resCode = res.code - resCode = await compileScriptFile(res.code, item, outputItem, buildAdapter) - fs.ensureDirSync(path.dirname(outputItem)) - if (isProduction) { - const uglifyPluginConfig = pluginsConfig.uglify || { enable: true } - if (uglifyPluginConfig.enable) { - const uglifyConfig = Object.assign(defaultUglifyConfig, uglifyPluginConfig.config || {}) - const uglifyResult = npmProcess.callPluginSync('uglifyjs', resCode, item, uglifyConfig) - if (uglifyResult.error) { - Util.printLog(Util.pocessTypeEnum.ERROR, '压缩错误', `文件${item}`) - console.log(uglifyResult.error) - } else { - resCode = uglifyResult.code - } - } - } - fs.writeFileSync(outputItem, resCode) - let modifyOutput = outputItem.replace(appPath + path.sep, '') - modifyOutput = modifyOutput.split(path.sep).join('/') - Util.printLog(Util.pocessTypeEnum.GENERATE, '依赖文件', modifyOutput) - // 编译依赖的脚本文件 - if (Util.isDifferentArray(fileDep['script'], res.scriptFiles)) { - compileDepScripts(res.scriptFiles) - } - // 拷贝依赖文件 - if (Util.isDifferentArray(fileDep['json'], res.jsonFiles)) { - copyFilesFromSrcToOutput(res.jsonFiles) - } - if (Util.isDifferentArray(fileDep['media'], res.mediaFiles)) { - copyFilesFromSrcToOutput(res.mediaFiles) - } - fileDep['script'] = res.scriptFiles - fileDep['json'] = res.jsonFiles - fileDep['media'] = res.mediaFiles - dependencyTree[item] = fileDep - } catch (err) { - Util.printLog(Util.pocessTypeEnum.ERROR, '编译失败', item.replace(appPath + path.sep, '')) - console.log(err) - } - } - } - }) -} - -function copyFileSync (from, to, options) { - const filename = path.basename(from) - if (fs.statSync(from).isFile() && !path.extname(to)) { - fs.ensureDir(to) - if (from === path.join(to, filename)) { - return - } - return fs.copySync(from, path.join(to, filename), options) - } - if (from === to) { - return - } - fs.ensureDir(path.dirname(to)) - return fs.copySync(from, to, options) -} - -function copyFiles () { - const copyConfig = projectConfig.copy || { patterns: [], options: {} } - if (copyConfig.patterns && copyConfig.patterns.length) { - copyConfig.options = copyConfig.options || {} - const globalIgnore = copyConfig.options.ignore - const projectDir = appPath - copyConfig.patterns.forEach(pattern => { - if (typeof pattern === 'object' && pattern.from && pattern.to) { - const from = path.join(projectDir, pattern.from) - const to = path.join(projectDir, pattern.to) - let ignore = pattern.ignore || globalIgnore - if (fs.existsSync(from)) { - const copyOptions = {} - if (ignore) { - ignore = Array.isArray(ignore) ? ignore : [ignore] - copyOptions.filter = src => { - let isMatch = false - ignore.forEach(iPa => { - if (minimatch(path.basename(src), iPa)) { - isMatch = true - } - }) - return !isMatch - } - } - copyFileSync(from, to, copyOptions) - } else { - Util.printLog(Util.pocessTypeEnum.ERROR, '拷贝失败', `${pattern.from} 文件不存在!`) - } - } - }) - } -} - -function watchFiles () { - console.log() - console.log(chalk.gray('监听文件修改中...')) - console.log() - isBuildingScripts = {} - isBuildingStyles = {} - isCopyingFiles = {} - const watcherPaths = [path.join(sourceDir)].concat(watcherDirs) - const watcher = chokidar.watch(watcherPaths, { - ignored: /(^|[/\\])\../, - persistent: true, - ignoreInitial: true - }) - watcher - .on('addDir', dirPath => { - console.log(dirPath) - }) - .on('add', filePath => { - console.log(filePath) - }) - .on('change', async filePath => { - const extname = path.extname(filePath) - // 编译JS文件 - if (Util.REG_SCRIPT.test(extname) || Util.REG_TYPESCRIPT.test(extname)) { - if (filePath.indexOf(entryFileName) >= 0) { - Util.printLog(Util.pocessTypeEnum.MODIFY, '入口文件', `${sourceDirName}/${entryFileName}.js`) - const config = await buildEntry() - // TODO 此处待优化 - if ((Util.checksum(JSON.stringify(config.pages)) !== Util.checksum(JSON.stringify(appConfig.pages))) || - (Util.checksum(JSON.stringify(config.subPackages || config.subpackages || {})) !== Util.checksum(JSON.stringify(appConfig.subPackages || appConfig.subpackages || {})))) { - appConfig = config - await buildPages() - } - } else { - const filePathWithoutExt = filePath.replace(extname, '') - if (isFileToBePage(filePath)) { // 编译页面 - filePath = filePathWithoutExt - filePath = filePath.replace(path.join(sourceDir) + path.sep, '') - filePath = filePath.split(path.sep).join('/') - Util.printLog(Util.pocessTypeEnum.MODIFY, '页面文件', `${sourceDirName}/${filePath}`) - await buildSinglePage(filePath) - } else if (hasBeenBuiltComponents.indexOf(filePath) >= 0) { // 编译组件 - let outoutShowFilePath = filePath.replace(appPath + path.sep, '') - outoutShowFilePath = outoutShowFilePath.split(path.sep).join('/') - Util.printLog(Util.pocessTypeEnum.MODIFY, '组件文件', outoutShowFilePath) - const hasbeenBuiltIndex = hasBeenBuiltComponents.indexOf(filePath) - if (hasbeenBuiltIndex >= 0) { - hasBeenBuiltComponents.splice(hasbeenBuiltIndex, 1) - } - - if (isWindows) { - await new Promise((resolve, reject) => { - setTimeout(async () => { - await buildSingleComponent(Object.assign({ - path: filePath - }, componentsNamedMap[filePath])) - resolve() - }, 300) - }) - } else { - await buildSingleComponent(Object.assign({ - path: filePath - }, componentsNamedMap[filePath])) - } - } else { - let isImported = false - for (const key in dependencyTree) { - const scripts = dependencyTree[key].script || [] - if (scripts.indexOf(filePath) >= 0) { - isImported = true - } - } - let modifySource = filePath.replace(appPath + path.sep, '') - modifySource = modifySource.split(path.sep).join('/') - if (isImported) { - Util.printLog(Util.pocessTypeEnum.MODIFY, 'JS文件', modifySource) - compileDepScripts([filePath]) - } else { - Util.printLog(Util.pocessTypeEnum.WARNING, 'JS文件', `${modifySource} 没有被引用到,不会被编译`) - } - } - } - } else if (Util.REG_STYLE.test(extname)) { - const includeStyleJSPath = [] - for (const key in dependencyTree) { - const styles = dependencyTree[key]['style'] || [] - styles.forEach(item => { - if (item === filePath) { - includeStyleJSPath.push({ - filePath: key, - styles - }) - } - }) - } - if (includeStyleJSPath.length) { - includeStyleJSPath.forEach(async item => { - let outputWXSSPath = null - outputWXSSPath = item.filePath.replace(path.extname(item.filePath), outputFilesTypes.STYLE) - let modifySource = outputWXSSPath.replace(appPath + path.sep, '') - modifySource = modifySource.split(path.sep).join('/') - Util.printLog(Util.pocessTypeEnum.MODIFY, '样式文件', modifySource) - if (NODE_MODULES_REG.test(outputWXSSPath)) { - let sourceNodeModulesDir = nodeModulesPath - let outputNodeModulesDir = npmOutputDir - outputWXSSPath = outputWXSSPath.replace(sourceNodeModulesDir, outputNodeModulesDir) - } else { - outputWXSSPath = outputWXSSPath.replace(sourceDir, outputDir) - } - let modifyOutput = outputWXSSPath.replace(appPath + path.sep, '') - modifyOutput = modifyOutput.split(path.sep).join('/') - let isComponent = false - if (!isFileToBePage(item.filePath) && item.filePath !== entryFilePath) { - isComponent = true - } - if (isWindows) { - await new Promise((resolve, reject) => { - setTimeout(async () => { - await compileDepStyles(outputWXSSPath, item.styles, isComponent) - resolve() - }, 300) - }) - } else { - await compileDepStyles(outputWXSSPath, item.styles, isComponent) - } - Util.printLog(Util.pocessTypeEnum.GENERATE, '样式文件', modifyOutput) - }) - } else { - let outputWXSSPath = filePath.replace(path.extname(filePath), outputFilesTypes.STYLE) - let modifySource = outputWXSSPath.replace(appPath + path.sep, '') - modifySource = modifySource.split(path.sep).join('/') - Util.printLog(Util.pocessTypeEnum.MODIFY, '样式文件', modifySource) - if (NODE_MODULES_REG.test(outputWXSSPath)) { - let sourceNodeModulesDir = nodeModulesPath - let outputNodeModulesDir = npmOutputDir - outputWXSSPath = outputWXSSPath.replace(sourceNodeModulesDir, outputNodeModulesDir) - } else { - outputWXSSPath = outputWXSSPath.replace(sourceDir, outputDir) - } - let modifyOutput = outputWXSSPath.replace(appPath + path.sep, '') - modifyOutput = modifyOutput.split(path.sep).join('/') - if (isWindows) { - await new Promise((resolve, reject) => { - setTimeout(async () => { - await compileDepStyles(outputWXSSPath, [filePath], false) - resolve() - }, 300) - }) - } else { - await compileDepStyles(outputWXSSPath, [filePath], false) - } - Util.printLog(Util.pocessTypeEnum.GENERATE, '样式文件', modifyOutput) - } - } else { - let modifySource = filePath.replace(appPath + path.sep, '') - modifySource = modifySource.split(path.sep).join('/') - Util.printLog(Util.pocessTypeEnum.MODIFY, '文件', modifySource) - copyFilesFromSrcToOutput([filePath]) - } - isBuildingScripts = {} - isBuildingStyles = {} - isCopyingFiles = {} - }) -} - -async function build ({ watch, adapter }) { - process.env.TARO_ENV = adapter - isProduction = process.env.NODE_ENV === 'production' || !watch - buildAdapter = adapter - outputFilesTypes = Util.MINI_APP_FILES[buildAdapter] - // 可以自定义输出文件类型 - if (weappConf.customFilesTypes && !Util.isEmptyObject(weappConf.customFilesTypes)) { - outputFilesTypes = Object.assign({}, outputFilesTypes, weappConf.customFilesTypes[buildAdapter] || {}) - } - constantsReplaceList = Object.assign({}, constantsReplaceList, { - 'process.env.TARO_ENV': buildAdapter - }) - buildProjectConfig() - await buildFrameworkInfo() - copyFiles() - appConfig = await buildEntry() - await buildPages() - if (watch) { - watchFiles() - } -} - -module.exports = { - build, - buildDepComponents, - buildSingleComponent, - compileDepStyles, - parseAst -} diff --git a/packages/taro-cli/tsconfig.json b/packages/taro-cli/tsconfig.json new file mode 100644 index 000000000000..28033d388ab9 --- /dev/null +++ b/packages/taro-cli/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "allowJs": true, + "baseUrl": ".", + "experimentalDecorators": true, + "lib": ["esnext", "dom"], + "module": "commonjs", + "moduleResolution": "node", + "resolveJsonModule": true, + "noImplicitAny": false, + "noUnusedLocals": true, + "outDir": "dist/", + "preserveConstEnums": true, + "removeComments": false, + "rootDir": "./src", + "sourceMap": false, + "strictNullChecks": true, + "target": "es2015", + "traceResolution": false, + "types" : ["node"] + }, + "include": [ + "./src" + ] +} diff --git a/packages/taro-cli/tslint.json b/packages/taro-cli/tslint.json new file mode 100644 index 000000000000..fa1c9fc90ffb --- /dev/null +++ b/packages/taro-cli/tslint.json @@ -0,0 +1,31 @@ +{ + "extends": [ + "tslint-config-standard", + "tslint-config-prettier" + ], + "defaultSeverity": "error", + "rules": { + "ban-types": false, + "forin": false, + "interface-name": false, + "member-access": false, + "no-bitwise": false, + "no-conditional-assignment": false, + "no-console": false, + "no-empty": false, + "no-object-literal-type-assertion": false, + "no-string-literal": false, + "no-var-keyword": true, + "object-literal-key-quotes": [ false, "as-needed" ], + "object-literal-sort-keys": false, + "one-variable-per-declaration": false, + "ordered-imports": false, + "prefer-for-of": false, + "quotemark": [ true, "single", "avoid-escape", "jsx-double" ], + "semicolon": [ false, "never" ], + "space-before-function-paren": false, + "trailing-comma": [ true, { "multiline": "never", "singleline": "never" } ], + "variable-name": [ true, "allow-leading-underscore", "ban-keywords" ], + "prefer-const": true + } +} diff --git a/packages/taro/types/index.d.ts b/packages/taro/types/index.d.ts index 00e9128fad63..7d1fbc755e6d 100644 --- a/packages/taro/types/index.d.ts +++ b/packages/taro/types/index.d.ts @@ -299,7 +299,8 @@ declare namespace Taro { * ] * @since 1.7.3 */ - subPackages?: SubPackage[] + subPackages?: SubPackage[], + subpackages?: SubPackage[] /** * Worker 代码放置的目录 * 使用 Worker 处理多线程任务时,设置 Worker 代码放置的目录 @@ -441,7 +442,7 @@ declare namespace Taro { function getEnv(): ENV_TYPE.WEAPP | ENV_TYPE.WEB | ENV_TYPE.RN | ENV_TYPE.ALIPAY | ENV_TYPE.TT | ENV_TYPE.SWAN; - function render(component: Component | JSX.Element, element: Element | null): any; + function render(component: Component | any, element: Element | null): any; function internal_safe_set (...arg: any[]): any; function internal_safe_get (...arg: any[]): any; From 38643f8a7fbe3d5b1db7ee29b1503edb2e108c38 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Wed, 2 Jan 2019 14:23:11 +0800 Subject: [PATCH 012/103] =?UTF-8?q?fix(cli):=20=E4=BF=AE=E5=A4=8D=E5=BC=95?= =?UTF-8?q?=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/bin/taro-convert | 2 +- packages/taro-cli/bin/taro-doctor | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/taro-cli/bin/taro-convert b/packages/taro-cli/bin/taro-convert index aac8fd0c6410..42cee5e7cd85 100755 --- a/packages/taro-cli/bin/taro-convert +++ b/packages/taro-cli/bin/taro-convert @@ -2,7 +2,7 @@ const program = require('commander') -const Convertor = require('../dist/convertor') +const Convertor = require('../dist/convertor').default program .parse(process.argv) diff --git a/packages/taro-cli/bin/taro-doctor b/packages/taro-cli/bin/taro-doctor index a0b60c550d83..b57e4febddb1 100755 --- a/packages/taro-cli/bin/taro-doctor +++ b/packages/taro-cli/bin/taro-doctor @@ -14,7 +14,7 @@ if (!fs.existsSync(PROJECT_CONF_PATH)) { process.exit(1) } -const { validators } = require('../dist/doctor') +const { validators } = require('../dist/doctor').default const NOTE_ALL_RIGHT = chalk.green('[✓] ') const NOTE_VALID = chalk.yellow('[!] ') From b897397ed6c2dfc3f235a8042cbb1ac57c43936d Mon Sep 17 00:00:00 2001 From: liliangquan Date: Thu, 3 Jan 2019 19:32:57 +0800 Subject: [PATCH 013/103] =?UTF-8?q?feat(taro-components-qa):=20=E5=BF=AB?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E7=9B=B8=E5=85=B3=E7=BB=84=E4=BB=B6=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/audio/img.js | 4 + .../src/components/audio/index.ux | 195 ++++++++++++++++++ .../src/components/button.js/img.js | 1 + .../src/components/button.js/index.ux | 155 ++++++++++++++ .../src/components/camera/index.ux | 80 +++++++ .../src/components/icon/index.ux | 132 ++++++++++++ .../src/components/image/index.ux | 84 ++++++++ .../src/components/input/index.ux | 113 ++++++++++ .../src/components/label/index.ux | 55 +++++ .../src/components/navigator/index.ux | 81 ++++++++ .../src/components/picker/index.ux | 160 ++++++++++++++ .../src/components/progress/index.ux | 106 ++++++++++ .../src/components/radio/index.ux | 70 +++++++ .../src/components/rich_text/index.ux | 53 +++++ .../src/components/slider/index.ux | 115 +++++++++++ .../src/components/swiper/index.ux | 90 ++++++++ .../src/components/switch/index.ux | 82 ++++++++ .../src/components/text/index.ux | 50 +++++ .../src/components/textarea/index.ux | 74 +++++++ .../src/components/video/index.ux | 126 +++++++++++ .../src/components/view/index.ux | 55 +++++ 21 files changed, 1881 insertions(+) create mode 100644 packages/taro-components-qa/src/components/audio/img.js create mode 100644 packages/taro-components-qa/src/components/audio/index.ux create mode 100644 packages/taro-components-qa/src/components/button.js/img.js create mode 100644 packages/taro-components-qa/src/components/button.js/index.ux create mode 100644 packages/taro-components-qa/src/components/camera/index.ux create mode 100644 packages/taro-components-qa/src/components/icon/index.ux create mode 100644 packages/taro-components-qa/src/components/image/index.ux create mode 100644 packages/taro-components-qa/src/components/input/index.ux create mode 100644 packages/taro-components-qa/src/components/label/index.ux create mode 100644 packages/taro-components-qa/src/components/navigator/index.ux create mode 100644 packages/taro-components-qa/src/components/picker/index.ux create mode 100644 packages/taro-components-qa/src/components/progress/index.ux create mode 100644 packages/taro-components-qa/src/components/radio/index.ux create mode 100644 packages/taro-components-qa/src/components/rich_text/index.ux create mode 100644 packages/taro-components-qa/src/components/slider/index.ux create mode 100644 packages/taro-components-qa/src/components/swiper/index.ux create mode 100644 packages/taro-components-qa/src/components/switch/index.ux create mode 100644 packages/taro-components-qa/src/components/text/index.ux create mode 100644 packages/taro-components-qa/src/components/textarea/index.ux create mode 100644 packages/taro-components-qa/src/components/video/index.ux create mode 100644 packages/taro-components-qa/src/components/view/index.ux diff --git a/packages/taro-components-qa/src/components/audio/img.js b/packages/taro-components-qa/src/components/audio/img.js new file mode 100644 index 000000000000..3347b3ac540a --- /dev/null +++ b/packages/taro-components-qa/src/components/audio/img.js @@ -0,0 +1,4 @@ +export const PAUSE_IMG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAABMklEQVRoQ+2Z0Y3CQAxE7QqOEqAjbwd0QAmEDijhOliXBBVAB0YrATqdkGxl10SRZn/XmXiek/kx08oPr7x/goGlJ4gJrGICIrIhoiMR7YnoTkS/qnoa1XyPfugTEpEzMx/+NmxmJ1WdRpjo0Y8auDFzm8L7mNlFVXeDDMzWDxkopdinRmutoec9kz36oQZ6XuA13+579GEgQtirwQQyCXna+AeyCWXrI4UihL0apFAmIU8bKZRNKFsfKRQh7NUghTIJedpIoWxC2fpIoQhhrwYplEnI00YKZRPK1kcKRQh7NUihTEKe9rdSqC01fv41c621biMNejWllNn6oZ9YRCZmbhua9xm84JitHzLQun6aaCsmMrO2YhqynXkRmasfNuB9Bkvdw8BS5F/vxQQwgU4CD9RcRkCIkNZgAAAAAElFTkSuQmCC' +export const START_IMG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAB2klEQVRoQ9WZfVEEMQzFEwXgACSAk+IAHIAC7hRwKAAJwQE4AAWAA1DwmDdTZjo3cNtuu023f3d282s+XtKqrHzpyu2XIoAQwqmZfYwEnQUQQggi8qCqxwC+RGRjZvcjgEwC8NRV9X3fWADPInJhZgRyWzkA16p695eF0RuEIIzLygHYqOrtIesA7MzsxoOgCQANB/AaQ6prkjcDiBDMhxsze+zljaYAv0YDMBG56pHgiwBEbzCUmOAMrcXWYgCJN6gZ26UIFgeI3lhMM7oAJAnOvGB+NFvdAJKQaqoZ3QESzaA3qhPcBaClZrgBtNIMd4BazRgCoEYzhgKYoxnDASQJnjVnDAmQQJxPzeDDAkSIrZltDsn26ACcLXZrBfgGcLbWEPoEEHJajRFD6AnAZe40NxIAQ4bDz8GY38+HUQDe4qkXd6fuAAB4RcmTn3XD5wnAkGGsV01oXgAv0fjqS7DuAAAm1bVkYO4JwNrOkGl6EdwLoKi2j+SBWbV9FIDZtd0doLa2ewI0qe1eAKzt7CBnKWqJ0eneJlWodW0vgckB+PeRT0Sy+/YSo0r25gDwmZVd4tHehxer7U0B+DE+dKsq+/QTEemeqFUzcclpeOydDCEPo0r+uXqAHzf0dkAxk0BxAAAAAElFTkSuQmCC' + +export default PAUSE_IMG \ No newline at end of file diff --git a/packages/taro-components-qa/src/components/audio/index.ux b/packages/taro-components-qa/src/components/audio/index.ux new file mode 100644 index 000000000000..8bd09fe4b175 --- /dev/null +++ b/packages/taro-components-qa/src/components/audio/index.ux @@ -0,0 +1,195 @@ + + + + \ No newline at end of file diff --git a/packages/taro-components-qa/src/components/button.js/img.js b/packages/taro-components-qa/src/components/button.js/img.js new file mode 100644 index 000000000000..619081d152a4 --- /dev/null +++ b/packages/taro-components-qa/src/components/button.js/img.js @@ -0,0 +1 @@ +export default 'data:image/gif;base64,R0lGODlhgACAAKIAAP///93d3bu7u5mZmQAA/wAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFBQAEACwCAAIAfAB8AAAD/0i63P4wygYqmDjrzbtflvWNZGliYXiubKuloivPLlzReD7al+7/Eh5wSFQIi8hHYBkwHUmD6CD5YTJLz49USuVYraRsZ7vtar7XnQ1Kjpoz6LRHvGlz35O4nEPP2O94EnpNc2sef1OBGIOFMId/inB6jSmPdpGScR19EoiYmZobnBCIiZ95k6KGGp6ni4wvqxilrqBfqo6skLW2YBmjDa28r6Eosp27w8Rov8ekycqoqUHODrTRvXsQwArC2NLF29UM19/LtxO5yJd4Au4CK7DUNxPebG4e7+8n8iv2WmQ66BtoYpo/dvfacBjIkITBE9DGlMvAsOIIZjIUAixliv9ixYZVtLUos5GjwI8gzc3iCGghypQqrbFsme8lwZgLZtIcYfNmTJ34WPTUZw5oRxdD9w0z6iOpO15MgTh1BTTJUKos39jE+o/KS64IFVmsFfYT0aU7capdy7at27dw48qdS7eu3bt480I02vUbX2F/JxYNDImw4GiGE/P9qbhxVpWOI/eFKtlNZbWXuzlmG1mv58+gQ4seTbq06dOoU6vGQZJy0FNlMcV+czhQ7SQmYd8eMhPs5BxVdfcGEtV3buDBXQ+fURxx8oM6MT9P+Fh6dOrH2zavc13u9JXVJb520Vp8dvC76wXMuN5Sepm/1WtkEZHDefnzR9Qvsd9+/wi8+en3X0ntYVcSdAE+UN4zs7ln24CaLagghIxBaGF8kFGoIYV+Ybghh841GIyI5ICIFoklJsigihmimJOLEbLYIYwxSgigiZ+8l2KB+Ml4oo/w8dijjcrouCORKwIpnJIjMnkkksalNeR4fuBIm5UEYImhIlsGCeWNNJphpJdSTlkml1jWeOY6TnaRpppUctcmFW9mGSaZceYopH9zkjnjUe59iR5pdapWaGqHopboaYua1qije67GJ6CuJAAAIfkEBQUABAAsCgACAFcAMAAAA/9Iutz+ML5Ag7w46z0r5WAoSp43nihXVmnrdusrv+s332dt4Tyo9yOBUJD6oQBIQGs4RBlHySSKyczVTtHoidocPUNZaZAr9F5FYbGI3PWdQWn1mi36buLKFJvojsHjLnshdhl4L4IqbxqGh4gahBJ4eY1kiX6LgDN7fBmQEJI4jhieD4yhdJ2KkZk8oiSqEaatqBekDLKztBG2CqBACq4wJRi4PZu1sA2+v8C6EJexrBAD1AOBzsLE0g/V1UvYR9sN3eR6lTLi4+TlY1wz6Qzr8u1t6FkY8vNzZTxaGfn6mAkEGFDgL4LrDDJDyE4hEIbdHB6ESE1iD4oVLfLAqPETIsOODwmCDJlv5MSGJklaS6khAQAh+QQFBQAEACwfAAIAVwAwAAAD/0i63P5LSAGrvTjrNuf+YKh1nWieIumhbFupkivPBEzR+GnnfLj3ooFwwPqdAshAazhEGUXJJIrJ1MGOUamJ2jQ9QVltkCv0XqFh5IncBX01afGYnDqD40u2z76JK/N0bnxweC5sRB9vF34zh4gjg4uMjXobihWTlJUZlw9+fzSHlpGYhTminKSepqebF50NmTyor6qxrLO0L7YLn0ALuhCwCrJAjrUqkrjGrsIkGMW/BMEPJcphLgDaABjUKNEh29vdgTLLIOLpF80s5xrp8ORVONgi8PcZ8zlRJvf40tL8/QPYQ+BAgjgMxkPIQ6E6hgkdjoNIQ+JEijMsasNY0RQix4gKP+YIKXKkwJIFF6JMudFEAgAh+QQFBQAEACw8AAIAQgBCAAAD/kg0PPowykmrna3dzXvNmSeOFqiRaGoyaTuujitv8Gx/661HtSv8gt2jlwIChYtc0XjcEUnMpu4pikpv1I71astytkGh9wJGJk3QrXlcKa+VWjeSPZHP4Rtw+I2OW81DeBZ2fCB+UYCBfWRqiQp0CnqOj4J1jZOQkpOUIYx/m4oxg5cuAaYBO4Qop6c6pKusrDevIrG2rkwptrupXB67vKAbwMHCFcTFxhLIt8oUzLHOE9Cy0hHUrdbX2KjaENzey9Dh08jkz8Tnx83q66bt8PHy8/T19vf4+fr6AP3+/wADAjQmsKDBf6AOKjS4aaHDgZMeSgTQcKLDhBYPEswoA1BBAgAh+QQFBQAEACxOAAoAMABXAAAD7Ei6vPOjyUkrhdDqfXHm4OZ9YSmNpKmiqVqykbuysgvX5o2HcLxzup8oKLQQix0UcqhcVo5ORi+aHFEn02sDeuWqBGCBkbYLh5/NmnldxajX7LbPBK+PH7K6narfO/t+SIBwfINmUYaHf4lghYyOhlqJWgqDlAuAlwyBmpVnnaChoqOkpaanqKmqKgGtrq+wsbA1srW2ry63urasu764Jr/CAb3Du7nGt7TJsqvOz9DR0tPU1TIA2ACl2dyi3N/aneDf4uPklObj6OngWuzt7u/d8fLY9PXr9eFX+vv8+PnYlUsXiqC3c6PmUUgAACH5BAUFAAQALE4AHwAwAFcAAAPpSLrc/m7IAau9bU7MO9GgJ0ZgOI5leoqpumKt+1axPJO1dtO5vuM9yi8TlAyBvSMxqES2mo8cFFKb8kzWqzDL7Xq/4LB4TC6bz1yBes1uu9uzt3zOXtHv8xN+Dx/x/wJ6gHt2g3Rxhm9oi4yNjo+QkZKTCgGWAWaXmmOanZhgnp2goaJdpKGmp55cqqusrZuvsJays6mzn1m4uRAAvgAvuBW/v8GwvcTFxqfIycA3zA/OytCl0tPPO7HD2GLYvt7dYd/ZX99j5+Pi6tPh6+bvXuTuzujxXens9fr7YPn+7egRI9PPHrgpCQAAIfkEBQUABAAsPAA8AEIAQgAAA/lIutz+UI1Jq7026h2x/xUncmD5jehjrlnqSmz8vrE8u7V5z/m5/8CgcEgsGo/IpHLJbDqf0Kh0ShBYBdTXdZsdbb/Yrgb8FUfIYLMDTVYz2G13FV6Wz+lX+x0fdvPzdn9WeoJGAYcBN39EiIiKeEONjTt0kZKHQGyWl4mZdREAoQAcnJhBXBqioqSlT6qqG6WmTK+rsa1NtaGsuEu6o7yXubojsrTEIsa+yMm9SL8osp3PzM2cStDRykfZ2tfUtS/bRd3ewtzV5pLo4eLjQuUp70Hx8t9E9eqO5Oku5/ztdkxi90qPg3x2EMpR6IahGocPCxp8AGtigwQAIfkEBQUABAAsHwBOAFcAMAAAA/9Iutz+MMo36pg4682J/V0ojs1nXmSqSqe5vrDXunEdzq2ta3i+/5DeCUh0CGnF5BGULC4tTeUTFQVONYAs4CfoCkZPjFar83rBx8l4XDObSUL1Ott2d1U4yZwcs5/xSBB7dBMBhgEYfncrTBGDW4WHhomKUY+QEZKSE4qLRY8YmoeUfkmXoaKInJ2fgxmpqqulQKCvqRqsP7WooriVO7u8mhu5NacasMTFMMHCm8qzzM2RvdDRK9PUwxzLKdnaz9y/Kt8SyR3dIuXmtyHpHMcd5+jvWK4i8/TXHff47SLjQvQLkU+fG29rUhQ06IkEG4X/Rryp4mwUxSgLL/7IqFETB8eONT6ChCFy5ItqJomES6kgAQAh+QQFBQAEACwKAE4AVwAwAAAD/0i63A4QuEmrvTi3yLX/4MeNUmieITmibEuppCu3sDrfYG3jPKbHveDktxIaF8TOcZmMLI9NyBPanFKJp4A2IBx4B5lkdqvtfb8+HYpMxp3Pl1qLvXW/vWkli16/3dFxTi58ZRcChwIYf3hWBIRchoiHiotWj5AVkpIXi4xLjxiaiJR/T5ehoomcnZ+EGamqq6VGoK+pGqxCtaiiuJVBu7yaHrk4pxqwxMUzwcKbyrPMzZG90NGDrh/JH8t72dq3IN1jfCHb3L/e5ebh4ukmxyDn6O8g08jt7tf26ybz+m/W9GNXzUQ9fm1Q/APoSWAhhfkMAmpEbRhFKwsvCsmosRIHx444PoKcIXKkjIImjTzjkQAAIfkEBQUABAAsAgA8AEIAQgAAA/VIBNz+8KlJq72Yxs1d/uDVjVxogmQqnaylvkArT7A63/V47/m2/8CgcEgsGo/IpHLJbDqf0Kh0Sj0FroGqDMvVmrjgrDcTBo8v5fCZki6vCW33Oq4+0832O/at3+f7fICBdzsChgJGeoWHhkV0P4yMRG1BkYeOeECWl5hXQ5uNIAOjA1KgiKKko1CnqBmqqk+nIbCkTq20taVNs7m1vKAnurtLvb6wTMbHsUq4wrrFwSzDzcrLtknW16tI2tvERt6pv0fi48jh5h/U6Zs77EXSN/BE8jP09ZFA+PmhP/xvJgAMSGBgQINvEK5ReIZhQ3QEMTBLAAAh+QQFBQAEACwCAB8AMABXAAAD50i6DA4syklre87qTbHn4OaNYSmNqKmiqVqyrcvBsazRpH3jmC7yD98OCBF2iEXjBKmsAJsWHDQKmw571l8my+16v+CweEwum8+hgHrNbrvbtrd8znbR73MVfg838f8BeoB7doN0cYZvaIuMjY6PkJGSk2gClgJml5pjmp2YYJ6dX6GeXaShWaeoVqqlU62ir7CXqbOWrLafsrNctjIDwAMWvC7BwRWtNsbGFKc+y8fNsTrQ0dK3QtXAYtrCYd3eYN3c49/a5NVj5eLn5u3s6e7x8NDo9fbL+Mzy9/T5+tvUzdN3Zp+GBAAh+QQJBQAEACwCAAIAfAB8AAAD/0i63P4wykmrvTjrzbv/YCiOZGmeaKqubOu+cCzPdArcQK2TOL7/nl4PSMwIfcUk5YhUOh3M5nNKiOaoWCuWqt1Ou16l9RpOgsvEMdocXbOZ7nQ7DjzTaeq7zq6P5fszfIASAYUBIYKDDoaGIImKC4ySH3OQEJKYHZWWi5iZG0ecEZ6eHEOio6SfqCaqpaytrpOwJLKztCO2jLi1uoW8Ir6/wCHCxMG2x7muysukzb230M6H09bX2Nna29zd3t/g4cAC5OXm5+jn3Ons7eba7vHt2fL16tj2+QL0+vXw/e7WAUwnrqDBgwgTKlzIsKHDh2gGSBwAccHEixAvaqTYcFCjRoYeNyoM6REhyZIHT4o0qPIjy5YTTcKUmHImx5cwE85cmJPnSYckK66sSAAj0aNIkypdyrSp06dQo0qdSrWq1atYs2rdyrWr169gwxZJAAA7' diff --git a/packages/taro-components-qa/src/components/button.js/index.ux b/packages/taro-components-qa/src/components/button.js/index.ux new file mode 100644 index 000000000000..0cf11a7b4ad8 --- /dev/null +++ b/packages/taro-components-qa/src/components/button.js/index.ux @@ -0,0 +1,155 @@ + + + + + diff --git a/packages/taro-components-qa/src/components/camera/index.ux b/packages/taro-components-qa/src/components/camera/index.ux new file mode 100644 index 000000000000..f7522ec4d642 --- /dev/null +++ b/packages/taro-components-qa/src/components/camera/index.ux @@ -0,0 +1,80 @@ + + + + + \ No newline at end of file diff --git a/packages/taro-components-qa/src/components/icon/index.ux b/packages/taro-components-qa/src/components/icon/index.ux new file mode 100644 index 000000000000..fdb57b710ce3 --- /dev/null +++ b/packages/taro-components-qa/src/components/icon/index.ux @@ -0,0 +1,132 @@ + + + + + diff --git a/packages/taro-components-qa/src/components/image/index.ux b/packages/taro-components-qa/src/components/image/index.ux new file mode 100644 index 000000000000..1e0ee91576cd --- /dev/null +++ b/packages/taro-components-qa/src/components/image/index.ux @@ -0,0 +1,84 @@ + + + + + diff --git a/packages/taro-components-qa/src/components/input/index.ux b/packages/taro-components-qa/src/components/input/index.ux new file mode 100644 index 000000000000..81441c65c583 --- /dev/null +++ b/packages/taro-components-qa/src/components/input/index.ux @@ -0,0 +1,113 @@ + + + + + diff --git a/packages/taro-components-qa/src/components/label/index.ux b/packages/taro-components-qa/src/components/label/index.ux new file mode 100644 index 000000000000..82cb4ef1f5c8 --- /dev/null +++ b/packages/taro-components-qa/src/components/label/index.ux @@ -0,0 +1,55 @@ + + + + + diff --git a/packages/taro-components-qa/src/components/navigator/index.ux b/packages/taro-components-qa/src/components/navigator/index.ux new file mode 100644 index 000000000000..a765bac33201 --- /dev/null +++ b/packages/taro-components-qa/src/components/navigator/index.ux @@ -0,0 +1,81 @@ + + + + + diff --git a/packages/taro-components-qa/src/components/picker/index.ux b/packages/taro-components-qa/src/components/picker/index.ux new file mode 100644 index 000000000000..b77104912e20 --- /dev/null +++ b/packages/taro-components-qa/src/components/picker/index.ux @@ -0,0 +1,160 @@ + + + + + diff --git a/packages/taro-components-qa/src/components/progress/index.ux b/packages/taro-components-qa/src/components/progress/index.ux new file mode 100644 index 000000000000..b06652626017 --- /dev/null +++ b/packages/taro-components-qa/src/components/progress/index.ux @@ -0,0 +1,106 @@ + + + + + \ No newline at end of file diff --git a/packages/taro-components-qa/src/components/radio/index.ux b/packages/taro-components-qa/src/components/radio/index.ux new file mode 100644 index 000000000000..4e3ce745afa2 --- /dev/null +++ b/packages/taro-components-qa/src/components/radio/index.ux @@ -0,0 +1,70 @@ + + + + + diff --git a/packages/taro-components-qa/src/components/rich_text/index.ux b/packages/taro-components-qa/src/components/rich_text/index.ux new file mode 100644 index 000000000000..bfda22088006 --- /dev/null +++ b/packages/taro-components-qa/src/components/rich_text/index.ux @@ -0,0 +1,53 @@ + + + + + \ No newline at end of file diff --git a/packages/taro-components-qa/src/components/slider/index.ux b/packages/taro-components-qa/src/components/slider/index.ux new file mode 100644 index 000000000000..26dd508dfece --- /dev/null +++ b/packages/taro-components-qa/src/components/slider/index.ux @@ -0,0 +1,115 @@ + + + + + + \ No newline at end of file diff --git a/packages/taro-components-qa/src/components/swiper/index.ux b/packages/taro-components-qa/src/components/swiper/index.ux new file mode 100644 index 000000000000..de95ed870b8e --- /dev/null +++ b/packages/taro-components-qa/src/components/swiper/index.ux @@ -0,0 +1,90 @@ + + + + + diff --git a/packages/taro-components-qa/src/components/switch/index.ux b/packages/taro-components-qa/src/components/switch/index.ux new file mode 100644 index 000000000000..5f62a068e768 --- /dev/null +++ b/packages/taro-components-qa/src/components/switch/index.ux @@ -0,0 +1,82 @@ + + + + + diff --git a/packages/taro-components-qa/src/components/text/index.ux b/packages/taro-components-qa/src/components/text/index.ux new file mode 100644 index 000000000000..d0eba4ddf688 --- /dev/null +++ b/packages/taro-components-qa/src/components/text/index.ux @@ -0,0 +1,50 @@ + + + + + diff --git a/packages/taro-components-qa/src/components/textarea/index.ux b/packages/taro-components-qa/src/components/textarea/index.ux new file mode 100644 index 000000000000..52e18dbd7b87 --- /dev/null +++ b/packages/taro-components-qa/src/components/textarea/index.ux @@ -0,0 +1,74 @@ + + + + + diff --git a/packages/taro-components-qa/src/components/video/index.ux b/packages/taro-components-qa/src/components/video/index.ux new file mode 100644 index 000000000000..79932b266f45 --- /dev/null +++ b/packages/taro-components-qa/src/components/video/index.ux @@ -0,0 +1,126 @@ + + + + + diff --git a/packages/taro-components-qa/src/components/view/index.ux b/packages/taro-components-qa/src/components/view/index.ux new file mode 100644 index 000000000000..e1744c01b0f8 --- /dev/null +++ b/packages/taro-components-qa/src/components/view/index.ux @@ -0,0 +1,55 @@ + + + + + From fde2817e8d5db696df391e49339c86c0db4fc1c0 Mon Sep 17 00:00:00 2001 From: Alan Zhang Date: Thu, 3 Jan 2019 15:41:34 +0800 Subject: [PATCH 014/103] =?UTF-8?q?fix(doctor):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=20typescript=20=E5=90=8E=E5=87=BA=E7=8E=B0?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/bin/taro-doctor | 4 ++-- packages/taro-cli/src/doctor/configSchema.ts | 14 +++++--------- packages/taro-cli/src/doctor/configValidator.ts | 6 +++--- packages/taro-cli/src/doctor/eslintValidator.ts | 4 ++-- packages/taro-cli/src/doctor/index.ts | 13 +++++++++---- packages/taro-cli/src/doctor/joi2desc.ts | 2 +- packages/taro-cli/src/doctor/packageValidator.ts | 4 ++-- packages/taro-cli/src/doctor/recommandValidator.ts | 6 +++--- packages/taro-cli/src/doctor/validatorEslintrc.ts | 2 +- 9 files changed, 28 insertions(+), 27 deletions(-) diff --git a/packages/taro-cli/bin/taro-doctor b/packages/taro-cli/bin/taro-doctor index b57e4febddb1..9c64060453a0 100755 --- a/packages/taro-cli/bin/taro-doctor +++ b/packages/taro-cli/bin/taro-doctor @@ -6,7 +6,7 @@ const _ = require('lodash/fp') const ora = require('ora') const chalk = require('chalk') const fs = require('fs-extra') -const { PROJECT_CONFIG } = require('../dist/util') +const { PROJECT_CONFIG } = require('../dist/util/constants') const PROJECT_CONF_PATH = path.join(process.cwd(), PROJECT_CONFIG) if (!fs.existsSync(PROJECT_CONF_PATH)) { @@ -57,7 +57,7 @@ program async function diagnose () { const spinner = ora('正在诊断项目...').start() - const reportsP = _.invokeMap(_.call, validators) + const reportsP = _.map(validator => validator(), validators) const reports = await Promise.all(reportsP) spinner.succeed('诊断完成') printReport(reports) diff --git a/packages/taro-cli/src/doctor/configSchema.ts b/packages/taro-cli/src/doctor/configSchema.ts index 25f7798e7335..c8fe11d391d6 100644 --- a/packages/taro-cli/src/doctor/configSchema.ts +++ b/packages/taro-cli/src/doctor/configSchema.ts @@ -1,4 +1,4 @@ -import Joi from 'joi' +import * as Joi from 'joi' const schema = Joi.object().keys({ 'projectName': Joi.string().required(), @@ -85,17 +85,13 @@ const schema = Joi.object().keys({ 'miniCssExtractPluginOption': Joi.object(), // 第三方配置 'module': Joi.object().keys({ - 'postcss': Joi.object().keys({ - 'autoprefixer': Joi.object().keys({ + 'postcss': Joi.object().pattern( + Joi.string(), + Joi.object().keys({ 'enable': Joi.bool(), 'config': Joi.object() // 第三方配置 }), - 'pxtransform': Joi.object().keys({ - 'enable': Joi.bool(), - 'config': Joi.object() - }), - 'plugins': Joi.array() // 第三方配置 - }) + ) }) }) }) diff --git a/packages/taro-cli/src/doctor/configValidator.ts b/packages/taro-cli/src/doctor/configValidator.ts index 53e257be11b2..afd68df332ef 100644 --- a/packages/taro-cli/src/doctor/configValidator.ts +++ b/packages/taro-cli/src/doctor/configValidator.ts @@ -1,6 +1,6 @@ -import Joi from 'joi' -import _ from 'lodash/fp' -import path from 'path' +import * as Joi from 'joi' +import * as _ from 'lodash/fp' +import * as path from 'path' import joi2desc from './joi2desc' import configSchema from './configSchema' diff --git a/packages/taro-cli/src/doctor/eslintValidator.ts b/packages/taro-cli/src/doctor/eslintValidator.ts index 498a9d6c6464..cb06bdfc3fa5 100644 --- a/packages/taro-cli/src/doctor/eslintValidator.ts +++ b/packages/taro-cli/src/doctor/eslintValidator.ts @@ -1,5 +1,5 @@ -import path from 'path' -import _ from 'lodash' +import * as path from 'path' +import * as _ from 'lodash' import { CLIEngine } from 'eslint' import { PROJECT_CONFIG } from '../util/constants' diff --git a/packages/taro-cli/src/doctor/index.ts b/packages/taro-cli/src/doctor/index.ts index 3dec316e1010..59247fdfa2a3 100644 --- a/packages/taro-cli/src/doctor/index.ts +++ b/packages/taro-cli/src/doctor/index.ts @@ -1,8 +1,13 @@ +import configValidator from './configValidator'; +import packageValidator from './packageValidator'; +import recommandValidator from './recommandValidator'; +import eslintValidator from './eslintValidator'; + export default { validators: [ - require('./configValidator'), - require('./packageValidator'), - require('./recommandValidator'), - require('./eslintValidator') + configValidator, + packageValidator, + recommandValidator, + eslintValidator ] } diff --git a/packages/taro-cli/src/doctor/joi2desc.ts b/packages/taro-cli/src/doctor/joi2desc.ts index 4fe795fdb705..4ba60dd5b7d9 100644 --- a/packages/taro-cli/src/doctor/joi2desc.ts +++ b/packages/taro-cli/src/doctor/joi2desc.ts @@ -57,7 +57,7 @@ const joi2desc = { 'number.precision': '', 'number.ref': '', 'number.unsafe': '', - 'object.allowUnknown': '', + 'object.allowUnknown': '不合法的字段', 'object.and': '', 'object.assert': '', 'object.base': '应该为一个对象', diff --git a/packages/taro-cli/src/doctor/packageValidator.ts b/packages/taro-cli/src/doctor/packageValidator.ts index 8f4d605a3e86..3551175fc5da 100644 --- a/packages/taro-cli/src/doctor/packageValidator.ts +++ b/packages/taro-cli/src/doctor/packageValidator.ts @@ -1,5 +1,5 @@ -import _ from 'lodash/fp' -import npmCheck from 'npm-check' +import * as _ from 'lodash/fp' +import * as npmCheck from 'npm-check' import { getPkgVersion } from '../util' diff --git a/packages/taro-cli/src/doctor/recommandValidator.ts b/packages/taro-cli/src/doctor/recommandValidator.ts index 0c5001409816..312a575fbe2b 100644 --- a/packages/taro-cli/src/doctor/recommandValidator.ts +++ b/packages/taro-cli/src/doctor/recommandValidator.ts @@ -1,6 +1,6 @@ -import _ from 'lodash/fp' -import fs from 'fs-extra' -import path from 'path' +import * as _ from 'lodash/fp' +import * as fs from 'fs-extra' +import * as path from 'path' import chalk from 'chalk' import { IErrorLine } from './interface' diff --git a/packages/taro-cli/src/doctor/validatorEslintrc.ts b/packages/taro-cli/src/doctor/validatorEslintrc.ts index 4e168dbb2596..521a005d3929 100644 --- a/packages/taro-cli/src/doctor/validatorEslintrc.ts +++ b/packages/taro-cli/src/doctor/validatorEslintrc.ts @@ -1,4 +1,4 @@ -export default { +module.exports = { 'extends': ['taro'], 'rules': { 'no-unused-vars': ['error', { 'varsIgnorePattern': 'Taro' }], From 9c5fc07acdb5258efd0eb9431975f2dcfb1ef2b6 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Tue, 8 Jan 2019 14:52:49 +0800 Subject: [PATCH 015/103] =?UTF-8?q?chore(cli):=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E5=85=83=E6=97=A6=E7=A5=9D=E7=A6=8F=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/bin/taro | 8 -------- packages/taro-cli/bin/year.txt | 9 --------- 2 files changed, 17 deletions(-) delete mode 100644 packages/taro-cli/bin/year.txt diff --git a/packages/taro-cli/bin/taro b/packages/taro-cli/bin/taro index 8f66b31d26b0..94234368074f 100755 --- a/packages/taro-cli/bin/taro +++ b/packages/taro-cli/bin/taro @@ -5,14 +5,6 @@ const { getPkgVersion, printPkgVersion } = require('../dist/util') printPkgVersion() -const startTime = new Date('2019-1-1 00:00').getTime() -const endTime = new Date('2019-1-2 00:00').getTime() -const nowTime = Date.now() -if (nowTime >= startTime && nowTime <= endTime) { - const yearTxt = String(require('fs-extra').readFileSync(require('path').resolve(__dirname, 'year.txt'))) - console.log(require('chalk').rgb(255, 87, 34)(yearTxt)) -} - program .version(getPkgVersion()) .usage(' [options]') diff --git a/packages/taro-cli/bin/year.txt b/packages/taro-cli/bin/year.txt deleted file mode 100644 index dc47403739fa..000000000000 --- a/packages/taro-cli/bin/year.txt +++ /dev/null @@ -1,9 +0,0 @@ -🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 -🎉 _ _ _ _ _____ _____ __ _____ _ 🎉 -🏮 | | | | | | | / __ | _ / || _ | | | 🏮 -🎉 | |_| | ___| | | ___ `' / /| |/' `| || |_| | | | 🎉 -🏮 | _ |/ _ | | |/ _ \ / / | /| || |\____ | | | 🏮 -🎉 | | | | __| | | (_) | ./ /__\ |_/ _| |.___/ / |_| 🎉 -🏮 \_| |_/\___|_|_|\___/ \_____/\___/\___\____/ (_) 🏮 -🎉 🎉 -🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 🎉 🏮 From 2242bd4434e3f854134ad350720cb9f8cd50c054 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Tue, 8 Jan 2019 15:12:13 +0800 Subject: [PATCH 016/103] =?UTF-8?q?feat(cli):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=BF=AB=E5=BA=94=E7=94=A8=E7=BC=96=E8=AF=91=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/bin/taro-build | 2 +- packages/taro-cli/src/build.ts | 9 ++++++++- packages/taro-cli/src/quick/index.ts | 5 +++++ packages/taro-cli/src/util/constants.ts | 3 ++- 4 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 packages/taro-cli/src/quick/index.ts diff --git a/packages/taro-cli/bin/taro-build b/packages/taro-cli/bin/taro-build index 3c141de6cfa3..82e794fd4d75 100755 --- a/packages/taro-cli/bin/taro-build +++ b/packages/taro-cli/bin/taro-build @@ -10,7 +10,7 @@ const { PROJECT_CONFIG } = require('../dist/util/constants') const projectConfPath = path.join(process.cwd(), PROJECT_CONFIG) program - .option('--type [typeName]', 'Build type, weapp/h5/rn/swan/alipay/tt') + .option('--type [typeName]', 'Build type, weapp/swan/alipay/tt/h5/quickapp/rn') .option('--watch', 'Watch mode') .option('--env [env]', 'Env type') .option('--ui', 'Build Taro UI library') diff --git a/packages/taro-cli/src/build.ts b/packages/taro-cli/src/build.ts index 27d34773fafd..21d7727e72e8 100644 --- a/packages/taro-cli/src/build.ts +++ b/packages/taro-cli/src/build.ts @@ -40,11 +40,14 @@ export default function build (args, buildConfig: IBuildConfig) { case BUILD_TYPES.RN: buildForRN({ watch }) break + case BUILD_TYPES.QUICKAPP: + buildForQuickApp({ watch }) + break case BUILD_TYPES.UI: buildForUILibrary({ watch }) break default: - console.log(chalk.red('输入类型错误,目前只支持 weapp/h5/rn/swan/alipay/tt 六端类型')) + console.log(chalk.red('输入类型错误,目前只支持 weapp/swan/alipay/tt/h5/quickapp/rn 七端类型')) } } @@ -84,6 +87,10 @@ function buildForRN ({ watch }: IBuildConfig) { require('./rn').build({ watch }) } +function buildForQuickApp ({ watch }: IBuildConfig) { + require('./quick').build({ watch }) +} + function buildForUILibrary ({ watch }: IBuildConfig) { require('./ui').build({ watch }) } diff --git a/packages/taro-cli/src/quick/index.ts b/packages/taro-cli/src/quick/index.ts new file mode 100644 index 000000000000..8012553029c2 --- /dev/null +++ b/packages/taro-cli/src/quick/index.ts @@ -0,0 +1,5 @@ +import * as fs from 'fs-extra' +import * as path from 'path' + +export async function build ({ watch }) { +} diff --git a/packages/taro-cli/src/util/constants.ts b/packages/taro-cli/src/util/constants.ts index 724b9d630cc6..b0f3f6f49e6d 100644 --- a/packages/taro-cli/src/util/constants.ts +++ b/packages/taro-cli/src/util/constants.ts @@ -93,7 +93,8 @@ export const enum BUILD_TYPES { SWAN ='swan', ALIPAY ='alipay', TT ='tt', - UI ='ui' + UI ='ui', + QUICKAPP = 'quickapp' } export const enum TEMPLATE_TYPES { From f8eb036821a5bd2d20a70dd2d3169be4dcfdba51 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Tue, 8 Jan 2019 21:38:50 +0800 Subject: [PATCH 017/103] =?UTF-8?q?feat(cli):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=BF=AB=E5=BA=94=E7=94=A8=20manifest=20=E7=9A=84=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/src/quick/entry.ts | 0 packages/taro-cli/src/quick/interface.ts | 142 +++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 packages/taro-cli/src/quick/entry.ts create mode 100644 packages/taro-cli/src/quick/interface.ts diff --git a/packages/taro-cli/src/quick/entry.ts b/packages/taro-cli/src/quick/entry.ts new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/taro-cli/src/quick/interface.ts b/packages/taro-cli/src/quick/interface.ts new file mode 100644 index 000000000000..8ddc201f41dc --- /dev/null +++ b/packages/taro-cli/src/quick/interface.ts @@ -0,0 +1,142 @@ +import { IOption } from '../util/types' + +type FeatureItem = { + name: string +} + +export type SystemConfig = { + /** + * 打印日志等级,分为 off,error,warn,info,log,debug + */ + logLevel?: 'off' | 'error' | 'warn' | 'info' | 'log' | 'debug', + /** + * 页面设计基准宽度,根据实际设备宽度来缩放元素大小 + */ + designWidth?: number, + /** + * 全局数据对象,属性名不能以$或_开头,在页面中可通过 this 进行访问;如果全局数据属性与页面的数据属性重名,则页面初始化时,全局数据会覆盖页面中对应的属性值 + */ + data?: IOption +} + +type RouterConfig = { + /** + * 首页名称 + */ + entry: string, + /** + * 页面配置列表,key 值为页面名称(对应页面目录名,例如 Hello 对应'Hello'目录),value 为页面详细配置 page + */ + pages: RouterPage[] +} +type RouterPage = { + /** + * 页面对应的组件名,与 ux 文件名保持一致,例如'hello' 对应 'hello.ux' + */ + component: string, + /** + * 页面路径,例如“/user”,不填则默认为/<页面名称>。 + * path 必须唯一,不能和其他 page 的 path 相同。 + * 下面 page 的 path 因为缺失,会被设置为“/Index”: + * "Index": {"component": "index"} + */ + path?: string, + /** + * 声明页面可以处理某种请求 + */ + filter: { + [key: string]: { + uri: string + } + } +} + +interface IDefaultDisplayConfig { + /** + * 窗口背景颜色 + */ + backgroundColor?: string, + /** + * 是否是全屏模式,默认不会同时作用于 titleBar,titleBar 需要继续通过 titleBar 控制 + */ + fullScreen?: boolean, + /** + * 是否显示 titleBar + */ + titleBar?: boolean, + /** + * 标题栏背景色 + */ + titleBarBackgroundColor?: string, + /** + * 标题栏文字颜色 + */ + titleBarTextColor?: string, + /** + * 标题栏文字(也可通过页面跳转传递参数(titleBarText)设置) + */ + titleBarText?: string, + /** + * 是否显示标题栏右上角菜单按钮,点击菜单按钮调用页面生命周期 onMenuPress 方法,如果该方法未实现则显示系统默认菜单 + */ + menu?: boolean, + /** + * 软键盘弹出时为保证输入框可见,页面的调整方式。 adjustPan:上移页面; adjustResize:压缩页面显示区域,当页面全屏时,此设置不生效 + */ + windowSoftInputMode?: 'adjustPan' | 'adjustResize' +} + +interface IDisplayConfig extends IDefaultDisplayConfig { + /** + * 各个页面的显示样式,key 为页面名(与路由中的页面名保持一致),value 为窗口显示样式,页面样式覆盖 default 样式 + */ + pages?: { + [key: string]: IDefaultDisplayConfig + } +} + +export interface ITaroManifestConfig { + /** + * 应用包名,确认与原生应用的包名不一致,推荐采用 com.company.module 的格式,如:com.example.demo + */ + package: string, + /** + * 应用名称,6 个汉字以内,与应用商店保存的名称一致,用于在桌面图标、弹窗等处显示应用名称 + */ + name: string, + /** + * 应用图标,提供 192x192 大小的即可 + */ + icon: string, + /** + * 应用版本名称,如:"1.0" + */ + versionName?: string, + /** + * 应用版本号,从1自增,推荐每次重新上传包时versionCode+1 + */ + versionCode: number, + /** + * 支持的最小平台版本号,兼容性检查,避免上线后在低版本平台运行并导致不兼容;如果不填按照内测版本处理 + */ + minPlatformVersion?: string, + /** + * 接口列表,绝大部分接口都需要在这里声明,否则不能调用,详见每个接口的文档说明 + */ + features?: FeatureItem[] +} + +export interface IManifestConfig extends ITaroManifestConfig { + /** + * 系统配置信息 + */ + config: SystemConfig, + /** + * 路由信息 + */ + router: RouterConfig, + /** + * UI 显示相关配置 + */ + display?: IDisplayConfig +} From dd2ec8a30332b8165caddd6b1ed8a75407487f7d Mon Sep 17 00:00:00 2001 From: Alan Zhang Date: Mon, 29 Oct 2018 11:40:48 +0800 Subject: [PATCH 018/103] =?UTF-8?q?feat(doctor):=20=E5=A2=9E=E5=8A=A0=20do?= =?UTF-8?q?ctor=20=E5=AD=90=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/bin/taro-doctor | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/taro-cli/bin/taro-doctor b/packages/taro-cli/bin/taro-doctor index 9c64060453a0..d652f6f97e90 100755 --- a/packages/taro-cli/bin/taro-doctor +++ b/packages/taro-cli/bin/taro-doctor @@ -6,7 +6,11 @@ const _ = require('lodash/fp') const ora = require('ora') const chalk = require('chalk') const fs = require('fs-extra') +<<<<<<< HEAD const { PROJECT_CONFIG } = require('../dist/util/constants') +======= +const { PROJECT_CONFIG } = require('../src/util') +>>>>>>> feat(doctor): 增加 doctor 子命令 const PROJECT_CONF_PATH = path.join(process.cwd(), PROJECT_CONFIG) if (!fs.existsSync(PROJECT_CONF_PATH)) { @@ -14,7 +18,11 @@ if (!fs.existsSync(PROJECT_CONF_PATH)) { process.exit(1) } +<<<<<<< HEAD const { validators } = require('../dist/doctor').default +======= +const { validators } = require('../src/doctor') +>>>>>>> feat(doctor): 增加 doctor 子命令 const NOTE_ALL_RIGHT = chalk.green('[✓] ') const NOTE_VALID = chalk.yellow('[!] ') @@ -57,7 +65,11 @@ program async function diagnose () { const spinner = ora('正在诊断项目...').start() +<<<<<<< HEAD const reportsP = _.map(validator => validator(), validators) +======= + const reportsP = _.invokeMap(_.call, validators) +>>>>>>> feat(doctor): 增加 doctor 子命令 const reports = await Promise.all(reportsP) spinner.succeed('诊断完成') printReport(reports) From 34f9e75e465df0fa17cebd51adf3e8f54fbe8ba7 Mon Sep 17 00:00:00 2001 From: Alan Zhang Date: Mon, 29 Oct 2018 11:40:48 +0800 Subject: [PATCH 019/103] chore: fix miss merge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat(doctor): 增加 doctor 子命令 --- packages/taro-cli/yarn.lock | 379 +++++++++++++++++++++++++++++++++--- 1 file changed, 355 insertions(+), 24 deletions(-) diff --git a/packages/taro-cli/yarn.lock b/packages/taro-cli/yarn.lock index 2f9854cbcc81..f10c66404a4a 100644 --- a/packages/taro-cli/yarn.lock +++ b/packages/taro-cli/yarn.lock @@ -867,11 +867,135 @@ babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: babel-helper-builder-react-jsx@^6.24.1: version "6.26.0" resolved "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + integrity sha1-zORReto1b0IgvK6KAsKzRvmlZmQ= + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-builder-react-jsx@^6.24.1: + version "6.26.0" + resolved "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0" + integrity sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA= + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + integrity sha1-zORReto1b0IgvK6KAsKzRvmlZmQ= + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-builder-react-jsx@^6.24.1: + version "6.26.0" + resolved "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0" + integrity sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA= dependencies: babel-runtime "^6.26.0" babel-types "^6.26.0" esutils "^2.0.2" +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + integrity sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340= + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + integrity sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8= + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-evaluate-path@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz#a62fa9c4e64ff7ea5cea9353174ef023a900a67c" + integrity sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA== + +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + integrity sha1-8luCz33BBDPFX3BZLVdGQArCLKo= + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-explode-class@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" + integrity sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes= + dependencies: + babel-helper-bindify-decorators "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + integrity sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340= + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + integrity sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8= + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-evaluate-path@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz#a62fa9c4e64ff7ea5cea9353174ef023a900a67c" + integrity sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA== + +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + integrity sha1-8luCz33BBDPFX3BZLVdGQArCLKo= + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-explode-class@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" + integrity sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes= + dependencies: + babel-helper-bindify-decorators "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + babel-helper-call-delegate@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" @@ -918,6 +1042,7 @@ babel-helper-explode-class@^6.24.1: babel-helper-function-name@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + integrity sha1-00dbjAPtmCQqJbSDUasYOZ01gKk= dependencies: babel-helper-get-function-arity "^6.24.1" babel-runtime "^6.22.0" @@ -928,8 +1053,69 @@ babel-helper-function-name@^6.24.1: babel-helper-get-function-arity@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + integrity sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0= + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + integrity sha1-HssnaJydJVE+rbyZFKc/VAi+enY= + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-mark-eval-scopes@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz#d244a3bef9844872603ffb46e22ce8acdf551562" + integrity sha1-0kSjvvmESHJgP/tG4izorN9VFWI= + +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + integrity sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc= + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-regex@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + integrity sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI= dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-remap-async-to-generator@^6.16.0, babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + integrity sha1-XsWBgnrXI/7N04HxySg5BnbkVRs= + dependencies: + babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-remove-or-void@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz#a4f03b40077a0ffe88e45d07010dee241ff5ae60" + integrity sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA= + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + integrity sha1-v22/5Dk40XNpohPKiov3S2qQqxo= + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" babel-types "^6.24.1" babel-helper-hoist-variables@^6.24.1: @@ -994,6 +1180,7 @@ babel-helper-replace-supers@^6.24.1: babel-helpers@^6.24.1, babel-helpers@^6.8.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + integrity sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI= dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" @@ -1008,6 +1195,7 @@ babel-jest@^23.6.0: babel-messages@^6.23.0, babel-messages@^6.8.0: version "6.23.0" resolved "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= dependencies: babel-runtime "^6.22.0" @@ -1058,6 +1246,7 @@ babel-plugin-react-transform@^3.0.0: babel-plugin-remove-dead-code@^1.3.2: version "1.3.2" resolved "https://registry.npmjs.org/babel-plugin-remove-dead-code/-/babel-plugin-remove-dead-code-1.3.2.tgz#e1a2cd9595bb2f767291f35cab4ec9b467ee62c6" + integrity sha1-4aLNlZW7L3ZykfNcq07JtGfuYsY= dependencies: babel-core "6.10.4" @@ -1076,10 +1265,17 @@ babel-plugin-syntax-class-constructor-call@^6.18.0: babel-plugin-syntax-class-properties@^6.5.0, babel-plugin-syntax-class-properties@^6.8.0: version "6.13.0" resolved "http://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + integrity sha1-1+sjt5oxf4VDlixQW4J8fWysJ94= babel-plugin-syntax-decorators@^6.1.18, babel-plugin-syntax-decorators@^6.13.0: version "6.13.0" resolved "http://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" + integrity sha1-MSVjtNvePMgGzuPkFszurd0RrAs= + +babel-plugin-syntax-do-expressions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz#5747756139aa26d390d09410b03744ba07e4796d" + integrity sha1-V0d1YTmqJtOQ0JQQsDdEugfkeW0= babel-plugin-syntax-do-expressions@^6.8.0: version "6.13.0" @@ -1088,6 +1284,17 @@ babel-plugin-syntax-do-expressions@^6.8.0: babel-plugin-syntax-dynamic-import@^6.18.0: version "6.18.0" resolved "http://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + integrity sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo= + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + integrity sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4= + +babel-plugin-syntax-export-extensions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" + integrity sha1-cKFITw+QiaToStRLrDU8lbmxJyE= babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" @@ -1100,6 +1307,7 @@ babel-plugin-syntax-export-extensions@^6.8.0: babel-plugin-syntax-flow@^6.18.0, babel-plugin-syntax-flow@^6.5.0, babel-plugin-syntax-flow@^6.8.0: version "6.18.0" resolved "http://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" + integrity sha1-TDqyCiryaqIM0lmVw5jE63AxDI0= babel-plugin-syntax-function-bind@^6.8.0: version "6.13.0" @@ -1108,6 +1316,53 @@ babel-plugin-syntax-function-bind@^6.8.0: babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.5.0, babel-plugin-syntax-jsx@^6.8.0: version "6.18.0" resolved "http://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= + +babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + integrity sha1-/WU28rzhODb/o6VFjEkDpZe7O/U= + +babel-plugin-syntax-trailing-function-commas@^6.20.0, babel-plugin-syntax-trailing-function-commas@^6.22.0, babel-plugin-syntax-trailing-function-commas@^6.5.0, babel-plugin-syntax-trailing-function-commas@^6.8.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + integrity sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM= + +babel-plugin-transform-async-generator-functions@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" + integrity sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds= + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-generators "^6.5.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-async-to-generator@6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.16.0.tgz#19ec36cb1486b59f9f468adfa42ce13908ca2999" + integrity sha1-Gew2yxSGtZ+fRorfpCzhOQjKKZk= + dependencies: + babel-helper-remap-async-to-generator "^6.16.0" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + integrity sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E= + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-class-constructor-call@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz#80dc285505ac067dcb8d6c65e2f6f11ab7765ef9" + integrity sha1-gNwoVQWsBn3LjWxl4vbxGrd2Xvk= + dependencies: + babel-plugin-syntax-class-constructor-call "^6.18.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0: version "6.13.0" @@ -1152,6 +1407,7 @@ babel-plugin-transform-class-constructor-call@^6.24.1: babel-plugin-transform-class-properties@^6.18.0, babel-plugin-transform-class-properties@^6.24.1, babel-plugin-transform-class-properties@^6.5.0, babel-plugin-transform-class-properties@^6.8.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" + integrity sha1-anl2PqYdM9NvN7YRqp3vgagbRqw= dependencies: babel-helper-function-name "^6.24.1" babel-plugin-syntax-class-properties "^6.8.0" @@ -1161,6 +1417,7 @@ babel-plugin-transform-class-properties@^6.18.0, babel-plugin-transform-class-pr babel-plugin-transform-decorators-legacy@^1.3.4: version "1.3.5" resolved "https://registry.npmjs.org/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.5.tgz#0e492dffa0edd70529072887f8aa86d4dd8b40a1" + integrity sha512-jYHwjzRXRelYQ1uGm353zNzf3QmtdCfvJbuYTZ4gKveK7M9H1fs3a5AKdY1JUDl0z97E30ukORW1dzhWvsabtA== dependencies: babel-plugin-syntax-decorators "^6.1.18" babel-runtime "^6.2.0" @@ -1179,6 +1436,7 @@ babel-plugin-transform-decorators@^6.24.1: babel-plugin-transform-define@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/babel-plugin-transform-define/-/babel-plugin-transform-define-1.3.0.tgz#94c5f9459c810c738cc7c50cbd44a31829d6f319" + integrity sha1-lMX5RZyBDHOMx8UMvUSjGCnW8xk= dependencies: lodash "4.17.4" traverse "0.6.6" @@ -2174,7 +2432,7 @@ core-js@^2.2.2, core-js@^2.4.1, core-js@^2.5.7: version "2.6.2" resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.2.tgz#267988d7268323b349e20b4588211655f0e83944" -core-js@^2.4.0, core-js@^2.5.0: +core-js@^2.2.2, core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0, core-js@^2.5.7: version "2.5.7" resolved "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" @@ -2311,7 +2569,16 @@ decompress-response@^3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" dependencies: - mimic-response "^1.0.0" + contains-path "^0.1.0" + debug "^2.6.8" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.1" + eslint-module-utils "^2.2.0" + has "^1.0.1" + lodash "^4.17.4" + minimatch "^3.0.3" + read-pkg-up "^2.0.0" + resolve "^1.6.0" deep-extend@^0.6.0: version "0.6.0" @@ -2331,32 +2598,36 @@ defaults@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" dependencies: - clone "^1.0.2" + eslint-plugin-react-native-globals "^0.1.1" define-properties@^1.1.2: version "1.1.3" resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" dependencies: - object-keys "^1.0.12" + array-includes "^3.0.3" + doctrine "^2.1.0" + has "^1.0.3" + jsx-ast-utils "^2.0.1" + prop-types "^15.6.2" define-property@^0.2.5: version "0.2.5" resolved "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" dependencies: - is-descriptor "^0.1.0" + has "^1.0.1" define-property@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" dependencies: - is-descriptor "^1.0.0" + requireindex "~1.1.0" define-property@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" + esrecurse "^4.1.0" + estraverse "^4.1.1" delayed-stream@~1.0.0: version "1.0.0" @@ -2382,7 +2653,8 @@ detect-indent@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" dependencies: - repeating "^2.0.0" + acorn "^5.5.0" + acorn-jsx "^3.0.0" detect-libc@^1.0.2: version "1.0.3" @@ -2427,10 +2699,7 @@ duplexify@^3.6.0: version "3.6.0" resolved "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz#592903f5d80b38d037220541264d69a198fb3410" dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" + estraverse "^4.1.0" ecc-jsbn@~0.1.1: version "0.1.2" @@ -2463,13 +2732,17 @@ encoding@^0.1.11: version "0.1.12" resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" dependencies: - iconv-lite "~0.4.13" + merge "^1.2.0" end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.1" resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" dependencies: - once "^1.4.0" + cross-spawn-async "^2.1.1" + npm-run-path "^1.0.0" + object-assign "^4.0.1" + path-key "^1.0.0" + strip-eof "^1.0.0" envinfo@^3.0.0: version "3.11.1" @@ -4532,6 +4805,7 @@ mem-fs-editor@^4.0.0: mem-fs@^1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/mem-fs/-/mem-fs-1.1.3.tgz#b8ae8d2e3fcb6f5d3f9165c12d4551a065d989cc" + integrity sha1-uK6NLj/Lb10/kWXBLUVRoGXZicw= dependencies: through2 "^2.0.0" vinyl "^1.1.0" @@ -5062,6 +5336,18 @@ on-headers@~1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + integrity sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c= + once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -5311,19 +5597,27 @@ pinkie@^2.0.0: pirates@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.0.tgz#850b18781b4ac6ec58a43c9ed9ec5fe6796addbd" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.0.tgz#850b18781b4ac6ec58a43c9ed9ec5fe6796addbd" dependencies: node-modules-regexp "^1.0.0" +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + dependencies: + find-up "^1.0.0" + pkg-dir@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= dependencies: find-up "^2.1.0" plist@2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/plist/-/plist-2.0.1.tgz#0a32ca9481b1c364e92e18dc55c876de9d01da8b" + resolved "https://registry.yarnpkg.com/plist/-/plist-2.0.1.tgz#0a32ca9481b1c364e92e18dc55c876de9d01da8b" + integrity sha1-CjLKlIGxw2TpLhjcVch23p0B2os= dependencies: base64-js "1.1.2" xmlbuilder "8.2.2" @@ -5331,7 +5625,8 @@ plist@2.0.1: plist@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/plist/-/plist-1.2.0.tgz#084b5093ddc92506e259f874b8d9b1afb8c79593" + resolved "https://registry.yarnpkg.com/plist/-/plist-1.2.0.tgz#084b5093ddc92506e259f874b8d9b1afb8c79593" + integrity sha1-CEtQk93JJQbiWfh0uNmxr7jHlZM= dependencies: base64-js "0.0.8" util-deprecate "1.0.2" @@ -5340,7 +5635,8 @@ plist@^1.2.0: plugin-error@^0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" + resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" + integrity sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4= dependencies: ansi-cyan "^0.1.1" ansi-red "^0.1.1" @@ -5350,7 +5646,8 @@ plugin-error@^0.1.2: pluralize@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + resolved "http://registry.npm.taobao.org/pluralize/download/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + integrity sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c= pn@^1.1.0: version "1.1.0" @@ -5930,7 +6227,7 @@ resolve@1.1.7: version "1.1.7" resolved "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" -resolve@^1.1.6, resolve@^1.6.0: +resolve@^1.1.6, resolve@^1.3.2, resolve@^1.5.0, resolve@^1.6.0: version "1.8.1" resolved "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" dependencies: @@ -6500,7 +6797,12 @@ time-stamp@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" -timed-out@^4.0.1: +time-stamp@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" + integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= + +timed-out@^4.0.0, timed-out@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" @@ -7006,7 +7308,36 @@ xpipe@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/xpipe/-/xpipe-1.0.5.tgz#8dd8bf45fc3f7f55f0e054b878f43a62614dafdf" -xtend@~4.0.0, xtend@~4.0.1: +xmlbuilder@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.0.0.tgz#98b8f651ca30aa624036f127d11cc66dc7b907a3" + integrity sha1-mLj2UcowqmJANvEn0RzGbce5B6M= + dependencies: + lodash "^3.5.0" + +xmlbuilder@8.2.2: + version "8.2.2" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773" + integrity sha1-aSSGc0ELS6QuGmE2VR0pIjNap3M= + +xmldoc@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/xmldoc/-/xmldoc-0.4.0.tgz#d257224be8393eaacbf837ef227fd8ec25b36888" + integrity sha1-0lciS+g5PqrL+DfvIn/Y7CWzaIg= + dependencies: + sax "~1.1.1" + +xmldom@0.1.x: + version "0.1.27" + resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" + integrity sha1-1QH5ezvbQDr4757MIFcxh6rawOk= + +xpipe@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/xpipe/-/xpipe-1.0.5.tgz#8dd8bf45fc3f7f55f0e054b878f43a62614dafdf" + integrity sha1-jdi/Rfw/f1Xw4FS4ePQ6YmFNr98= + +xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" From 9ece5eedba2380e7d69c64eb1501ee588781de0f Mon Sep 17 00:00:00 2001 From: yuche Date: Tue, 25 Dec 2018 21:25:31 +0800 Subject: [PATCH 020/103] =?UTF-8?q?refactor(transformer):=20=E6=AF=8F?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E5=8C=85=E5=90=AB=20JSX=20=E7=9A=84=E7=B1=BB?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E9=83=BD=E6=9C=89=E7=8B=AC=E7=AB=8B=E7=9A=84?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=92=8C=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refactor(transformer): 每一个包含 JSX 的类函数都有独立的数据和引用 --- packages/taro-transformer-wx/src/class.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/taro-transformer-wx/src/class.ts b/packages/taro-transformer-wx/src/class.ts index aa6748674c3b..adc803f83b81 100644 --- a/packages/taro-transformer-wx/src/class.ts +++ b/packages/taro-transformer-wx/src/class.ts @@ -329,6 +329,10 @@ class Transformer { } }) } + if (name.startsWith('render')) { + self.renderJSX.set(name, path) + self.refIdMap.set(path, new Set([])) + } if (name === 'constructor') { path.traverse({ AssignmentExpression (p) { From 5707786cb6f68b9023012a60139b6d13d4ca9a8a Mon Sep 17 00:00:00 2001 From: yuche Date: Thu, 27 Dec 2018 11:08:40 +0800 Subject: [PATCH 021/103] =?UTF-8?q?refactor(transformer):=20=E5=8F=96?= =?UTF-8?q?=E6=B6=88=E6=8E=89=E7=B1=BB=E5=87=BD=E6=95=B0=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E5=8F=AA=E8=83=BD=E4=BC=A0=E5=85=A5=E4=B8=80=E4=B8=AA=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E7=9A=84=E9=99=90=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/class.ts | 4 ---- packages/taro-transformer-wx/src/render.ts | 19 +++++-------------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/packages/taro-transformer-wx/src/class.ts b/packages/taro-transformer-wx/src/class.ts index adc803f83b81..27d3155d188a 100644 --- a/packages/taro-transformer-wx/src/class.ts +++ b/packages/taro-transformer-wx/src/class.ts @@ -306,10 +306,6 @@ class Transformer { const args = callPath.node.arguments const { object, property } = callee.node if (t.isThisExpression(object) && t.isIdentifier(property) && property.name.startsWith('render')) { - if (args.length > 1) { - // @TODO: 加入文档地址 - throw codeFrameError(args[0], '类属性函数只能传入一个参数,如果你需要传入多个参数,考虑传入一个对象并使用解构语法,参考:') - } const name = property.name callPath.replaceWith(t.jSXElement( t.jSXOpeningElement(t.jSXIdentifier('Template'), [ diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts index 0a89b21ff478..2c8351afcd37 100644 --- a/packages/taro-transformer-wx/src/render.ts +++ b/packages/taro-transformer-wx/src/render.ts @@ -1170,20 +1170,11 @@ export class RenderParser { renderBody.traverse(this.quickappVistor) } - const renderMethodArgs = this.renderPath.node.params - if (!this.isDefaultRender) { - const len = renderMethodArgs.length - if (len === 0) { - // - } else if (len === 1) { - const renderArg = renderMethodArgs[0] - if (t.isRestElement(renderArg)) { - throw codeFrameError(renderMethodArgs, '类函数式组件只能传入一个参数,如果需要传入更多参数可以考虑传入一个对象。') - } - // this.renderArg = renderArg as any - } else { - throw codeFrameError(renderMethodArgs, '类函数式组件只能传入一个参数,如果需要传入更多参数可以考虑传入一个对象。') - } + if (t.isIdentifier(this.renderPath.node.key)) { + this.renderMethodName = this.renderPath.node.key.name + this.renderPath.node.key.name = this.getCreateJSXMethodName(this.renderMethodName) + } else { + throw codeFrameError(this.renderPath.node, '类函数对象必须指明函数名') } if (t.isIdentifier(this.renderPath.node.key)) { From 95b5b39731a3473ec582ca70d769deaa0fdb4899 Mon Sep 17 00:00:00 2001 From: yuche Date: Thu, 27 Dec 2018 17:00:13 +0800 Subject: [PATCH 022/103] =?UTF-8?q?feat(transformer):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=B1=BB=E5=87=BD=E6=95=B0=E5=BC=8F=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat(transformer): 支持类函数式组件 feat(transformer): 支持类函数式组件 --- packages/taro-transformer-wx/src/class.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/taro-transformer-wx/src/class.ts b/packages/taro-transformer-wx/src/class.ts index 27d3155d188a..eccfe9aa4790 100644 --- a/packages/taro-transformer-wx/src/class.ts +++ b/packages/taro-transformer-wx/src/class.ts @@ -325,10 +325,6 @@ class Transformer { } }) } - if (name.startsWith('render')) { - self.renderJSX.set(name, path) - self.refIdMap.set(path, new Set([])) - } if (name === 'constructor') { path.traverse({ AssignmentExpression (p) { From 9ef6e9f09b2d1ce53698aeb66166c4d783fb3a37 Mon Sep 17 00:00:00 2001 From: yuche Date: Tue, 25 Dec 2018 21:25:31 +0800 Subject: [PATCH 023/103] =?UTF-8?q?refactor(transformer):=20=E6=AF=8F?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E5=8C=85=E5=90=AB=20JSX=20=E7=9A=84=E7=B1=BB?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E9=83=BD=E6=9C=89=E7=8B=AC=E7=AB=8B=E7=9A=84?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=92=8C=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/class.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/taro-transformer-wx/src/class.ts b/packages/taro-transformer-wx/src/class.ts index eccfe9aa4790..27d3155d188a 100644 --- a/packages/taro-transformer-wx/src/class.ts +++ b/packages/taro-transformer-wx/src/class.ts @@ -325,6 +325,10 @@ class Transformer { } }) } + if (name.startsWith('render')) { + self.renderJSX.set(name, path) + self.refIdMap.set(path, new Set([])) + } if (name === 'constructor') { path.traverse({ AssignmentExpression (p) { From f45141730f2cd6760380d75f31cd8e6d7195479e Mon Sep 17 00:00:00 2001 From: yuche Date: Thu, 27 Dec 2018 10:43:46 +0800 Subject: [PATCH 024/103] =?UTF-8?q?refactor(transformer):=20=E7=B1=BB?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E7=BB=84=E4=BB=B6=E7=9A=84=20createData=20?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/render.ts | 64 ++++++++++++---------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts index 2c8351afcd37..489a4ec1a8a9 100644 --- a/packages/taro-transformer-wx/src/render.ts +++ b/packages/taro-transformer-wx/src/render.ts @@ -116,6 +116,7 @@ export class RenderParser { private isDefaultRender: boolean = false // private renderArg: t.Identifier | t.ObjectPattern | null = null private renderMethodName: string = '' + private renderArg: t.Identifier | t.ObjectPattern | null = null private renderPath: NodePath private methods: ClassMethodsMap @@ -1702,41 +1703,46 @@ export class RenderParser { ) } else { const usedState = Array.from(this.usedThisState).map(s => t.objectProperty(t.identifier(s), t.memberExpression(t.thisExpression(), t.identifier(s)))) - // if (this.renderArg) { - // if (t.isIdentifier(this.renderArg)) { - // const renderArgName = this.renderArg.name - // const shadowArgName = this.renderPath.scope.generateUid(renderArgName) - // const renderBody = this.renderPath.get('body') - // renderBody.traverse({ - // Scope ({ scope }) { - // scope.rename(renderArgName, shadowArgName) - // } - // }) - // this.renderPath.node.body.body.unshift( - // // t.expressionStatement(t.assignmentExpression('=', t.identifier(renderArgName), t.objectExpression([ - // // t.objectProperty( - // // t.identifier(shadowArgName), - // // t.identifier(shadowArgName) - // // ) - // // ]))) - // buildConstVariableDeclaration(shadowArgName, t.identifier(renderArgName)) - // ) - // usedState.push(t.objectProperty( - // t.identifier(shadowArgName), - // t.identifier(shadowArgName) - // )) - // } else { - // // TODO - // // usedState.push() - // } - // } + if (this.renderArg) { + if (t.isIdentifier(this.renderArg)) { + const renderArgName = this.renderArg.name + const shadowArgName = this.renderPath.scope.generateUid(renderArgName) + const renderBody = this.renderPath.get('body') + renderBody.traverse({ + Scope ({ scope }) { + scope.rename(renderArgName, shadowArgName) + } + }) + this.renderPath.node.body.body.unshift( + t.expressionStatement(t.assignmentExpression('=', t.identifier(renderArgName), t.objectExpression([ + t.objectProperty( + t.identifier(shadowArgName), + t.identifier(shadowArgName) + ) + ]))) + ) + usedState.push(t.objectProperty( + t.identifier(shadowArgName), + t.identifier(shadowArgName) + )) + } else { + // TODO + // usedState.push() + } + } this.renderPath.node.body.body.push( t.returnStatement(t.objectExpression(pendingState.properties.concat(usedState))) ) + + if (t.isIdentifier(this.renderPath.node.key)) { + this.renderPath.node.key.name = this.getCreateJSXMethodName(name) + } else { + throw codeFrameError(this.renderPath.node, '类函数对象必须指明函数名') + } } } - getCreateJSXMethodName = (name: string) => `_create${name.slice(6)}Data` + getCreateJSXMethodName = (name: string) => `_create${name}Data` createData () { if (!this.isDefaultRender) { From 456bc89e7ae15a9c80745e7a4472d0e09d59e331 Mon Sep 17 00:00:00 2001 From: yuche Date: Wed, 2 Jan 2019 21:54:07 +0800 Subject: [PATCH 025/103] =?UTF-8?q?feat(transformer):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E5=BC=8F=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../taro-transformer-wx/src/functional.ts | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 packages/taro-transformer-wx/src/functional.ts diff --git a/packages/taro-transformer-wx/src/functional.ts b/packages/taro-transformer-wx/src/functional.ts new file mode 100644 index 000000000000..ad5f1c6158b5 --- /dev/null +++ b/packages/taro-transformer-wx/src/functional.ts @@ -0,0 +1,47 @@ +import { Visitor } from 'babel-traverse' +import { codeFrameError, buildConstVariableDeclaration } from './utils' +import * as t from 'babel-types' +import { cloneDeep } from 'lodash' + +export const functionalComponent: () => { + visitor: Visitor +} = () => { + return { + visitor: { + JSXElement (path) { + const functionDecl = path.findParent(p => p.isFunctionDeclaration()) + if (functionDecl && functionDecl.isFunctionDeclaration()) { + const hasClassDecl = functionDecl.findParent(p => p.isClassDeclaration()) + if (hasClassDecl) { + return + } + const { id, body, params } = functionDecl.node + let arg: null | t.LVal = null + if (params.length > 1) { + throw codeFrameError(id, '函数式组件的参数最多只能传入一个') + } else if (params.length === 1) { + arg = params[0] + } + const cloneBody = cloneDeep(body) + if (arg) { + if (t.isIdentifier(arg)) { + cloneBody.body.push(buildConstVariableDeclaration(arg.name, t.memberExpression(t.thisExpression(), t.identifier('props')))) + } else if (t.isObjectPattern(arg)) { + cloneBody.body.push( + t.variableDeclaration('const', [ + t.variableDeclarator(arg, t.memberExpression(t.thisExpression(), t.identifier('props'))) + ]) + ) + } else { + throw codeFrameError(arg, '函数式组件只支持传入一个简单标识符或使用对象结构') + } + } + const classDecl = t.classDeclaration(id, t.memberExpression(t.identifier('Taro'), t.identifier('Component')), t.classBody([ + t.classMethod('method', t.identifier('render'), [], cloneBody) + ]), []) + functionDecl.replaceWith(classDecl) + } + } + } + } +} From f7780c9f2e45ba7e9404f2f9b09ae0d5541f8d9e Mon Sep 17 00:00:00 2001 From: yuche Date: Wed, 2 Jan 2019 21:54:44 +0800 Subject: [PATCH 026/103] =?UTF-8?q?refactor(eslint):=20=E5=8F=96=E6=B6=88?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E4=BD=BF=E7=94=A8=E5=87=BD=E6=95=B0=E5=BC=8F?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E7=9A=84=20eslint=20=E8=A7=84=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/eslint-plugin-taro/rules/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin-taro/rules/index.js b/packages/eslint-plugin-taro/rules/index.js index edce1cbfa959..0c486fc3503d 100644 --- a/packages/eslint-plugin-taro/rules/index.js +++ b/packages/eslint-plugin-taro/rules/index.js @@ -6,7 +6,7 @@ const allRules = { //'no-anonymous-function-in-props': require('./no-anonymous-function-in-props'), // 'no-jsx-in-class-method': require('./no-jsx-in-class-method'), 'no-spread-in-props': require('./no-spread-in-props'), - 'no-stateless-component': require('./no-stateless-component'), + // 'no-stateless-component': require('./no-stateless-component'), // 'jsx-handler-names': require('./jsx-handler-names'), 'reserve-class-properties': require('./reserve-class-properties'), // 'function-naming': require('./function-naming'), From fb7835d51e793a1172cb537d7bc942ae04bc5726 Mon Sep 17 00:00:00 2001 From: yuche Date: Thu, 3 Jan 2019 17:27:45 +0800 Subject: [PATCH 027/103] =?UTF-8?q?feat(transformer):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=94=A8=E5=87=BD=E6=95=B0=E8=A1=A8=E8=BE=BE=E5=BC=8F=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E5=87=BD=E6=95=B0=E5=BC=8F=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../taro-transformer-wx/src/functional.ts | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/taro-transformer-wx/src/functional.ts b/packages/taro-transformer-wx/src/functional.ts index ad5f1c6158b5..4225ee74347b 100644 --- a/packages/taro-transformer-wx/src/functional.ts +++ b/packages/taro-transformer-wx/src/functional.ts @@ -3,17 +3,51 @@ import { codeFrameError, buildConstVariableDeclaration } from './utils' import * as t from 'babel-types' import { cloneDeep } from 'lodash' +function initialIsCapital (word: string) { + return word[0] !== word[0].toLowerCase() +} + export const functionalComponent: () => { visitor: Visitor } = () => { return { visitor: { JSXElement (path) { + const arrowFuncExpr = path.findParent(p => p.isArrowFunctionExpression()) + if (arrowFuncExpr && arrowFuncExpr.isArrowFunctionExpression() && arrowFuncExpr.parentPath.isVariableDeclarator()) { + const valDecl = arrowFuncExpr.parentPath.parentPath + if (!valDecl.isVariableDeclaration()) { + throw codeFrameError(valDecl.node, '函数式组件不能同时定义多个值') + } + const id = arrowFuncExpr.parentPath.node.id + if (!t.isIdentifier(id)) { + throw codeFrameError(id, '函数式组件只能使用普通标识符定义') + } + if (!initialIsCapital(id.name)) { + throw codeFrameError(id, '组件命名规则请遵守帕斯卡命名法(Pascal Case)') + } + const hasClassDecl = arrowFuncExpr.findParent(p => p.isClassDeclaration()) + if (hasClassDecl) { + // @TODO: 加上链接 + throw codeFrameError(arrowFuncExpr.node, '在类中的函数式组件请写成类函数式组件:参考:') + } + const { body } = arrowFuncExpr.node + if (t.isBlockStatement(body)) { + valDecl.replaceWith(t.functionDeclaration(id, arrowFuncExpr.node.params, body)) + } else { + valDecl.replaceWith(t.functionDeclaration(id, arrowFuncExpr.node.params, t.blockStatement([ + t.returnStatement(body) + ]))) + } + return + } + const functionDecl = path.findParent(p => p.isFunctionDeclaration()) if (functionDecl && functionDecl.isFunctionDeclaration()) { const hasClassDecl = functionDecl.findParent(p => p.isClassDeclaration()) if (hasClassDecl) { - return + // @TODO: 加上链接 + throw codeFrameError(functionDecl.node, '在类中的函数式组件请写成类函数式组件:参考:') } const { id, body, params } = functionDecl.node let arg: null | t.LVal = null @@ -23,6 +57,9 @@ export const functionalComponent: () => { arg = params[0] } const cloneBody = cloneDeep(body) + if (!initialIsCapital(id.name)) { + throw codeFrameError(id, '组件命名规则请遵守帕斯卡命名法(Pascal Case)') + } if (arg) { if (t.isIdentifier(arg)) { cloneBody.body.push(buildConstVariableDeclaration(arg.name, t.memberExpression(t.thisExpression(), t.identifier('props')))) From b525ee4c96274c85a93cf760c5ac4f03b599eaeb Mon Sep 17 00:00:00 2001 From: yuche Date: Thu, 3 Jan 2019 20:09:28 +0800 Subject: [PATCH 028/103] =?UTF-8?q?test(transformer):=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E5=A3=B0=E6=98=8E=E5=BC=8F=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E5=92=8C=E5=87=BD=E6=95=B0=E8=A1=A8=E8=BE=BE=E5=BC=8F=E7=BB=84?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__tests__/functional.ts | 284 ++++++++++++++++++ 1 file changed, 284 insertions(+) create mode 100644 packages/taro-transformer-wx/__tests__/functional.ts diff --git a/packages/taro-transformer-wx/__tests__/functional.ts b/packages/taro-transformer-wx/__tests__/functional.ts new file mode 100644 index 000000000000..f61609b92da0 --- /dev/null +++ b/packages/taro-transformer-wx/__tests__/functional.ts @@ -0,0 +1,284 @@ +import transform from '../src' +import { buildComponent, baseOptions, evalClass, prettyPrint } from './utils' + +describe('函数式组件', () => { + describe('函数声明', () => { + test('无参数传入', () => { + const { template, ast,code } = transform({ + ...baseOptions, + isRoot: true, + code: `function Test () { + const tasks = [] + if (tasks !== null) { + return + + } + + return ( + + Hello world! + + ) + }` + }) + + const inst = evalClass(ast) + expect(inst.state.tasks).toEqual([]) + expect(inst.$usedState).toEqual(['tasks']) + + expect(template).toMatch(prettyPrint(` + + + + + + Hello world! + + + `)) + }) + + test('传入一个参数', () => { + const { template, ast,code } = transform({ + ...baseOptions, + isRoot: true, + code: `function Test (props) { + const { tasks } = props + if (tasks !== null) { + return + + } + + return ( + + Hello world! + + ) + }` + }) + + expect(template).toMatch(prettyPrint(` + + + + + + Hello world! + + + `)) + }) + + test('传入对象解构参数', () => { + const { template, ast,code } = transform({ + ...baseOptions, + isRoot: true, + code: `function Test ({ tasks }) { + if (tasks !== null) { + return + + } + + return ( + + Hello world! + + ) + }` + }) + + expect(template).toMatch(prettyPrint(` + + + + + + Hello world! + + + `)) + }) + + test('传入数组解构参数', () => { + expect(() => { + transform({ + ...baseOptions, + isRoot: true, + code: `function Test ([a]) { + if (tasks !== null) { + return + + } + + return ( + + Hello world! + + ) + }` + }) + }).toThrowError(/函数式组件只支持传入一个简单标识符或使用对象结构/) + }) + + test('传入多个参数', () => { + expect(() => { + transform({ + ...baseOptions, + isRoot: true, + code: `function Test (a, b) { + if (tasks !== null) { + return + + } + + return ( + + Hello world! + + ) + }` + }) + }).toThrowError(/函数式组件的参数最多只能传入一个/) + }) + }) + + describe('函数表达式', () => { + test('无参数传入', () => { + const { template, ast,code } = transform({ + ...baseOptions, + isRoot: true, + code: `const Test = () => { + const tasks = [] + if (tasks !== null) { + return + + } + + return ( + + Hello world! + + ) + }` + }) + + const inst = evalClass(ast) + expect(inst.state.tasks).toEqual([]) + expect(inst.$usedState).toEqual(['tasks']) + + expect(template).toMatch(prettyPrint(` + + + + + + Hello world! + + + `)) + }) + + test('传入一个参数', () => { + const { template, ast,code } = transform({ + ...baseOptions, + isRoot: true, + code: `const Test = (props) => { + const { tasks } = props + if (tasks !== null) { + return + + } + + return ( + + Hello world! + + ) + }` + }) + + expect(template).toMatch(prettyPrint(` + + + + + + Hello world! + + + `)) + }) + + test('传入对象解构参数', () => { + const { template, ast,code } = transform({ + ...baseOptions, + isRoot: true, + code: `const Test = ({ tasks }) => { + if (tasks !== null) { + return + + } + + return ( + + Hello world! + + ) + }` + }) + + expect(template).toMatch(prettyPrint(` + + + + + + Hello world! + + + `)) + }) + + test('传入数组解构参数', () => { + expect(() => { + transform({ + ...baseOptions, + isRoot: true, + code: `const Test = ([a]) => { + if (tasks !== null) { + return + + } + + return ( + + Hello world! + + ) + }` + }) + }).toThrowError(/函数式组件只支持传入一个简单标识符或使用对象结构/) + }) + + test('传入多个参数', () => { + expect(() => { + transform({ + ...baseOptions, + isRoot: true, + code: `const Test = (a, b) => { + if (tasks !== null) { + return + + } + + return ( + + Hello world! + + ) + }` + }) + }).toThrowError(/函数式组件的参数最多只能传入一个/) + }) + }) +}) From bc935a8e2fbb5c1b61e1442aaca3792f58f21393 Mon Sep 17 00:00:00 2001 From: yuche Date: Fri, 4 Jan 2019 11:00:34 +0800 Subject: [PATCH 029/103] =?UTF-8?q?test(transformer):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E7=9A=84=E7=B1=BB=E5=87=BD=E6=95=B0=E5=BC=8F?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__tests__/functional.ts | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/packages/taro-transformer-wx/__tests__/functional.ts b/packages/taro-transformer-wx/__tests__/functional.ts index f61609b92da0..2cc5df34d78c 100644 --- a/packages/taro-transformer-wx/__tests__/functional.ts +++ b/packages/taro-transformer-wx/__tests__/functional.ts @@ -1,6 +1,114 @@ import transform from '../src' import { buildComponent, baseOptions, evalClass, prettyPrint } from './utils' +describe('类函数式组件', () => { + test('简单情况', () => { + const { template, ast, code } = transform({ + ...baseOptions, + isRoot: true, + code: buildComponent(` + const array = [{ list: [] }] + return ( + {this.renderTest()} + ) + `, `state = { tasks: [] }; renderTest () { + return ( + abc + ) + }`) + }) + + const inst = evalClass(ast) + expect(inst.state.anonymousState__temp2).toEqual({}) + expect(inst.$usedState.includes('anonymousState__temp2')).toBe(true) + + expect(template).toMatch(prettyPrint(` + + + + + + + `)) + }) + + test('命名为变量', () => { + const { template, ast, code } = transform({ + ...baseOptions, + isRoot: true, + code: buildComponent(` + const test = this.renderTest() + return ( + {test} + ) + `, `state = { tasks: [] }; renderTest () { + return ( + abc + ) + }`) + }) + + const inst = evalClass(ast) + expect(inst.state.anonymousState__temp).toEqual({}) + expect(inst.$usedState.includes('anonymousState__temp')).toBe(true) + + expect(template).toMatch(prettyPrint(` + + + + + + + `)) + }) + + test.skip('在循环中直接 return', () => { + const { template, ast, code } = transform({ + ...baseOptions, + isRoot: true, + code: buildComponent(` + const test = this.renderTest() + return ( + {this.state.tasks.map(i => { + return {this.renderTest()} + })} + ) + `, `state = { tasks: [] }; renderTest () { + return ( + abc + ) + }`) + }) + + const inst = evalClass(ast) + // console.log(code) + // console.log(template) + expect(inst.state.anonymousState__temp).toEqual({}) + expect(inst.$usedState.includes('anonymousState__temp')).toBe(true) + + expect(template).toMatch(prettyPrint(` + + + + + + + `)) + }) +}) + describe('函数式组件', () => { describe('函数声明', () => { test('无参数传入', () => { From 13aaac32073e780f0d16ffef947e01dc7350a701 Mon Sep 17 00:00:00 2001 From: yuche Date: Fri, 4 Jan 2019 11:15:38 +0800 Subject: [PATCH 030/103] =?UTF-8?q?refactor(transformer):=20=E5=88=9B?= =?UTF-8?q?=E9=80=A0=E7=B1=BB=E5=87=BD=E6=95=B0=E5=BC=8F=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E5=A6=82=E6=9E=9C=E6=B2=A1=E6=9C=89=E4=BC=A0=E5=85=A5=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E5=B0=B1=E5=BF=85=E9=A1=BB=E8=B0=83=E7=94=A8=E5=AF=B9?= =?UTF-8?q?=E5=BA=94=E7=9A=84=20createData=20=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../taro-transformer-wx/__tests__/functional.ts | 10 ++++------ packages/taro-transformer-wx/src/class.ts | 13 +++++++++---- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/taro-transformer-wx/__tests__/functional.ts b/packages/taro-transformer-wx/__tests__/functional.ts index 2cc5df34d78c..2bdb82be0b27 100644 --- a/packages/taro-transformer-wx/__tests__/functional.ts +++ b/packages/taro-transformer-wx/__tests__/functional.ts @@ -19,8 +19,7 @@ describe('类函数式组件', () => { }) const inst = evalClass(ast) - expect(inst.state.anonymousState__temp2).toEqual({}) - expect(inst.$usedState.includes('anonymousState__temp2')).toBe(true) + expect(inst.state).toEqual({ tasks: [] }) expect(template).toMatch(prettyPrint(` - + `)) @@ -53,8 +52,7 @@ describe('类函数式组件', () => { }) const inst = evalClass(ast) - expect(inst.state.anonymousState__temp).toEqual({}) - expect(inst.$usedState.includes('anonymousState__temp')).toBe(true) + expect(inst.state).toEqual({ tasks: [] }) expect(template).toMatch(prettyPrint(` - + `)) diff --git a/packages/taro-transformer-wx/src/class.ts b/packages/taro-transformer-wx/src/class.ts index 27d3155d188a..df4fd53ebde0 100644 --- a/packages/taro-transformer-wx/src/class.ts +++ b/packages/taro-transformer-wx/src/class.ts @@ -307,16 +307,21 @@ class Transformer { const { object, property } = callee.node if (t.isThisExpression(object) && t.isIdentifier(property) && property.name.startsWith('render')) { const name = property.name - callPath.replaceWith(t.jSXElement( - t.jSXOpeningElement(t.jSXIdentifier('Template'), [ - t.jSXAttribute(t.jSXIdentifier('is'), t.stringLiteral(name)), + const templateAttr = [ + t.jSXAttribute(t.jSXIdentifier('is'), t.stringLiteral(name)) + ] + if (args.length) { + templateAttr.push( t.jSXAttribute(t.jSXIdentifier('data'), t.jSXExpressionContainer( t.callExpression(t.memberExpression( t.thisExpression(), t.identifier(`_create${name.slice(6)}Data`) ), args) )) - ]), + ) + } + callPath.replaceWith(t.jSXElement( + t.jSXOpeningElement(t.jSXIdentifier('Template'), templateAttr), t.jSXClosingElement(t.jSXIdentifier('Template')), [], false From 10755aa73dc167eaf0a2cc6cfecff873e26b8357 Mon Sep 17 00:00:00 2001 From: yuche Date: Fri, 4 Jan 2019 18:25:59 +0800 Subject: [PATCH 031/103] =?UTF-8?q?fix(transformer):=20=E5=9C=A8=E5=BE=AA?= =?UTF-8?q?=E7=8E=AF=E4=B8=AD=E4=BD=BF=E7=94=A8=E7=B1=BB=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E5=BC=8F=E7=BB=84=E4=BB=B6=E4=B8=8D=E4=BC=9A=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E6=96=B0=E6=95=B0=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__tests__/functional.ts | 341 +++++++++++++----- packages/taro-transformer-wx/src/class.ts | 71 ++-- packages/taro-transformer-wx/src/render.ts | 2 +- 3 files changed, 301 insertions(+), 113 deletions(-) diff --git a/packages/taro-transformer-wx/__tests__/functional.ts b/packages/taro-transformer-wx/__tests__/functional.ts index 2bdb82be0b27..55d63e0a1d29 100644 --- a/packages/taro-transformer-wx/__tests__/functional.ts +++ b/packages/taro-transformer-wx/__tests__/functional.ts @@ -2,108 +2,279 @@ import transform from '../src' import { buildComponent, baseOptions, evalClass, prettyPrint } from './utils' describe('类函数式组件', () => { - test('简单情况', () => { - const { template, ast, code } = transform({ - ...baseOptions, - isRoot: true, - code: buildComponent(` - const array = [{ list: [] }] - return ( - {this.renderTest()} - ) - `, `state = { tasks: [] }; renderTest () { - return ( - abc - ) - }`) + describe('不传参', () => { + test('简单情况', () => { + const { template, ast, code } = transform({ + ...baseOptions, + isRoot: true, + code: buildComponent(` + const array = [{ list: [] }] + return ( + {this.renderTest()} + ) + `, `state = { tasks: [] }; renderTest () { + return ( + abc + ) + }`) + }) + + const inst = evalClass(ast) + expect(inst.state).toEqual({ tasks: [] }) + + expect(template).toMatch(prettyPrint(` + + + + + + + `)) }) - const inst = evalClass(ast) - expect(inst.state).toEqual({ tasks: [] }) + test('命名为变量', () => { + const { template, ast, code } = transform({ + ...baseOptions, + isRoot: true, + code: buildComponent(` + const test = this.renderTest() + return ( + {test} + ) + `, `state = { tasks: [] }; renderTest () { + return ( + abc + ) + }`) + }) + + const inst = evalClass(ast) + expect(inst.state).toEqual({ tasks: [] }) + + expect(template).toMatch(prettyPrint(` + + + + + + + `)) + }) - expect(template).toMatch(prettyPrint(` - - - - - - - `)) - }) - - test('命名为变量', () => { - const { template, ast, code } = transform({ - ...baseOptions, - isRoot: true, - code: buildComponent(` - const test = this.renderTest() - return ( - {test} - ) - `, `state = { tasks: [] }; renderTest () { - return ( - abc - ) - }`) + `)) }) - const inst = evalClass(ast) - expect(inst.state).toEqual({ tasks: [] }) + test('在循环中直接 return', () => { + const { template, ast, code } = transform({ + ...baseOptions, + isRoot: true, + code: buildComponent(` + const test = this.renderTest() + return ( + {this.state.tasks.map(i => this.renderTest())} + ) + `, `state = { tasks: [] }; renderTest () { + return ( + abc + ) + }`) + }) - expect(template).toMatch(prettyPrint(` - - - - - - - `)) + `)) + }) }) - test.skip('在循环中直接 return', () => { - const { template, ast, code } = transform({ - ...baseOptions, - isRoot: true, - code: buildComponent(` - const test = this.renderTest() - return ( - {this.state.tasks.map(i => { - return {this.renderTest()} - })} - ) - `, `state = { tasks: [] }; renderTest () { - return ( - abc - ) - }`) + describe('传参', () => { + + test('简单情况', () => { + const { template, ast, code } = transform({ + ...baseOptions, + isRoot: true, + code: buildComponent(` + const array = [{ list: [] }] + return ( + {this.renderTest([])} + ) + `, `state = { tasks: [] }; renderTest (p) { + return ( + {p} + ) + }`) + }) + + const inst = evalClass(ast) + expect(inst.state.anonymousState__temp).toEqual({ p: [] }) + expect(template).toMatch(prettyPrint(` + + + + + + + `)) + }) + + test('命名为变量', () => { + const { template, ast, code } = transform({ + ...baseOptions, + isRoot: true, + code: buildComponent(` + const test = this.renderTest([]) + return ( + {test} + ) + `, `state = { tasks: [] }; renderTest (p) { + return ( + {p} + ) + }`) + }) + + const inst = evalClass(ast) + expect(inst.state.anonymousState__temp).toEqual({ p: [] }) + + expect(template).toMatch(prettyPrint(` + + + + + + + `)) + }) + + test('循环', () => { + const { template, ast, code } = transform({ + ...baseOptions, + isRoot: true, + code: buildComponent(` + return ( + {this.state.tasks.map(i => { + return {this.renderTest([])} + })} + ) + `, `state = { tasks: [] }; renderTest (p) { + return ( + {p} + ) + }`) + }) + + const inst = evalClass(ast) + expect(inst.state).toEqual({ tasks: [], loopArray0: [] }) + + expect(template).toMatch(prettyPrint(` + + + + + + + + + `)) }) - const inst = evalClass(ast) - // console.log(code) - // console.log(template) - expect(inst.state.anonymousState__temp).toEqual({}) - expect(inst.$usedState.includes('anonymousState__temp')).toBe(true) + test('在循环中直接 return', () => { + const { template, ast, code } = transform({ + ...baseOptions, + isRoot: true, + code: buildComponent(` + const test = this.renderTest() + return ( + {this.state.tasks.map(i => this.renderTest())} + ) + `, `state = { tasks: [] }; renderTest () { + return ( + abc + ) + }`) + }) - expect(template).toMatch(prettyPrint(` - - - - - - - `)) + `)) + }) }) }) diff --git a/packages/taro-transformer-wx/src/class.ts b/packages/taro-transformer-wx/src/class.ts index df4fd53ebde0..9253fe0b5296 100644 --- a/packages/taro-transformer-wx/src/class.ts +++ b/packages/taro-transformer-wx/src/class.ts @@ -298,34 +298,51 @@ class Transformer { } } }, - CallExpression (callPath) { - const callee = callPath.get('callee') - if (!callee.isMemberExpression()) { - return - } - const args = callPath.node.arguments - const { object, property } = callee.node - if (t.isThisExpression(object) && t.isIdentifier(property) && property.name.startsWith('render')) { - const name = property.name - const templateAttr = [ - t.jSXAttribute(t.jSXIdentifier('is'), t.stringLiteral(name)) - ] - if (args.length) { - templateAttr.push( - t.jSXAttribute(t.jSXIdentifier('data'), t.jSXExpressionContainer( - t.callExpression(t.memberExpression( - t.thisExpression(), - t.identifier(`_create${name.slice(6)}Data`) - ), args) - )) - ) + CallExpression: { + enter (callPath: NodePath) { + const callee = callPath.get('callee') + if (!callee.isMemberExpression()) { + return + } + const args = callPath.node.arguments + const { object, property } = callee.node + if (t.isThisExpression(object) && t.isIdentifier(property) && property.name.startsWith('render')) { + const name = property.name + const templateAttr = [ + t.jSXAttribute(t.jSXIdentifier('is'), t.stringLiteral(name)) + ] + if (args.length) { + templateAttr.push( + t.jSXAttribute(t.jSXIdentifier('data'), t.jSXExpressionContainer( + t.callExpression(t.memberExpression( + t.thisExpression(), + t.identifier(`_create${name.slice(6)}Data`) + ), args) + )) + ) + } + callPath.replaceWith(t.jSXElement( + t.jSXOpeningElement(t.jSXIdentifier('Template'), templateAttr), + t.jSXClosingElement(t.jSXIdentifier('Template')), + [], + false + )) + } + }, + exit (callPath: NodePath) { + const jsxExpr = callPath.parentPath + if (!jsxExpr.isJSXExpressionContainer()) { + return + } + const jsxAttr = jsxExpr.parentPath + if (!jsxAttr.isJSXAttribute()) { + return + } + const { name: attrName } = jsxAttr.node + if (!t.isJSXIdentifier(attrName, { name: 'data' })) { + return } - callPath.replaceWith(t.jSXElement( - t.jSXOpeningElement(t.jSXIdentifier('Template'), templateAttr), - t.jSXClosingElement(t.jSXIdentifier('Template')), - [], - false - )) + generateAnonymousState(callPath.scope, callPath, self.refIdMap.get(path)!) } } }) diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts index 489a4ec1a8a9..e9ffae8d8392 100644 --- a/packages/taro-transformer-wx/src/render.ts +++ b/packages/taro-transformer-wx/src/render.ts @@ -986,7 +986,7 @@ export class RenderParser { if (jsxAttr && t.isJSXIdentifier(jsxAttr.node.name) && jsxAttr.node.name.name.startsWith('on')) { return } - if (t.isIdentifier(id)) { + if (t.isIdentifier(id) && !(id.name.startsWith('_create') && id.name.endsWith('Data'))) { this.referencedIdentifiers.add(id) this.usedThisProperties.add(id.name) } From bc0d58c5742a005d5939b0514162151d04b69efe Mon Sep 17 00:00:00 2001 From: luckyadam Date: Wed, 2 Jan 2019 00:33:03 +0800 Subject: [PATCH 032/103] =?UTF-8?q?feat(cli):=20=E4=BD=BF=E7=94=A8=20types?= =?UTF-8?q?cript=20=E9=87=8D=E6=9E=84=20cli=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/bin/taro-doctor | 13 +- packages/taro-cli/src/doctor/index.ts | 13 +- .../taro-cli/src/doctor/validatorEslintrc.ts | 2 +- packages/taro-cli/yarn.lock | 379 ++---------------- 4 files changed, 30 insertions(+), 377 deletions(-) diff --git a/packages/taro-cli/bin/taro-doctor b/packages/taro-cli/bin/taro-doctor index d652f6f97e90..c8df1543db30 100755 --- a/packages/taro-cli/bin/taro-doctor +++ b/packages/taro-cli/bin/taro-doctor @@ -6,11 +6,8 @@ const _ = require('lodash/fp') const ora = require('ora') const chalk = require('chalk') const fs = require('fs-extra') -<<<<<<< HEAD const { PROJECT_CONFIG } = require('../dist/util/constants') -======= -const { PROJECT_CONFIG } = require('../src/util') ->>>>>>> feat(doctor): 增加 doctor 子命令 + const PROJECT_CONF_PATH = path.join(process.cwd(), PROJECT_CONFIG) if (!fs.existsSync(PROJECT_CONF_PATH)) { @@ -18,11 +15,7 @@ if (!fs.existsSync(PROJECT_CONF_PATH)) { process.exit(1) } -<<<<<<< HEAD const { validators } = require('../dist/doctor').default -======= -const { validators } = require('../src/doctor') ->>>>>>> feat(doctor): 增加 doctor 子命令 const NOTE_ALL_RIGHT = chalk.green('[✓] ') const NOTE_VALID = chalk.yellow('[!] ') @@ -65,11 +58,7 @@ program async function diagnose () { const spinner = ora('正在诊断项目...').start() -<<<<<<< HEAD const reportsP = _.map(validator => validator(), validators) -======= - const reportsP = _.invokeMap(_.call, validators) ->>>>>>> feat(doctor): 增加 doctor 子命令 const reports = await Promise.all(reportsP) spinner.succeed('诊断完成') printReport(reports) diff --git a/packages/taro-cli/src/doctor/index.ts b/packages/taro-cli/src/doctor/index.ts index 59247fdfa2a3..3dec316e1010 100644 --- a/packages/taro-cli/src/doctor/index.ts +++ b/packages/taro-cli/src/doctor/index.ts @@ -1,13 +1,8 @@ -import configValidator from './configValidator'; -import packageValidator from './packageValidator'; -import recommandValidator from './recommandValidator'; -import eslintValidator from './eslintValidator'; - export default { validators: [ - configValidator, - packageValidator, - recommandValidator, - eslintValidator + require('./configValidator'), + require('./packageValidator'), + require('./recommandValidator'), + require('./eslintValidator') ] } diff --git a/packages/taro-cli/src/doctor/validatorEslintrc.ts b/packages/taro-cli/src/doctor/validatorEslintrc.ts index 521a005d3929..4e168dbb2596 100644 --- a/packages/taro-cli/src/doctor/validatorEslintrc.ts +++ b/packages/taro-cli/src/doctor/validatorEslintrc.ts @@ -1,4 +1,4 @@ -module.exports = { +export default { 'extends': ['taro'], 'rules': { 'no-unused-vars': ['error', { 'varsIgnorePattern': 'Taro' }], diff --git a/packages/taro-cli/yarn.lock b/packages/taro-cli/yarn.lock index f10c66404a4a..2f9854cbcc81 100644 --- a/packages/taro-cli/yarn.lock +++ b/packages/taro-cli/yarn.lock @@ -867,135 +867,11 @@ babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: babel-helper-builder-react-jsx@^6.24.1: version "6.26.0" resolved "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" - integrity sha1-zORReto1b0IgvK6KAsKzRvmlZmQ= - dependencies: - babel-helper-explode-assignable-expression "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-builder-react-jsx@^6.24.1: - version "6.26.0" - resolved "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0" - integrity sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA= - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" - integrity sha1-zORReto1b0IgvK6KAsKzRvmlZmQ= - dependencies: - babel-helper-explode-assignable-expression "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-builder-react-jsx@^6.24.1: - version "6.26.0" - resolved "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0" - integrity sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA= dependencies: babel-runtime "^6.26.0" babel-types "^6.26.0" esutils "^2.0.2" -babel-helper-call-delegate@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" - integrity sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340= - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-define-map@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" - integrity sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8= - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-evaluate-path@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz#a62fa9c4e64ff7ea5cea9353174ef023a900a67c" - integrity sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA== - -babel-helper-explode-assignable-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" - integrity sha1-8luCz33BBDPFX3BZLVdGQArCLKo= - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-explode-class@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" - integrity sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes= - dependencies: - babel-helper-bindify-decorators "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-call-delegate@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" - integrity sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340= - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-define-map@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" - integrity sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8= - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-evaluate-path@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz#a62fa9c4e64ff7ea5cea9353174ef023a900a67c" - integrity sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA== - -babel-helper-explode-assignable-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" - integrity sha1-8luCz33BBDPFX3BZLVdGQArCLKo= - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-explode-class@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" - integrity sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes= - dependencies: - babel-helper-bindify-decorators "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - babel-helper-call-delegate@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" @@ -1042,7 +918,6 @@ babel-helper-explode-class@^6.24.1: babel-helper-function-name@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" - integrity sha1-00dbjAPtmCQqJbSDUasYOZ01gKk= dependencies: babel-helper-get-function-arity "^6.24.1" babel-runtime "^6.22.0" @@ -1053,69 +928,8 @@ babel-helper-function-name@^6.24.1: babel-helper-get-function-arity@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" - integrity sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0= - dependencies: - babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" - babel-plugin-syntax-exponentiation-operator "^6.8.0" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-hoist-variables@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" - integrity sha1-HssnaJydJVE+rbyZFKc/VAi+enY= - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-mark-eval-scopes@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz#d244a3bef9844872603ffb46e22ce8acdf551562" - integrity sha1-0kSjvvmESHJgP/tG4izorN9VFWI= - -babel-helper-optimise-call-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" - integrity sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc= - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-regex@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" - integrity sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI= dependencies: - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-remap-async-to-generator@^6.16.0, babel-helper-remap-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" - integrity sha1-XsWBgnrXI/7N04HxySg5BnbkVRs= - dependencies: - babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-remove-or-void@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz#a4f03b40077a0ffe88e45d07010dee241ff5ae60" - integrity sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA= - -babel-helper-replace-supers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" - integrity sha1-v22/5Dk40XNpohPKiov3S2qQqxo= - dependencies: - babel-helper-optimise-call-expression "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" babel-types "^6.24.1" babel-helper-hoist-variables@^6.24.1: @@ -1180,7 +994,6 @@ babel-helper-replace-supers@^6.24.1: babel-helpers@^6.24.1, babel-helpers@^6.8.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" - integrity sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI= dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" @@ -1195,7 +1008,6 @@ babel-jest@^23.6.0: babel-messages@^6.23.0, babel-messages@^6.8.0: version "6.23.0" resolved "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= dependencies: babel-runtime "^6.22.0" @@ -1246,7 +1058,6 @@ babel-plugin-react-transform@^3.0.0: babel-plugin-remove-dead-code@^1.3.2: version "1.3.2" resolved "https://registry.npmjs.org/babel-plugin-remove-dead-code/-/babel-plugin-remove-dead-code-1.3.2.tgz#e1a2cd9595bb2f767291f35cab4ec9b467ee62c6" - integrity sha1-4aLNlZW7L3ZykfNcq07JtGfuYsY= dependencies: babel-core "6.10.4" @@ -1265,17 +1076,10 @@ babel-plugin-syntax-class-constructor-call@^6.18.0: babel-plugin-syntax-class-properties@^6.5.0, babel-plugin-syntax-class-properties@^6.8.0: version "6.13.0" resolved "http://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" - integrity sha1-1+sjt5oxf4VDlixQW4J8fWysJ94= babel-plugin-syntax-decorators@^6.1.18, babel-plugin-syntax-decorators@^6.13.0: version "6.13.0" resolved "http://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" - integrity sha1-MSVjtNvePMgGzuPkFszurd0RrAs= - -babel-plugin-syntax-do-expressions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz#5747756139aa26d390d09410b03744ba07e4796d" - integrity sha1-V0d1YTmqJtOQ0JQQsDdEugfkeW0= babel-plugin-syntax-do-expressions@^6.8.0: version "6.13.0" @@ -1284,17 +1088,6 @@ babel-plugin-syntax-do-expressions@^6.8.0: babel-plugin-syntax-dynamic-import@^6.18.0: version "6.18.0" resolved "http://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" - integrity sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo= - -babel-plugin-syntax-exponentiation-operator@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" - integrity sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4= - -babel-plugin-syntax-export-extensions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" - integrity sha1-cKFITw+QiaToStRLrDU8lbmxJyE= babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" @@ -1307,7 +1100,6 @@ babel-plugin-syntax-export-extensions@^6.8.0: babel-plugin-syntax-flow@^6.18.0, babel-plugin-syntax-flow@^6.5.0, babel-plugin-syntax-flow@^6.8.0: version "6.18.0" resolved "http://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" - integrity sha1-TDqyCiryaqIM0lmVw5jE63AxDI0= babel-plugin-syntax-function-bind@^6.8.0: version "6.13.0" @@ -1316,53 +1108,6 @@ babel-plugin-syntax-function-bind@^6.8.0: babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.5.0, babel-plugin-syntax-jsx@^6.8.0: version "6.18.0" resolved "http://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" - integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= - -babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" - integrity sha1-/WU28rzhODb/o6VFjEkDpZe7O/U= - -babel-plugin-syntax-trailing-function-commas@^6.20.0, babel-plugin-syntax-trailing-function-commas@^6.22.0, babel-plugin-syntax-trailing-function-commas@^6.5.0, babel-plugin-syntax-trailing-function-commas@^6.8.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" - integrity sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM= - -babel-plugin-transform-async-generator-functions@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" - integrity sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds= - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-generators "^6.5.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-async-to-generator@6.16.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.16.0.tgz#19ec36cb1486b59f9f468adfa42ce13908ca2999" - integrity sha1-Gew2yxSGtZ+fRorfpCzhOQjKKZk= - dependencies: - babel-helper-remap-async-to-generator "^6.16.0" - babel-plugin-syntax-async-functions "^6.8.0" - babel-runtime "^6.0.0" - -babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" - integrity sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E= - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-functions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-class-constructor-call@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz#80dc285505ac067dcb8d6c65e2f6f11ab7765ef9" - integrity sha1-gNwoVQWsBn3LjWxl4vbxGrd2Xvk= - dependencies: - babel-plugin-syntax-class-constructor-call "^6.18.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0: version "6.13.0" @@ -1407,7 +1152,6 @@ babel-plugin-transform-class-constructor-call@^6.24.1: babel-plugin-transform-class-properties@^6.18.0, babel-plugin-transform-class-properties@^6.24.1, babel-plugin-transform-class-properties@^6.5.0, babel-plugin-transform-class-properties@^6.8.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" - integrity sha1-anl2PqYdM9NvN7YRqp3vgagbRqw= dependencies: babel-helper-function-name "^6.24.1" babel-plugin-syntax-class-properties "^6.8.0" @@ -1417,7 +1161,6 @@ babel-plugin-transform-class-properties@^6.18.0, babel-plugin-transform-class-pr babel-plugin-transform-decorators-legacy@^1.3.4: version "1.3.5" resolved "https://registry.npmjs.org/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.5.tgz#0e492dffa0edd70529072887f8aa86d4dd8b40a1" - integrity sha512-jYHwjzRXRelYQ1uGm353zNzf3QmtdCfvJbuYTZ4gKveK7M9H1fs3a5AKdY1JUDl0z97E30ukORW1dzhWvsabtA== dependencies: babel-plugin-syntax-decorators "^6.1.18" babel-runtime "^6.2.0" @@ -1436,7 +1179,6 @@ babel-plugin-transform-decorators@^6.24.1: babel-plugin-transform-define@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/babel-plugin-transform-define/-/babel-plugin-transform-define-1.3.0.tgz#94c5f9459c810c738cc7c50cbd44a31829d6f319" - integrity sha1-lMX5RZyBDHOMx8UMvUSjGCnW8xk= dependencies: lodash "4.17.4" traverse "0.6.6" @@ -2432,7 +2174,7 @@ core-js@^2.2.2, core-js@^2.4.1, core-js@^2.5.7: version "2.6.2" resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.2.tgz#267988d7268323b349e20b4588211655f0e83944" -core-js@^2.2.2, core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0, core-js@^2.5.7: +core-js@^2.4.0, core-js@^2.5.0: version "2.5.7" resolved "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" @@ -2569,16 +2311,7 @@ decompress-response@^3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" dependencies: - contains-path "^0.1.0" - debug "^2.6.8" - doctrine "1.5.0" - eslint-import-resolver-node "^0.3.1" - eslint-module-utils "^2.2.0" - has "^1.0.1" - lodash "^4.17.4" - minimatch "^3.0.3" - read-pkg-up "^2.0.0" - resolve "^1.6.0" + mimic-response "^1.0.0" deep-extend@^0.6.0: version "0.6.0" @@ -2598,36 +2331,32 @@ defaults@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" dependencies: - eslint-plugin-react-native-globals "^0.1.1" + clone "^1.0.2" define-properties@^1.1.2: version "1.1.3" resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" dependencies: - array-includes "^3.0.3" - doctrine "^2.1.0" - has "^1.0.3" - jsx-ast-utils "^2.0.1" - prop-types "^15.6.2" + object-keys "^1.0.12" define-property@^0.2.5: version "0.2.5" resolved "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" dependencies: - has "^1.0.1" + is-descriptor "^0.1.0" define-property@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" dependencies: - requireindex "~1.1.0" + is-descriptor "^1.0.0" define-property@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" + is-descriptor "^1.0.2" + isobject "^3.0.1" delayed-stream@~1.0.0: version "1.0.0" @@ -2653,8 +2382,7 @@ detect-indent@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" dependencies: - acorn "^5.5.0" - acorn-jsx "^3.0.0" + repeating "^2.0.0" detect-libc@^1.0.2: version "1.0.3" @@ -2699,7 +2427,10 @@ duplexify@^3.6.0: version "3.6.0" resolved "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz#592903f5d80b38d037220541264d69a198fb3410" dependencies: - estraverse "^4.1.0" + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" ecc-jsbn@~0.1.1: version "0.1.2" @@ -2732,17 +2463,13 @@ encoding@^0.1.11: version "0.1.12" resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" dependencies: - merge "^1.2.0" + iconv-lite "~0.4.13" end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.1" resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" dependencies: - cross-spawn-async "^2.1.1" - npm-run-path "^1.0.0" - object-assign "^4.0.1" - path-key "^1.0.0" - strip-eof "^1.0.0" + once "^1.4.0" envinfo@^3.0.0: version "3.11.1" @@ -4805,7 +4532,6 @@ mem-fs-editor@^4.0.0: mem-fs@^1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/mem-fs/-/mem-fs-1.1.3.tgz#b8ae8d2e3fcb6f5d3f9165c12d4551a065d989cc" - integrity sha1-uK6NLj/Lb10/kWXBLUVRoGXZicw= dependencies: through2 "^2.0.0" vinyl "^1.1.0" @@ -5336,18 +5062,6 @@ on-headers@~1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - -on-headers@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" - integrity sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c= - once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -5597,27 +5311,19 @@ pinkie@^2.0.0: pirates@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.0.tgz#850b18781b4ac6ec58a43c9ed9ec5fe6796addbd" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.0.tgz#850b18781b4ac6ec58a43c9ed9ec5fe6796addbd" dependencies: node-modules-regexp "^1.0.0" -pkg-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" - dependencies: - find-up "^1.0.0" - pkg-dir@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" dependencies: find-up "^2.1.0" plist@2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/plist/-/plist-2.0.1.tgz#0a32ca9481b1c364e92e18dc55c876de9d01da8b" - integrity sha1-CjLKlIGxw2TpLhjcVch23p0B2os= + resolved "https://registry.npmjs.org/plist/-/plist-2.0.1.tgz#0a32ca9481b1c364e92e18dc55c876de9d01da8b" dependencies: base64-js "1.1.2" xmlbuilder "8.2.2" @@ -5625,8 +5331,7 @@ plist@2.0.1: plist@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/plist/-/plist-1.2.0.tgz#084b5093ddc92506e259f874b8d9b1afb8c79593" - integrity sha1-CEtQk93JJQbiWfh0uNmxr7jHlZM= + resolved "https://registry.npmjs.org/plist/-/plist-1.2.0.tgz#084b5093ddc92506e259f874b8d9b1afb8c79593" dependencies: base64-js "0.0.8" util-deprecate "1.0.2" @@ -5635,8 +5340,7 @@ plist@^1.2.0: plugin-error@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" - integrity sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4= + resolved "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" dependencies: ansi-cyan "^0.1.1" ansi-red "^0.1.1" @@ -5646,8 +5350,7 @@ plugin-error@^0.1.2: pluralize@^7.0.0: version "7.0.0" - resolved "http://registry.npm.taobao.org/pluralize/download/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" - integrity sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c= + resolved "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" pn@^1.1.0: version "1.1.0" @@ -6227,7 +5930,7 @@ resolve@1.1.7: version "1.1.7" resolved "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" -resolve@^1.1.6, resolve@^1.3.2, resolve@^1.5.0, resolve@^1.6.0: +resolve@^1.1.6, resolve@^1.6.0: version "1.8.1" resolved "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" dependencies: @@ -6797,12 +6500,7 @@ time-stamp@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" -time-stamp@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" - integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= - -timed-out@^4.0.0, timed-out@^4.0.1: +timed-out@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" @@ -7308,36 +7006,7 @@ xpipe@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/xpipe/-/xpipe-1.0.5.tgz#8dd8bf45fc3f7f55f0e054b878f43a62614dafdf" -xmlbuilder@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.0.0.tgz#98b8f651ca30aa624036f127d11cc66dc7b907a3" - integrity sha1-mLj2UcowqmJANvEn0RzGbce5B6M= - dependencies: - lodash "^3.5.0" - -xmlbuilder@8.2.2: - version "8.2.2" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773" - integrity sha1-aSSGc0ELS6QuGmE2VR0pIjNap3M= - -xmldoc@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/xmldoc/-/xmldoc-0.4.0.tgz#d257224be8393eaacbf837ef227fd8ec25b36888" - integrity sha1-0lciS+g5PqrL+DfvIn/Y7CWzaIg= - dependencies: - sax "~1.1.1" - -xmldom@0.1.x: - version "0.1.27" - resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" - integrity sha1-1QH5ezvbQDr4757MIFcxh6rawOk= - -xpipe@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/xpipe/-/xpipe-1.0.5.tgz#8dd8bf45fc3f7f55f0e054b878f43a62614dafdf" - integrity sha1-jdi/Rfw/f1Xw4FS4ePQ6YmFNr98= - -xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: +xtend@~4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" From b8a6a09971550fb6d4589b6aaa0663a953b500b5 Mon Sep 17 00:00:00 2001 From: Alan Zhang Date: Thu, 3 Jan 2019 15:41:34 +0800 Subject: [PATCH 033/103] =?UTF-8?q?fix(doctor):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=20typescript=20=E5=90=8E=E5=87=BA=E7=8E=B0?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/bin/taro-doctor | 1 - packages/taro-cli/src/doctor/index.ts | 13 +++++++++---- packages/taro-cli/src/doctor/validatorEslintrc.ts | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/taro-cli/bin/taro-doctor b/packages/taro-cli/bin/taro-doctor index c8df1543db30..9c64060453a0 100755 --- a/packages/taro-cli/bin/taro-doctor +++ b/packages/taro-cli/bin/taro-doctor @@ -7,7 +7,6 @@ const ora = require('ora') const chalk = require('chalk') const fs = require('fs-extra') const { PROJECT_CONFIG } = require('../dist/util/constants') - const PROJECT_CONF_PATH = path.join(process.cwd(), PROJECT_CONFIG) if (!fs.existsSync(PROJECT_CONF_PATH)) { diff --git a/packages/taro-cli/src/doctor/index.ts b/packages/taro-cli/src/doctor/index.ts index 3dec316e1010..59247fdfa2a3 100644 --- a/packages/taro-cli/src/doctor/index.ts +++ b/packages/taro-cli/src/doctor/index.ts @@ -1,8 +1,13 @@ +import configValidator from './configValidator'; +import packageValidator from './packageValidator'; +import recommandValidator from './recommandValidator'; +import eslintValidator from './eslintValidator'; + export default { validators: [ - require('./configValidator'), - require('./packageValidator'), - require('./recommandValidator'), - require('./eslintValidator') + configValidator, + packageValidator, + recommandValidator, + eslintValidator ] } diff --git a/packages/taro-cli/src/doctor/validatorEslintrc.ts b/packages/taro-cli/src/doctor/validatorEslintrc.ts index 4e168dbb2596..521a005d3929 100644 --- a/packages/taro-cli/src/doctor/validatorEslintrc.ts +++ b/packages/taro-cli/src/doctor/validatorEslintrc.ts @@ -1,4 +1,4 @@ -export default { +module.exports = { 'extends': ['taro'], 'rules': { 'no-unused-vars': ['error', { 'varsIgnorePattern': 'Taro' }], From 140e8cec8795b84a7ea0984a2f467b1a3ec8ff95 Mon Sep 17 00:00:00 2001 From: yuche Date: Wed, 23 Jan 2019 11:15:34 +0800 Subject: [PATCH 034/103] =?UTF-8?q?fix(transformer):=20=20=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E7=94=9F=E6=88=90=E5=87=BD=E6=95=B0=E5=BC=8F=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=20Squashed=20commits:=20[5404695b]=20chore(transforme?= =?UTF-8?q?r):=20fix=20typo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/src/rn/transformJS.ts | 6 +- packages/taro-transformer-wx/src/options.ts | 2 + packages/taro-transformer-wx/src/render.ts | 70 +++++++++------------ 3 files changed, 34 insertions(+), 44 deletions(-) diff --git a/packages/taro-cli/src/rn/transformJS.ts b/packages/taro-cli/src/rn/transformJS.ts index 370984917365..004ab5083a8e 100644 --- a/packages/taro-cli/src/rn/transformJS.ts +++ b/packages/taro-cli/src/rn/transformJS.ts @@ -77,8 +77,10 @@ function getClassPropertyVisitor ({filePath, pages, iconPaths, isEntryFile}) { root = rootNode ? rootNode.value.value : '' value.elements.forEach(v => { - const pagePath = `${root}/${(v as t.StringLiteral).value}`.replace(/\/{2,}/g, '/') - pages.push(pagePath.replace(/^\//, '')) + if (t.isStringLiteral(v)) { + const pagePath = `${root}/${v.value}`.replace(/\/{2,}/g, '/') + pages.push(pagePath.replace(/^\//, '')) + } }) astPath.remove() } diff --git a/packages/taro-transformer-wx/src/options.ts b/packages/taro-transformer-wx/src/options.ts index f8aa10c1b427..729b812c0484 100644 --- a/packages/taro-transformer-wx/src/options.ts +++ b/packages/taro-transformer-wx/src/options.ts @@ -1,6 +1,7 @@ import { Adapters } from './adapter' import { eslintValidation } from './eslint' import { TransformOptions } from 'babel-core' +import { functionalComponent } from './functional' export interface Options { isRoot?: boolean, @@ -44,6 +45,7 @@ export const buildBabelTransformOptions: () => TransformOptions = () => { }, plugins: [ require('babel-plugin-transform-flow-strip-types'), + functionalComponent, [require('babel-plugin-transform-define').default, transformOptions.env] ].concat(process.env.ESLINT === 'false' || transformOptions.isNormal || transformOptions.isTyped ? [] : eslintValidation) .concat((process.env.NODE_ENV === 'test') ? [] : require('babel-plugin-remove-dead-code').default) diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts index e9ffae8d8392..d4049aa29433 100644 --- a/packages/taro-transformer-wx/src/render.ts +++ b/packages/taro-transformer-wx/src/render.ts @@ -116,7 +116,6 @@ export class RenderParser { private isDefaultRender: boolean = false // private renderArg: t.Identifier | t.ObjectPattern | null = null private renderMethodName: string = '' - private renderArg: t.Identifier | t.ObjectPattern | null = null private renderPath: NodePath private methods: ClassMethodsMap @@ -1178,13 +1177,6 @@ export class RenderParser { throw codeFrameError(this.renderPath.node, '类函数对象必须指明函数名') } - if (t.isIdentifier(this.renderPath.node.key)) { - this.renderMethodName = this.renderPath.node.key.name - this.renderPath.node.key.name = this.getCreateJSXMethodName(this.renderMethodName) - } else { - throw codeFrameError(this.renderPath.node, '类函数对象必须指明函数名') - } - this.setOutputTemplate() this.checkDuplicateName() this.removeJSXStatement() @@ -1703,46 +1695,40 @@ export class RenderParser { ) } else { const usedState = Array.from(this.usedThisState).map(s => t.objectProperty(t.identifier(s), t.memberExpression(t.thisExpression(), t.identifier(s)))) - if (this.renderArg) { - if (t.isIdentifier(this.renderArg)) { - const renderArgName = this.renderArg.name - const shadowArgName = this.renderPath.scope.generateUid(renderArgName) - const renderBody = this.renderPath.get('body') - renderBody.traverse({ - Scope ({ scope }) { - scope.rename(renderArgName, shadowArgName) - } - }) - this.renderPath.node.body.body.unshift( - t.expressionStatement(t.assignmentExpression('=', t.identifier(renderArgName), t.objectExpression([ - t.objectProperty( - t.identifier(shadowArgName), - t.identifier(shadowArgName) - ) - ]))) - ) - usedState.push(t.objectProperty( - t.identifier(shadowArgName), - t.identifier(shadowArgName) - )) - } else { - // TODO - // usedState.push() - } - } + // if (this.renderArg) { + // if (t.isIdentifier(this.renderArg)) { + // const renderArgName = this.renderArg.name + // const shadowArgName = this.renderPath.scope.generateUid(renderArgName) + // const renderBody = this.renderPath.get('body') + // renderBody.traverse({ + // Scope ({ scope }) { + // scope.rename(renderArgName, shadowArgName) + // } + // }) + // this.renderPath.node.body.body.unshift( + // t.expressionStatement(t.assignmentExpression('=', t.identifier(renderArgName), t.objectExpression([ + // t.objectProperty( + // t.identifier(shadowArgName), + // t.identifier(shadowArgName) + // ) + // ]))) + // ) + // usedState.push(t.objectProperty( + // t.identifier(shadowArgName), + // t.identifier(shadowArgName) + // )) + // } else { + // // TODO + // // usedState.push() + // } + // } this.renderPath.node.body.body.push( t.returnStatement(t.objectExpression(pendingState.properties.concat(usedState))) ) - - if (t.isIdentifier(this.renderPath.node.key)) { - this.renderPath.node.key.name = this.getCreateJSXMethodName(name) - } else { - throw codeFrameError(this.renderPath.node, '类函数对象必须指明函数名') - } } } - getCreateJSXMethodName = (name: string) => `_create${name}Data` + getCreateJSXMethodName = (name: string) => `_create${name.slice(6)}Data` createData () { if (!this.isDefaultRender) { From 01cbd2eff2243186733513d708c06cead4f35518 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Mon, 18 Feb 2019 22:11:55 +0800 Subject: [PATCH 035/103] =?UTF-8?q?feat(taro):=20tabbar=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20custom=20=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro/types/index.d.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/taro/types/index.d.ts b/packages/taro/types/index.d.ts index 7d1fbc755e6d..78ca4c0b3e1c 100644 --- a/packages/taro/types/index.d.ts +++ b/packages/taro/types/index.d.ts @@ -195,7 +195,15 @@ declare namespace Taro { */ position?: 'bottom' | 'top', - list: TarbarList[] + list: TarbarList[], + + /** + * 自定义 tabBar + * @see https://developers.weixin.qq.com/miniprogram/dev/framework/ability/custom-tabbar.html?search-key=%E8%87%AA%E5%AE%9A%E4%B9%89%20tabbar + * @default false + * @since 2.5.0 + */ + custom?: boolean } interface NetworkTimeout { @@ -972,7 +980,7 @@ declare namespace Taro { namespace connectSocket { type Promised = SocketTask; - + type Param = { /** * 开发者服务器接口地址,必须是 wss 协议,且域名必须是后台配置的合法域名 From 0300df47e02fe0f4c026c479f58a6631092b6f6e Mon Sep 17 00:00:00 2001 From: luckyadam Date: Mon, 18 Feb 2019 22:12:24 +0800 Subject: [PATCH 036/103] =?UTF-8?q?chore:=20=E5=90=8C=E6=AD=A5=E4=B8=BB?= =?UTF-8?q?=E5=B9=B2=E7=9A=84=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/src/mini/index.ts | 32 ++++++++++++++-------------- packages/taro-cli/src/quick/index.ts | 3 --- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/packages/taro-cli/src/mini/index.ts b/packages/taro-cli/src/mini/index.ts index af15e4b335ad..e36e38d94312 100644 --- a/packages/taro-cli/src/mini/index.ts +++ b/packages/taro-cli/src/mini/index.ts @@ -27,21 +27,21 @@ import { watchFiles } from './watch' const appPath = process.cwd() -async function checkCliAndFrameworkVersion () { - const { buildAdapter, nodeModulesPath } = getBuildData() - const frameworkName = `@tarojs/taro-${buildAdapter}` - const frameworkVersion = getInstalledNpmPkgVersion(frameworkName, nodeModulesPath) - if (frameworkVersion) { - if (frameworkVersion !== getPkgVersion()) { - printLog(processTypeEnum.ERROR, '版本问题', `Taro CLI 与本地安装的小程序框架 ${frameworkName} 版本不一致,请确保一致`) - console.log(`Taro CLI: ${getPkgVersion()}`) - console.log(`${frameworkName}: ${frameworkVersion}`) - process.exit(1) - } - } else { - printLog(processTypeEnum.WARNING, '依赖安装', chalk.red(`项目依赖 ${frameworkName} 未安装,或安装有误!`)) - } -} +// async function checkCliAndFrameworkVersion () { +// const { buildAdapter, nodeModulesPath } = getBuildData() +// const frameworkName = `@tarojs/taro-${buildAdapter}` +// const frameworkVersion = getInstalledNpmPkgVersion(frameworkName, nodeModulesPath) +// if (frameworkVersion) { +// if (frameworkVersion !== getPkgVersion()) { +// printLog(processTypeEnum.ERROR, '版本问题', `Taro CLI 与本地安装的小程序框架 ${frameworkName} 版本不一致,请确保一致`) +// console.log(`Taro CLI: ${getPkgVersion()}`) +// console.log(`${frameworkName}: ${frameworkVersion}`) +// process.exit(1) +// } +// } else { +// printLog(processTypeEnum.WARNING, '依赖安装', chalk.red(`项目依赖 ${frameworkName} 未安装,或安装有误!`)) +// } +// } function buildProjectConfig () { const { buildAdapter, sourceDir, outputDir, outputDirName } = getBuildData() @@ -138,7 +138,7 @@ export async function build ({ watch, adapter = BUILD_TYPES.WEAPP }: IMiniAppBui process.env.TARO_ENV = adapter setIsProduction(process.env.NODE_ENV === 'production' || !watch) setBuildAdapter(adapter) - await checkCliAndFrameworkVersion() + // await checkCliAndFrameworkVersion() buildProjectConfig() await buildFrameworkInfo() copyFiles() diff --git a/packages/taro-cli/src/quick/index.ts b/packages/taro-cli/src/quick/index.ts index 8012553029c2..43480c41db32 100644 --- a/packages/taro-cli/src/quick/index.ts +++ b/packages/taro-cli/src/quick/index.ts @@ -1,5 +1,2 @@ -import * as fs from 'fs-extra' -import * as path from 'path' - export async function build ({ watch }) { } From 6512415a2a6c3df44c9357a0e6700b9692ae8fb9 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Wed, 20 Feb 2019 11:06:30 +0800 Subject: [PATCH 037/103] =?UTF-8?q?fix(cli):=20=E4=BF=AE=E5=A4=8D=20pretti?= =?UTF-8?q?er=20=E5=8F=82=E6=95=B0=E7=B1=BB=E5=9E=8B=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/package.json | 2 +- packages/taro-cli/src/util/types.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/taro-cli/package.json b/packages/taro-cli/package.json index ff14d93e8e70..a641b767d69e 100644 --- a/packages/taro-cli/package.json +++ b/packages/taro-cli/package.json @@ -82,7 +82,7 @@ "postcss-pxtransform": "1.2.13", "postcss-taro-unit-transform": "1.2.13", "postcss-url": "^7.3.2", - "prettier": "^1.15.3", + "prettier": "^1.16.4", "prop-types": "^15.6.2", "resolve": "^1.6.0", "semver": "^5.5.0", diff --git a/packages/taro-cli/src/util/types.ts b/packages/taro-cli/src/util/types.ts index 08cd658b4541..f59429dcd2c1 100644 --- a/packages/taro-cli/src/util/types.ts +++ b/packages/taro-cli/src/util/types.ts @@ -35,7 +35,7 @@ export interface IPrettierConfig { arrowParens?: 'avoid' | 'always', rangeStart?: number, rangeEnd?: number, - parser?: 'babylon' | 'flow' | 'typescript' | 'css' | 'scss' | 'less' | 'json' | 'json5' | 'json-stringify' | 'graphql' | 'markdown' | 'mdx' | 'html' | 'vue' | 'angular' | 'yaml', + parser?: 'babel' | 'babylon' | 'flow' | 'typescript' | 'css' | 'scss' | 'less' | 'json' | 'json5' | 'json-stringify' | 'graphql' | 'markdown' | 'mdx' | 'html' | 'vue' | 'angular' | 'yaml', filepath?: string, requirePragma?: boolean, insertPragma?: boolean, From f52596112fc2635816bf2a547046e87176ba3810 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Mon, 25 Feb 2019 17:19:25 +0800 Subject: [PATCH 038/103] =?UTF-8?q?fix(cli):=20=E5=B0=8F=E7=A8=8B=E5=BA=8F?= =?UTF-8?q?=20&&=20=E5=BF=AB=E5=BA=94=E7=94=A8=E7=BC=96=E8=AF=91=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/src/build.ts | 5 +- packages/taro-cli/src/h5.ts | 48 +---- packages/taro-cli/src/mini/astProcess.ts | 49 +---- packages/taro-cli/src/mini/compileScript.ts | 9 +- packages/taro-cli/src/mini/component.ts | 6 +- packages/taro-cli/src/mini/constants.ts | 3 - packages/taro-cli/src/mini/copy.ts | 20 -- packages/taro-cli/src/mini/helper.ts | 6 +- packages/taro-cli/src/mini/index.ts | 44 +---- packages/taro-cli/src/mini/interface.ts | 4 - packages/taro-cli/src/mini/native.ts | 3 +- packages/taro-cli/src/mini/page.ts | 9 +- packages/taro-cli/src/mini/watch.ts | 5 +- packages/taro-cli/src/quick/astProcess.ts | 176 ++++++++++++++++++ packages/taro-cli/src/quick/constants.ts | 6 + packages/taro-cli/src/quick/entry.ts | 47 +++++ packages/taro-cli/src/quick/helper.ts | 105 +++++++++++ packages/taro-cli/src/quick/index.ts | 22 ++- packages/taro-cli/src/quick/interface.ts | 146 +-------------- packages/taro-cli/src/util/constants.ts | 19 ++ packages/taro-cli/src/util/index.ts | 96 +++++++++- .../taro-cli/src/{mini => util}/npmExact.ts | 10 +- packages/taro-cli/src/util/types.ts | 166 ++++++++++++++++- 23 files changed, 679 insertions(+), 325 deletions(-) delete mode 100644 packages/taro-cli/src/mini/copy.ts create mode 100644 packages/taro-cli/src/quick/astProcess.ts create mode 100644 packages/taro-cli/src/quick/constants.ts create mode 100644 packages/taro-cli/src/quick/helper.ts rename packages/taro-cli/src/{mini => util}/npmExact.ts (88%) diff --git a/packages/taro-cli/src/build.ts b/packages/taro-cli/src/build.ts index 21d7727e72e8..746afabad25b 100644 --- a/packages/taro-cli/src/build.ts +++ b/packages/taro-cli/src/build.ts @@ -88,7 +88,10 @@ function buildForRN ({ watch }: IBuildConfig) { } function buildForQuickApp ({ watch }: IBuildConfig) { - require('./quick').build({ watch }) + require('./quick').build({ + watch, + adapter: BUILD_TYPES.QUICKAPP + }) } function buildForUILibrary ({ watch }: IBuildConfig) { diff --git a/packages/taro-cli/src/h5.ts b/packages/taro-cli/src/h5.ts index fd9ad58343f3..74e809c42085 100644 --- a/packages/taro-cli/src/h5.ts +++ b/packages/taro-cli/src/h5.ts @@ -11,7 +11,6 @@ import generate from 'better-babel-generator' import * as _ from 'lodash' import * as rimraf from 'rimraf' import { promisify } from 'util' -import minimatch from 'minimatch' import * as Util from './util' import * as npmProcess from './util/npm' @@ -24,7 +23,6 @@ import { processTypeEnum, BUILD_TYPES } from './util/constants' -import { ICopyOptions } from './mini/interface' const appPath = process.cwd() const projectConfig = require(path.join(appPath, PROJECT_CONFIG))(_.merge) @@ -930,54 +928,10 @@ async function clean () { } } -function copyFileSync (from, to, options) { - const filename = path.basename(from) - if (fs.statSync(from).isFile() && !path.extname(to)) { - fs.ensureDir(to) - return fs.copySync(from, path.join(to, filename), options) - } - fs.ensureDir(path.dirname(to)) - return fs.copySync(from, to, options) -} - -function copyFiles () { - const copyConfig = projectConfig.copy || { patterns: [], options: {} } - if (copyConfig.patterns && copyConfig.patterns.length) { - copyConfig.options = copyConfig.options || {} - const globalIgnore = copyConfig.options.ignore - const projectDir = appPath - copyConfig.patterns.forEach(pattern => { - if (typeof pattern === 'object' && pattern.from && pattern.to) { - const from = path.join(projectDir, pattern.from) - const to = path.join(projectDir, pattern.to) - let ignore = pattern.ignore || globalIgnore - if (fs.existsSync(from)) { - const copyOptions: ICopyOptions = {} - if (ignore) { - ignore = Array.isArray(ignore) ? ignore : [ignore] - copyOptions.filter = src => { - let isMatch = false - ignore.forEach(iPa => { - if (minimatch(path.basename(src), iPa)) { - isMatch = true - } - }) - return !isMatch - } - } - copyFileSync(from, to, copyOptions) - } else { - Util.printLog(processTypeEnum.ERROR, '拷贝失败', `${pattern.from} 文件不存在!`) - } - } - }) - } -} - export async function build (buildConfig) { process.env.TARO_ENV = BUILD_TYPES.H5 await clean() - copyFiles() + Util.copyFiles(appPath, projectConfig.copy) await buildTemp() await buildDist(buildConfig) if (buildConfig.watch) { diff --git a/packages/taro-cli/src/mini/astProcess.ts b/packages/taro-cli/src/mini/astProcess.ts index e45a7ba5235f..253a34b760ef 100644 --- a/packages/taro-cli/src/mini/astProcess.ts +++ b/packages/taro-cli/src/mini/astProcess.ts @@ -11,7 +11,6 @@ import { Config as IConfig } from '@tarojs/taro' const template = require('babel-template') import { - CONFIG_MAP, REG_SCRIPT, REG_TYPESCRIPT, REG_JSON, @@ -21,7 +20,8 @@ import { REG_STYLE, CSS_EXT, processTypeEnum, - BUILD_TYPES + BUILD_TYPES, + NODE_MODULES_REG } from '../util/constants' import { resolveScriptPath, @@ -29,13 +29,14 @@ import { promoteRelativePath, isNpmPkg, isAliasPath, - replaceAliasPath + replaceAliasPath, + traverseObjectNode } from '../util' import { convertObjectToAstExpression, convertArrayToAstExpression } from '../util/astConvert' import babylonConfig from '../config/babylon' +import { getExactedNpmFilePath, getNotExistNpmList } from '../util/npmExact' import { - NODE_MODULES_REG, PARSE_AST_TYPE, taroJsComponents, taroJsRedux, @@ -43,48 +44,12 @@ import { DEVICE_RATIO_NAME } from './constants' import { IComponentObj } from './interface' -import { getExactedNpmFilePath, getNotExistNpmList } from './npmExact' import { getBuildData, isFileToBePage } from './helper' import { processStyleUseCssModule } from './compileStyle' -function traverseObjectNode (node) { - const { buildAdapter } = getBuildData() - if (node.type === 'ClassProperty' || node.type === 'ObjectProperty') { - const properties = node.value.properties - const obj = {} - properties.forEach(p => { - let key = t.isIdentifier(p.key) ? p.key.name : p.key.value - if (CONFIG_MAP[buildAdapter][key]) { - key = CONFIG_MAP[buildAdapter][key] - } - obj[key] = traverseObjectNode(p.value) - }) - return obj - } - if (node.type === 'ObjectExpression') { - const properties = node.properties - const obj= {} - properties.forEach(p => { - let key = t.isIdentifier(p.key) ? p.key.name : p.key.value - if (CONFIG_MAP[buildAdapter][key]) { - key = CONFIG_MAP[buildAdapter][key] - } - obj[key] = traverseObjectNode(p.value) - }) - return obj - } - if (node.type === 'ArrayExpression') { - return node.elements.map(item => traverseObjectNode(item)) - } - if (node.type === 'NullLiteral') { - return null - } - return node.value -} - interface IAnalyzeImportUrlOptions { astPath: any, value: string, @@ -299,7 +264,7 @@ export function parseAst ( left.object.type === 'ThisExpression' && left.property.type === 'Identifier' && left.property.name === 'config') { - configObj = traverseObjectNode(node.expression.right) + configObj = traverseObjectNode(node.expression.right, buildAdapter) } } } @@ -382,7 +347,7 @@ export function parseAst ( ClassProperty (astPath) { const node = astPath.node if (node.key.name === 'config') { - configObj = traverseObjectNode(node) + configObj = traverseObjectNode(node, buildAdapter) } }, diff --git a/packages/taro-cli/src/mini/compileScript.ts b/packages/taro-cli/src/mini/compileScript.ts index 975c5cbcc42b..9771bdc4b302 100644 --- a/packages/taro-cli/src/mini/compileScript.ts +++ b/packages/taro-cli/src/mini/compileScript.ts @@ -5,12 +5,14 @@ import * as wxTransformer from '@tarojs/transformer-wx' import { printLog, - isDifferentArray + isDifferentArray, + copyFileSync } from '../util' import { BUILD_TYPES, processTypeEnum, - REG_TYPESCRIPT + REG_TYPESCRIPT, + NODE_MODULES_REG } from '../util/constants' import { callPlugin } from '../util/npm' import { IWxTransformResult } from '../util/types' @@ -24,8 +26,7 @@ import { uglifyJS } from './helper' import { parseAst } from './astProcess' -import { PARSE_AST_TYPE, NODE_MODULES_REG } from './constants' -import { copyFileSync } from './copy' +import { PARSE_AST_TYPE } from './constants' import { IDependency } from './interface' const isBuildingScripts: Map = new Map() diff --git a/packages/taro-cli/src/mini/component.ts b/packages/taro-cli/src/mini/component.ts index 451990d1c265..cd32bd622d3a 100644 --- a/packages/taro-cli/src/mini/component.ts +++ b/packages/taro-cli/src/mini/component.ts @@ -9,7 +9,9 @@ import traverse from 'babel-traverse' import { IWxTransformResult } from '../util/types' import { REG_TYPESCRIPT, - processTypeEnum + processTypeEnum, + NODE_MODULES_REG, + NODE_MODULES } from '../util/constants' import { printLog, @@ -37,7 +39,7 @@ import { import { compileScriptFile, compileDepScripts } from './compileScript' import { compileDepStyles } from './compileStyle' import { transfromNativeComponents, processNativeWxml } from './native' -import { PARSE_AST_TYPE, NODE_MODULES_REG, NODE_MODULES } from './constants' +import { PARSE_AST_TYPE } from './constants' const notTaroComponents = new Set() const componentsNamedMap = new Map() diff --git a/packages/taro-cli/src/mini/constants.ts b/packages/taro-cli/src/mini/constants.ts index 13c44e0d256d..d0f91d80ad25 100644 --- a/packages/taro-cli/src/mini/constants.ts +++ b/packages/taro-cli/src/mini/constants.ts @@ -4,9 +4,6 @@ export const taroJsFramework = '@tarojs/taro' export const taroJsComponents = '@tarojs/components' export const taroJsRedux = '@tarojs/redux' -export const NODE_MODULES = 'node_modules' -export const NODE_MODULES_REG = /(.*)node_modules/ - export enum PARSE_AST_TYPE { ENTRY = 'ENTRY', PAGE = 'PAGE', diff --git a/packages/taro-cli/src/mini/copy.ts b/packages/taro-cli/src/mini/copy.ts deleted file mode 100644 index 4458c810f76e..000000000000 --- a/packages/taro-cli/src/mini/copy.ts +++ /dev/null @@ -1,20 +0,0 @@ -import * as fs from 'fs-extra' -import * as path from 'path' - -import { ICopyOptions } from './interface' - -export function copyFileSync (from: string, to: string, options?: ICopyOptions) { - const filename = path.basename(from) - if (fs.statSync(from).isFile() && !path.extname(to)) { - fs.ensureDir(to) - if (from === path.join(to, filename)) { - return - } - return fs.copySync(from, path.join(to, filename), options) - } - if (from === to) { - return - } - fs.ensureDir(path.dirname(to)) - return fs.copySync(from, to, options) -} diff --git a/packages/taro-cli/src/mini/helper.ts b/packages/taro-cli/src/mini/helper.ts index 67311c362048..285e862da73b 100644 --- a/packages/taro-cli/src/mini/helper.ts +++ b/packages/taro-cli/src/mini/helper.ts @@ -10,7 +10,8 @@ import { IMINI_APP_FILE_TYPE, PROJECT_CONFIG, processTypeEnum, - REG_SCRIPTS + REG_SCRIPTS, + NODE_MODULES_REG } from '../util/constants' import { resolveScriptPath, @@ -39,8 +40,7 @@ import { IBuildResult, IDependency } from './interface' -import { NODE_MODULES_REG } from './constants' -import { getNodeModulesPath, getNpmOutputDir } from './npmExact' +import { getNodeModulesPath, getNpmOutputDir } from '../util/npmExact' const appPath = process.cwd() const configDir = path.join(appPath, PROJECT_CONFIG) diff --git a/packages/taro-cli/src/mini/index.ts b/packages/taro-cli/src/mini/index.ts index e36e38d94312..c95dd922cc5d 100644 --- a/packages/taro-cli/src/mini/index.ts +++ b/packages/taro-cli/src/mini/index.ts @@ -2,13 +2,13 @@ import * as fs from 'fs-extra' import * as path from 'path' import chalk from 'chalk' -import * as minimatch from 'minimatch' import * as _ from 'lodash' import { printLog, getInstalledNpmPkgVersion, - getPkgVersion + getPkgVersion, + copyFiles } from '../util' import { processTypeEnum, BUILD_TYPES } from '../util/constants' import { IMiniAppBuildConfig } from '../util/types' @@ -19,8 +19,6 @@ import { setBuildAdapter, setAppConfig } from './helper' -import { ICopyOptions } from './interface' -import { copyFileSync } from './copy' import { buildEntry } from './entry' import { buildPages } from './page' import { watchFiles } from './watch' @@ -99,49 +97,15 @@ async function buildFrameworkInfo () { } } -function copyFiles () { - const { projectConfig } = getBuildData() - const copyConfig = projectConfig.copy || { patterns: [], options: {} } - if (copyConfig.patterns && copyConfig.patterns.length) { - copyConfig.options = copyConfig.options || {} - const globalIgnore = copyConfig.options.ignore - const projectDir = appPath - copyConfig.patterns.forEach(pattern => { - if (typeof pattern === 'object' && pattern.from && pattern.to) { - const from = path.join(projectDir, pattern.from) - const to = path.join(projectDir, pattern.to) - let ignore = pattern.ignore || globalIgnore - if (fs.existsSync(from)) { - const copyOptions: ICopyOptions = {} - if (ignore) { - ignore = Array.isArray(ignore) ? ignore : [ignore] - copyOptions.filter = src => { - let isMatch = false - ignore && ignore.forEach(iPa => { - if (minimatch(path.basename(src), iPa)) { - isMatch = true - } - }) - return !isMatch - } - } - copyFileSync(from, to, copyOptions) - } else { - printLog(processTypeEnum.ERROR, '拷贝失败', `${pattern.from} 文件不存在!`) - } - } - }) - } -} - export async function build ({ watch, adapter = BUILD_TYPES.WEAPP }: IMiniAppBuildConfig) { + const { projectConfig } = getBuildData() process.env.TARO_ENV = adapter setIsProduction(process.env.NODE_ENV === 'production' || !watch) setBuildAdapter(adapter) // await checkCliAndFrameworkVersion() buildProjectConfig() await buildFrameworkInfo() - copyFiles() + copyFiles(appPath, projectConfig.copy) const appConfig = await buildEntry() setAppConfig(appConfig) await buildPages() diff --git a/packages/taro-cli/src/mini/interface.ts b/packages/taro-cli/src/mini/interface.ts index 92fac4df8d16..54d9505bd70d 100644 --- a/packages/taro-cli/src/mini/interface.ts +++ b/packages/taro-cli/src/mini/interface.ts @@ -23,7 +23,3 @@ export interface IDependency { json: string[], media: string[] } - -export interface ICopyOptions { - filter?: (src: string) => boolean -} diff --git a/packages/taro-cli/src/mini/native.ts b/packages/taro-cli/src/mini/native.ts index 1cdf243d5a14..42305af74ced 100644 --- a/packages/taro-cli/src/mini/native.ts +++ b/packages/taro-cli/src/mini/native.ts @@ -5,9 +5,8 @@ import { Config as IConfig } from '@tarojs/taro' import chalk from 'chalk' import { REG_WXML_IMPORT, processTypeEnum } from '../util/constants' -import { isEmptyObject, printLog, resolveScriptPath } from '../util' +import { isEmptyObject, printLog, resolveScriptPath, copyFileSync } from '../util' -import { copyFileSync } from './copy' import { buildDepComponents } from './component' import { taroJsFramework } from './constants' import { compileDepScripts } from './compileScript' diff --git a/packages/taro-cli/src/mini/page.ts b/packages/taro-cli/src/mini/page.ts index d912dbbf5fc3..56dc49613cff 100644 --- a/packages/taro-cli/src/mini/page.ts +++ b/packages/taro-cli/src/mini/page.ts @@ -7,20 +7,21 @@ import * as _ from 'lodash' import { REG_TYPESCRIPT, - processTypeEnum + processTypeEnum, + NODE_MODULES_REG } from '../util/constants' import { resolveScriptPath, printLog, isEmptyObject, promoteRelativePath, - isDifferentArray + isDifferentArray, + copyFileSync } from '../util' import { IWxTransformResult } from '../util/types' import { IComponentObj } from './interface' -import { PARSE_AST_TYPE, NODE_MODULES_REG, taroJsFramework } from './constants' -import { copyFileSync } from './copy' +import { PARSE_AST_TYPE, taroJsFramework } from './constants' import { getBuildData, getRealComponentsPathList, diff --git a/packages/taro-cli/src/mini/watch.ts b/packages/taro-cli/src/mini/watch.ts index ef6feba9d5fb..dc4c73ce81d3 100644 --- a/packages/taro-cli/src/mini/watch.ts +++ b/packages/taro-cli/src/mini/watch.ts @@ -7,7 +7,8 @@ import { REG_TYPESCRIPT, REG_SCRIPT, REG_STYLE, - processTypeEnum + processTypeEnum, + NODE_MODULES_REG } from '../util/constants' import { printLog, @@ -29,7 +30,7 @@ import { import { buildEntry } from './entry' import { buildPages, buildSinglePage } from './page' import { buildSingleComponent, getComponentsNamedMap } from './component' -import { isWindows, NODE_MODULES_REG } from './constants' +import { isWindows } from './constants' export function watchFiles () { const appPath = process.cwd() diff --git a/packages/taro-cli/src/quick/astProcess.ts b/packages/taro-cli/src/quick/astProcess.ts new file mode 100644 index 000000000000..6221fadddea2 --- /dev/null +++ b/packages/taro-cli/src/quick/astProcess.ts @@ -0,0 +1,176 @@ +import * as fs from 'fs-extra' +import * as path from 'path' + +import * as babel from 'babel-core' +import * as t from 'babel-types' +import generate from 'babel-generator' +import traverse from 'babel-traverse' +import _ from 'lodash' +import { Config as IConfig } from '@tarojs/taro' + +import { PARSE_AST_TYPE } from './constants' +import { getBuildData } from './helper' +import { getNotExistNpmList } from '../util/npmExact' +import { traverseObjectNode } from '../util' + +export function parseAst ( + type: PARSE_AST_TYPE, + ast: t.File, + sourceFilePath: string, + filePath: string, + npmSkip: boolean = false +) { + const styleFiles: string[] = [] + const scriptFiles: string[] = [] + const jsonFiles: string[] = [] + const mediaFiles: string[] = [] + + const { + nodeModulesPath, + npmOutputDir, + sourceDir, + outputDir, + buildAdapter, + constantsReplaceList, + isProduction, + npmConfig, + alias: pathAlias, + projectConfig + } = getBuildData() + const notExistNpmList = getNotExistNpmList() + const taroMiniAppFramework = `@tarojs/taro-${buildAdapter}` + let needExportDefault = false + let configObj: IConfig = {} + let componentClassName: string = '' + ast = babel.transformFromAst(ast, '', { + plugins: [ + [require('babel-plugin-danger-remove-unused-import'), { ignore: ['@tarojs/taro', 'react', 'nervjs'] }], + [require('babel-plugin-transform-define').default, constantsReplaceList] + ] + }).ast as t.File + traverse(ast, { + ClassDeclaration (astPath) { + const node = astPath.node + let hasCreateData = false + if (astPath.isProperty({ superClass: true })) { + astPath.traverse({ + ClassMethod (astPath) { + if (astPath.get('key').isIdentifier({ name: '_createData' })) { + hasCreateData = true + } + } + }) + if (hasCreateData) { + needExportDefault = true + astPath.traverse({ + ClassMethod (astPath) { + const node = astPath.node + if (node.kind === 'constructor') { + astPath.traverse({ + ExpressionStatement (astPath) { + const node = astPath.node + if (node.expression && + node.expression.type === 'AssignmentExpression' && + node.expression.operator === '=') { + const left = node.expression.left + if (left.type === 'MemberExpression' && + left.object.type === 'ThisExpression' && + left.property.type === 'Identifier' && + left.property.name === 'config') { + configObj = traverseObjectNode(node.expression.right, buildAdapter) + } + } + } + }) + } + } + }) + if (node.id === null) { + componentClassName = '_TaroComponentClass' + astPath.replaceWith( + t.classDeclaration( + t.identifier(componentClassName), + node.superClass as t.Expression, + node.body as t.ClassBody, + node.decorators as t.Decorator[] || [] + ) + ) + } else if (node.id.name === 'App') { + componentClassName = '_App' + astPath.replaceWith( + t.classDeclaration( + t.identifier(componentClassName), + node.superClass as t.Expression, + node.body as t.ClassBody, + node.decorators as t.Decorator[] || [] + ) + ) + } else { + componentClassName = node.id.name + } + } + } + }, + + ClassExpression (astPath) { + const node = astPath.node + if (node.superClass) { + let hasCreateData = false + astPath.traverse({ + ClassMethod (astPath) { + if (astPath.get('key').isIdentifier({ name: '_createData' })) { + hasCreateData = true + } + } + }) + if (hasCreateData) { + needExportDefault = true + if (node.id === null) { + const parentNode = astPath.parentPath.node as any + if (t.isVariableDeclarator(astPath.parentPath)) { + componentClassName = parentNode.id.name + } else { + componentClassName = '_TaroComponentClass' + } + astPath.replaceWith( + t.classExpression( + t.identifier(componentClassName), + node.superClass as t.Expression, + node.body as t.ClassBody, + node.decorators as t.Decorator[] || [] + ) + ) + } else if (node.id.name === 'App') { + componentClassName = '_App' + astPath.replaceWith( + t.classExpression( + t.identifier(componentClassName), + node.superClass as t.Expression, + node.body as t.ClassBody, + node.decorators as t.Decorator[] || [] + ) + ) + } else { + componentClassName = node.id.name + } + } + } + }, + + ClassProperty (astPath) { + const node = astPath.node + if (node.key.name === 'config') { + configObj = traverseObjectNode(node, buildAdapter) + } + } + }) + return { + code: generate(ast).code, + styleFiles, + scriptFiles, + jsonFiles, + configObj, + mediaFiles, + componentClassName + } +} diff --git a/packages/taro-cli/src/quick/constants.ts b/packages/taro-cli/src/quick/constants.ts new file mode 100644 index 000000000000..7feed344bca2 --- /dev/null +++ b/packages/taro-cli/src/quick/constants.ts @@ -0,0 +1,6 @@ +export enum PARSE_AST_TYPE { + ENTRY = 'ENTRY', + PAGE = 'PAGE', + COMPONENT = 'COMPONENT', + NORMAL = 'NORMAL' +} diff --git a/packages/taro-cli/src/quick/entry.ts b/packages/taro-cli/src/quick/entry.ts index e69de29bb2d1..3227bf257d54 100644 --- a/packages/taro-cli/src/quick/entry.ts +++ b/packages/taro-cli/src/quick/entry.ts @@ -0,0 +1,47 @@ +import * as fs from 'fs-extra' +import * as path from 'path' + +import * as wxTransformer from '@tarojs/transformer-wx' + +import { IWxTransformResult } from '../util/types' +import { processTypeEnum, REG_TYPESCRIPT } from '../util/constants' +import { printLog } from '../util' + +import { getBuildData, setAppConfig, getDependencyTree } from './helper' +import { parseAst } from './astProcess' +import { PARSE_AST_TYPE } from './constants' + +export async function buildEntry () { + const { + buildAdapter, + constantsReplaceList, + entryFilePath, + outputDir, + entryFileName, + sourceDirName, + projectConfig + } = getBuildData() + + const quickAppConf = projectConfig.quickApp + const entryFileCode = fs.readFileSync(entryFilePath).toString() + const outputEntryFilePath = path.join(outputDir, entryFileName) + + printLog(processTypeEnum.COMPILE, '入口文件', `${sourceDirName}/${entryFileName}`) + try { + const transformResult: IWxTransformResult = wxTransformer({ + code: entryFileCode, + sourcePath: entryFilePath, + outputPath: outputEntryFilePath, + isApp: true, + isTyped: REG_TYPESCRIPT.test(entryFilePath), + adapter: buildAdapter, + env: constantsReplaceList + }) + const { configObj, code } = parseAst(PARSE_AST_TYPE.ENTRY, transformResult.ast, entryFilePath, outputEntryFilePath) + const dependencyTree = getDependencyTree() + setAppConfig(configObj) + console.log(transformResult.template) + } catch (err) { + console.log(err) + } +} diff --git a/packages/taro-cli/src/quick/helper.ts b/packages/taro-cli/src/quick/helper.ts new file mode 100644 index 000000000000..084ca7f68fbd --- /dev/null +++ b/packages/taro-cli/src/quick/helper.ts @@ -0,0 +1,105 @@ +import * as path from 'path' + +import * as _ from 'lodash' +import { AppConfig } from '@tarojs/taro' + +import { + BUILD_TYPES, + PROJECT_CONFIG +} from '../util/constants' +import CONFIG from '../config' +import { + resolveScriptPath, + generateEnvList, + generateConstantsList +} from '../util' +import { IProjectConfig, INpmConfig, IOption } from '../util/types' +import { getNodeModulesPath, getNpmOutputDir } from '../util/npmExact' +import { IDependency } from './interface' + +const appPath = process.cwd() +const configDir = path.join(appPath, PROJECT_CONFIG) +const projectConfig = require(configDir)(_.merge) +const sourceDirName = projectConfig.sourceRoot || CONFIG.SOURCE_DIR +const outputDirName = projectConfig.outputRoot || CONFIG.OUTPUT_DIR +const sourceDir = path.join(appPath, sourceDirName) +const outputDir = path.join(appPath, outputDirName) +const entryFilePath = resolveScriptPath(path.join(sourceDir, CONFIG.ENTRY)) +const entryFileName = path.basename(entryFilePath) + +const pathAlias = projectConfig.alias || {} +const quickAppConf = projectConfig.quickApp || {} +const npmConfig = Object.assign({ + name: CONFIG.NPM_DIR, + dir: null +}, quickAppConf.npm) + +const minifestJSON = {} +const dependencyTree: Map = new Map() + +export interface IBuildData { + appPath: string, + configDir: string, + sourceDirName: string, + outputDirName: string, + sourceDir: string, + outputDir: string, + entryFilePath: string, + entryFileName: string, + projectConfig: IProjectConfig, + npmConfig: INpmConfig, + appConfig: AppConfig, + alias: IOption, + isProduction: boolean, + buildAdapter: BUILD_TYPES, + constantsReplaceList: IOption, + nodeModulesPath: string, + npmOutputDir: string +} + +const BuildData: IBuildData = { + appPath, + configDir, + sourceDirName, + outputDirName, + sourceDir, + outputDir, + entryFilePath, + entryFileName, + projectConfig, + npmConfig, + alias: pathAlias, + isProduction: false, + appConfig: {}, + buildAdapter: BUILD_TYPES.WEAPP, + constantsReplaceList: {}, + nodeModulesPath: getNodeModulesPath(), + npmOutputDir: getNpmOutputDir(outputDir, configDir, npmConfig) +} + +export function setAppConfig (appConfig: AppConfig) { + BuildData.appConfig = appConfig +} + +export function setIsProduction (isProduction: boolean) { + BuildData.isProduction = isProduction +} + +export function setBuildAdapter (adapter: BUILD_TYPES) { + BuildData.buildAdapter = adapter + BuildData.constantsReplaceList = Object.assign({}, generateEnvList(projectConfig.env || {}), generateConstantsList(projectConfig.defineConstants || {}), { + 'process.env.TARO_ENV': adapter + }) +} + +export function getBuildData (): IBuildData { + return BuildData +} + +export function setManifestJSON (key, value) { + minifestJSON[key] = value +} + +export function getDependencyTree (): Map { + return dependencyTree +} diff --git a/packages/taro-cli/src/quick/index.ts b/packages/taro-cli/src/quick/index.ts index 43480c41db32..69a02a8669eb 100644 --- a/packages/taro-cli/src/quick/index.ts +++ b/packages/taro-cli/src/quick/index.ts @@ -1,2 +1,22 @@ -export async function build ({ watch }) { +import { BUILD_TYPES } from '../util/constants' +import { IMiniAppBuildConfig } from '../util/types' + +import { + getBuildData, + setIsProduction, + setBuildAdapter, + setAppConfig +} from './helper' +import { copyFiles } from '../util' + +import { buildEntry } from './entry' + +export async function build ({ watch, adapter = BUILD_TYPES.QUICKAPP }: IMiniAppBuildConfig) { + const { projectConfig, appPath } = getBuildData() + process.env.TARO_ENV = adapter + setIsProduction(process.env.NODE_ENV === 'production' || !watch) + setBuildAdapter(adapter) + copyFiles(appPath, projectConfig.copy) + const appConfig = await buildEntry() + // setAppConfig(appConfig) } diff --git a/packages/taro-cli/src/quick/interface.ts b/packages/taro-cli/src/quick/interface.ts index 8ddc201f41dc..db83f46215ee 100644 --- a/packages/taro-cli/src/quick/interface.ts +++ b/packages/taro-cli/src/quick/interface.ts @@ -1,142 +1,6 @@ -import { IOption } from '../util/types' - -type FeatureItem = { - name: string -} - -export type SystemConfig = { - /** - * 打印日志等级,分为 off,error,warn,info,log,debug - */ - logLevel?: 'off' | 'error' | 'warn' | 'info' | 'log' | 'debug', - /** - * 页面设计基准宽度,根据实际设备宽度来缩放元素大小 - */ - designWidth?: number, - /** - * 全局数据对象,属性名不能以$或_开头,在页面中可通过 this 进行访问;如果全局数据属性与页面的数据属性重名,则页面初始化时,全局数据会覆盖页面中对应的属性值 - */ - data?: IOption -} - -type RouterConfig = { - /** - * 首页名称 - */ - entry: string, - /** - * 页面配置列表,key 值为页面名称(对应页面目录名,例如 Hello 对应'Hello'目录),value 为页面详细配置 page - */ - pages: RouterPage[] -} -type RouterPage = { - /** - * 页面对应的组件名,与 ux 文件名保持一致,例如'hello' 对应 'hello.ux' - */ - component: string, - /** - * 页面路径,例如“/user”,不填则默认为/<页面名称>。 - * path 必须唯一,不能和其他 page 的 path 相同。 - * 下面 page 的 path 因为缺失,会被设置为“/Index”: - * "Index": {"component": "index"} - */ - path?: string, - /** - * 声明页面可以处理某种请求 - */ - filter: { - [key: string]: { - uri: string - } - } -} - -interface IDefaultDisplayConfig { - /** - * 窗口背景颜色 - */ - backgroundColor?: string, - /** - * 是否是全屏模式,默认不会同时作用于 titleBar,titleBar 需要继续通过 titleBar 控制 - */ - fullScreen?: boolean, - /** - * 是否显示 titleBar - */ - titleBar?: boolean, - /** - * 标题栏背景色 - */ - titleBarBackgroundColor?: string, - /** - * 标题栏文字颜色 - */ - titleBarTextColor?: string, - /** - * 标题栏文字(也可通过页面跳转传递参数(titleBarText)设置) - */ - titleBarText?: string, - /** - * 是否显示标题栏右上角菜单按钮,点击菜单按钮调用页面生命周期 onMenuPress 方法,如果该方法未实现则显示系统默认菜单 - */ - menu?: boolean, - /** - * 软键盘弹出时为保证输入框可见,页面的调整方式。 adjustPan:上移页面; adjustResize:压缩页面显示区域,当页面全屏时,此设置不生效 - */ - windowSoftInputMode?: 'adjustPan' | 'adjustResize' -} - -interface IDisplayConfig extends IDefaultDisplayConfig { - /** - * 各个页面的显示样式,key 为页面名(与路由中的页面名保持一致),value 为窗口显示样式,页面样式覆盖 default 样式 - */ - pages?: { - [key: string]: IDefaultDisplayConfig - } -} - -export interface ITaroManifestConfig { - /** - * 应用包名,确认与原生应用的包名不一致,推荐采用 com.company.module 的格式,如:com.example.demo - */ - package: string, - /** - * 应用名称,6 个汉字以内,与应用商店保存的名称一致,用于在桌面图标、弹窗等处显示应用名称 - */ - name: string, - /** - * 应用图标,提供 192x192 大小的即可 - */ - icon: string, - /** - * 应用版本名称,如:"1.0" - */ - versionName?: string, - /** - * 应用版本号,从1自增,推荐每次重新上传包时versionCode+1 - */ - versionCode: number, - /** - * 支持的最小平台版本号,兼容性检查,避免上线后在低版本平台运行并导致不兼容;如果不填按照内测版本处理 - */ - minPlatformVersion?: string, - /** - * 接口列表,绝大部分接口都需要在这里声明,否则不能调用,详见每个接口的文档说明 - */ - features?: FeatureItem[] -} - -export interface IManifestConfig extends ITaroManifestConfig { - /** - * 系统配置信息 - */ - config: SystemConfig, - /** - * 路由信息 - */ - router: RouterConfig, - /** - * UI 显示相关配置 - */ - display?: IDisplayConfig +export interface IDependency { + style: string[], + script: string[], + json: string[], + media: string[] } diff --git a/packages/taro-cli/src/util/constants.ts b/packages/taro-cli/src/util/constants.ts index b0f3f6f49e6d..e1c37f31a9f5 100644 --- a/packages/taro-cli/src/util/constants.ts +++ b/packages/taro-cli/src/util/constants.ts @@ -86,6 +86,9 @@ export const REG_WXML_IMPORT: RegExp = / { + let key = t.isIdentifier(p.key) ? p.key.name : p.key.value + if (CONFIG_MAP[buildAdapter][key] === false) { + return + } + if (CONFIG_MAP[buildAdapter][key]) { + key = CONFIG_MAP[buildAdapter][key] + } + obj[key] = traverseObjectNode(p.value, buildAdapter) + }) + return obj + } + if (node.type === 'ObjectExpression') { + const properties = node.properties + const obj= {} + properties.forEach(p => { + let key = t.isIdentifier(p.key) ? p.key.name : p.key.value + if (CONFIG_MAP[buildAdapter][key] === false) { + return + } + if (CONFIG_MAP[buildAdapter][key]) { + key = CONFIG_MAP[buildAdapter][key] + } + obj[key] = traverseObjectNode(p.value, buildAdapter) + }) + return obj + } + if (node.type === 'ArrayExpression') { + return node.elements.map(item => traverseObjectNode(item, buildAdapter)) + } + if (node.type === 'NullLiteral') { + return null + } + return node.value +} + +export function copyFileSync (from: string, to: string, options?: ICopyArgOptions) { + const filename = path.basename(from) + if (fs.statSync(from).isFile() && !path.extname(to)) { + fs.ensureDir(to) + if (from === path.join(to, filename)) { + return + } + return fs.copySync(from, path.join(to, filename), options) + } + if (from === to) { + return + } + fs.ensureDir(path.dirname(to)) + return fs.copySync(from, to, options) +} + +export function copyFiles (appPath: string, copyConfig: ICopyOptions | void) { + copyConfig = copyConfig || { patterns: [], options: {} } + if (copyConfig.patterns && copyConfig.patterns.length) { + copyConfig.options = copyConfig.options || {} + const globalIgnore = copyConfig.options.ignore + const projectDir = appPath + copyConfig.patterns.forEach(pattern => { + if (typeof pattern === 'object' && pattern.from && pattern.to) { + const from = path.join(projectDir, pattern.from) + const to = path.join(projectDir, pattern.to) + let ignore = pattern.ignore || globalIgnore + if (fs.existsSync(from)) { + const copyOptions: ICopyArgOptions = {} + if (ignore) { + ignore = Array.isArray(ignore) ? ignore : [ignore] + copyOptions.filter = src => { + let isMatch = false + ignore && ignore.forEach(iPa => { + if (minimatch(path.basename(src), iPa)) { + isMatch = true + } + }) + return !isMatch + } + } + copyFileSync(from, to, copyOptions) + } else { + printLog(processTypeEnum.ERROR, '拷贝失败', `${pattern.from} 文件不存在!`) + } + } + }) + } +} diff --git a/packages/taro-cli/src/mini/npmExact.ts b/packages/taro-cli/src/util/npmExact.ts similarity index 88% rename from packages/taro-cli/src/mini/npmExact.ts rename to packages/taro-cli/src/util/npmExact.ts index 3309c7d7cd5c..29e9f83033bd 100644 --- a/packages/taro-cli/src/mini/npmExact.ts +++ b/packages/taro-cli/src/util/npmExact.ts @@ -1,11 +1,9 @@ import * as path from 'path' -import { resolveNpmFilesPath } from '../util/resolve_npm_files' -import { INpmConfig } from '../util/types' -import { BUILD_TYPES, REG_STYLE } from '../util/constants' -import { promoteRelativePath, recursiveFindNodeModules } from '../util' - -import { NODE_MODULES } from './constants' +import { resolveNpmFilesPath } from './resolve_npm_files' +import { INpmConfig } from './types' +import { BUILD_TYPES, REG_STYLE, NODE_MODULES } from './constants' +import { promoteRelativePath, recursiveFindNodeModules } from './index' interface IArgs { npmName: string, diff --git a/packages/taro-cli/src/util/types.ts b/packages/taro-cli/src/util/types.ts index f59429dcd2c1..07274ea1dcd5 100644 --- a/packages/taro-cli/src/util/types.ts +++ b/packages/taro-cli/src/util/types.ts @@ -69,6 +69,10 @@ export interface ICopyOptions { } } +export interface ICopyArgOptions { + filter?: (src: string) => boolean +} + export interface IWxTransformResult { code: string, ast: t.File, @@ -106,7 +110,8 @@ export interface ICompileOption { } export interface IMiniAppConfig { - appOutput: boolean, + appOutput?: boolean, + npm?: INpmConfig, module?: { postcss?: IPostcssOption }, @@ -156,6 +161,162 @@ export interface IH5Config { } } +type FeatureItem = { + name: string +} + +const enum LogLevel { + OFF = 'off', + ERROR = 'error', + WARN = 'warn', + INFO = 'info', + LOG = 'log', + DEBUG = 'debug' +} + +export type SystemConfig = { + /** + * 打印日志等级,分为 off,error,warn,info,log,debug + */ + logLevel?: LogLevel, + /** + * 页面设计基准宽度,根据实际设备宽度来缩放元素大小 + */ + designWidth?: number, + /** + * 全局数据对象,属性名不能以$或_开头,在页面中可通过 this 进行访问;如果全局数据属性与页面的数据属性重名,则页面初始化时,全局数据会覆盖页面中对应的属性值 + */ + data?: IOption +} + +type RouterConfig = { + /** + * 首页名称 + */ + entry: string, + /** + * 页面配置列表,key 值为页面名称(对应页面目录名,例如 Hello 对应'Hello'目录),value 为页面详细配置 page + */ + pages: RouterPage[] +} +type RouterPage = { + /** + * 页面对应的组件名,与 ux 文件名保持一致,例如'hello' 对应 'hello.ux' + */ + component: string, + /** + * 页面路径,例如“/user”,不填则默认为/<页面名称>。 + * path 必须唯一,不能和其他 page 的 path 相同。 + * 下面 page 的 path 因为缺失,会被设置为“/Index”: + * "Index": {"component": "index"} + */ + path?: string, + /** + * 声明页面可以处理某种请求 + */ + filter: { + [key: string]: { + uri: string + } + } +} + +interface IDefaultDisplayConfig { + /** + * 窗口背景颜色 + */ + backgroundColor?: string, + /** + * 是否是全屏模式,默认不会同时作用于 titleBar,titleBar 需要继续通过 titleBar 控制 + */ + fullScreen?: boolean, + /** + * 是否显示 titleBar + */ + titleBar?: boolean, + /** + * 标题栏背景色 + */ + titleBarBackgroundColor?: string, + /** + * 标题栏文字颜色 + */ + titleBarTextColor?: string, + /** + * 标题栏文字(也可通过页面跳转传递参数(titleBarText)设置) + */ + titleBarText?: string, + /** + * 是否显示标题栏右上角菜单按钮,点击菜单按钮调用页面生命周期 onMenuPress 方法,如果该方法未实现则显示系统默认菜单 + */ + menu?: boolean, + /** + * 软键盘弹出时为保证输入框可见,页面的调整方式。 adjustPan:上移页面; adjustResize:压缩页面显示区域,当页面全屏时,此设置不生效 + */ + windowSoftInputMode?: 'adjustPan' | 'adjustResize' +} + +interface IDisplayConfig extends IDefaultDisplayConfig { + /** + * 各个页面的显示样式,key 为页面名(与路由中的页面名保持一致),value 为窗口显示样式,页面样式覆盖 default 样式 + */ + pages?: { + [key: string]: IDefaultDisplayConfig + } +} + +export interface ITaroManifestConfig { + npm?: INpmConfig, + /** + * 应用包名,确认与原生应用的包名不一致,推荐采用 com.company.module 的格式,如:com.example.demo + */ + package: string, + /** + * 应用名称,6 个汉字以内,与应用商店保存的名称一致,用于在桌面图标、弹窗等处显示应用名称 + */ + name: string, + /** + * 应用图标,提供 192x192 大小的即可 + */ + icon: string, + /** + * 应用版本名称,如:"1.0" + */ + versionName?: string, + /** + * 应用版本号,从1自增,推荐每次重新上传包时versionCode+1 + */ + versionCode: number, + /** + * 支持的最小平台版本号,兼容性检查,避免上线后在低版本平台运行并导致不兼容;如果不填按照内测版本处理 + */ + minPlatformVersion?: string, + /** + * 接口列表,绝大部分接口都需要在这里声明,否则不能调用,详见每个接口的文档说明 + */ + features?: FeatureItem[], + /** + * + */ + logLevel?: LogLevel +} + +export interface IManifestConfig extends ITaroManifestConfig { + /** + * 系统配置信息 + */ + config: SystemConfig, + /** + * 路由信息 + */ + router: RouterConfig, + /** + * UI 显示相关配置 + */ + display?: IDisplayConfig +} + + export interface IProjectConfig { projectName?: string, date?: string, @@ -176,5 +337,6 @@ export interface IProjectConfig { defineConstants?: IOption, copy?: ICopyOptions, weapp?: IMiniAppConfig, - h5?: IH5Config + h5?: IH5Config, + quickApp?: ITaroManifestConfig } From cc7175c53c399ca9e60398f613ebef8daa92a4bd Mon Sep 17 00:00:00 2001 From: luckyadam Date: Wed, 13 Mar 2019 11:34:37 +0800 Subject: [PATCH 039/103] =?UTF-8?q?feat:=20=E5=BF=AB=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E5=8F=8A=E5=BF=AB=E5=BA=94=E7=94=A8=E6=A1=86?= =?UTF-8?q?=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lerna.json | 1 + packages/taro-cli/src/mini/astProcess.ts | 14 ++- packages/taro-cli/src/mini/compileScript.ts | 4 +- packages/taro-cli/src/mini/compileStyle.ts | 3 +- packages/taro-cli/src/mini/component.ts | 4 +- packages/taro-cli/src/mini/constants.ts | 14 --- packages/taro-cli/src/mini/entry.ts | 4 +- packages/taro-cli/src/mini/native.ts | 3 +- packages/taro-cli/src/mini/page.ts | 5 +- packages/taro-cli/src/mini/watch.ts | 4 +- packages/taro-cli/src/quick/astProcess.ts | 25 +++++- packages/taro-cli/src/quick/constants.ts | 7 +- packages/taro-cli/src/quick/entry.ts | 5 +- packages/taro-cli/src/quick/helper.ts | 4 + packages/taro-cli/src/util/constants.ts | 16 ++++ packages/taro-quickapp/README.md | 3 + packages/taro-quickapp/index.js | 2 + packages/taro-quickapp/package.json | 29 +++++++ packages/taro-quickapp/rollup.config.js | 74 ++++++++++++++++ .../src/api/interactive/index.js | 0 .../src/api/request/index.js | 0 .../src/api/router/index.js | 12 +-- .../src/api/storage/index.js | 0 .../src/api/utils/index.js | 0 packages/taro-quickapp/src/component.js | 87 +++++++++++++++++++ packages/taro-quickapp/src/create-app.js | 26 ++++++ .../taro-quickapp/src/create-component.js | 3 + packages/taro-quickapp/src/index.js | 39 +++++++++ .../src/native-api.js | 0 packages/taro-quickapp/src/pure-component.js | 13 +++ 30 files changed, 347 insertions(+), 54 deletions(-) create mode 100644 packages/taro-quickapp/README.md create mode 100644 packages/taro-quickapp/index.js create mode 100644 packages/taro-quickapp/package.json create mode 100644 packages/taro-quickapp/rollup.config.js rename packages/{taro-qapp => taro-quickapp}/src/api/interactive/index.js (100%) rename packages/{taro-qapp => taro-quickapp}/src/api/request/index.js (100%) rename packages/{taro-qapp => taro-quickapp}/src/api/router/index.js (90%) rename packages/{taro-qapp => taro-quickapp}/src/api/storage/index.js (100%) rename packages/{taro-qapp => taro-quickapp}/src/api/utils/index.js (100%) create mode 100644 packages/taro-quickapp/src/component.js create mode 100644 packages/taro-quickapp/src/create-app.js create mode 100644 packages/taro-quickapp/src/create-component.js create mode 100644 packages/taro-quickapp/src/index.js rename packages/{taro-qapp => taro-quickapp}/src/native-api.js (100%) create mode 100644 packages/taro-quickapp/src/pure-component.js diff --git a/lerna.json b/lerna.json index 04a129537dfc..094ab39dfe31 100644 --- a/lerna.json +++ b/lerna.json @@ -26,6 +26,7 @@ "packages/taro-swan", "packages/taro-alipay", "packages/taro-tt", + "packages/taro-quickapp", "packages/taro-webpack-runner", "packages/postcss-plugin-constparse", "packages/eslint-config-taro", diff --git a/packages/taro-cli/src/mini/astProcess.ts b/packages/taro-cli/src/mini/astProcess.ts index 253a34b760ef..86295e171318 100644 --- a/packages/taro-cli/src/mini/astProcess.ts +++ b/packages/taro-cli/src/mini/astProcess.ts @@ -21,7 +21,12 @@ import { CSS_EXT, processTypeEnum, BUILD_TYPES, - NODE_MODULES_REG + NODE_MODULES_REG, + PARSE_AST_TYPE, + taroJsComponents, + taroJsRedux, + taroJsFramework, + DEVICE_RATIO_NAME } from '../util/constants' import { resolveScriptPath, @@ -36,13 +41,6 @@ import { convertObjectToAstExpression, convertArrayToAstExpression } from '../ut import babylonConfig from '../config/babylon' import { getExactedNpmFilePath, getNotExistNpmList } from '../util/npmExact' -import { - PARSE_AST_TYPE, - taroJsComponents, - taroJsRedux, - taroJsFramework, - DEVICE_RATIO_NAME -} from './constants' import { IComponentObj } from './interface' import { getBuildData, diff --git a/packages/taro-cli/src/mini/compileScript.ts b/packages/taro-cli/src/mini/compileScript.ts index 9771bdc4b302..73f0ad9b5fef 100644 --- a/packages/taro-cli/src/mini/compileScript.ts +++ b/packages/taro-cli/src/mini/compileScript.ts @@ -12,7 +12,8 @@ import { BUILD_TYPES, processTypeEnum, REG_TYPESCRIPT, - NODE_MODULES_REG + NODE_MODULES_REG, + PARSE_AST_TYPE } from '../util/constants' import { callPlugin } from '../util/npm' import { IWxTransformResult } from '../util/types' @@ -26,7 +27,6 @@ import { uglifyJS } from './helper' import { parseAst } from './astProcess' -import { PARSE_AST_TYPE } from './constants' import { IDependency } from './interface' const isBuildingScripts: Map = new Map() diff --git a/packages/taro-cli/src/mini/compileStyle.ts b/packages/taro-cli/src/mini/compileStyle.ts index 023b5ce654c3..aeac33ee7e65 100644 --- a/packages/taro-cli/src/mini/compileStyle.ts +++ b/packages/taro-cli/src/mini/compileStyle.ts @@ -24,13 +24,12 @@ import { processStyleImports, promoteRelativePath } from '../util' -import { CSS_EXT, FILE_PROCESSOR_MAP } from '../util/constants' +import { CSS_EXT, FILE_PROCESSOR_MAP, DEVICE_RATIO_NAME } from '../util/constants' import { IMiniAppConfig } from '../util/types' import { getBuildData } from './helper' -import { DEVICE_RATIO_NAME } from './constants' const genericNames = require('generic-names') diff --git a/packages/taro-cli/src/mini/component.ts b/packages/taro-cli/src/mini/component.ts index cd32bd622d3a..6008ca7963d1 100644 --- a/packages/taro-cli/src/mini/component.ts +++ b/packages/taro-cli/src/mini/component.ts @@ -11,7 +11,8 @@ import { REG_TYPESCRIPT, processTypeEnum, NODE_MODULES_REG, - NODE_MODULES + NODE_MODULES, + PARSE_AST_TYPE } from '../util/constants' import { printLog, @@ -39,7 +40,6 @@ import { import { compileScriptFile, compileDepScripts } from './compileScript' import { compileDepStyles } from './compileStyle' import { transfromNativeComponents, processNativeWxml } from './native' -import { PARSE_AST_TYPE } from './constants' const notTaroComponents = new Set() const componentsNamedMap = new Map() diff --git a/packages/taro-cli/src/mini/constants.ts b/packages/taro-cli/src/mini/constants.ts index d0f91d80ad25..8b137891791f 100644 --- a/packages/taro-cli/src/mini/constants.ts +++ b/packages/taro-cli/src/mini/constants.ts @@ -1,15 +1 @@ -import * as os from 'os' -export const taroJsFramework = '@tarojs/taro' -export const taroJsComponents = '@tarojs/components' -export const taroJsRedux = '@tarojs/redux' - -export enum PARSE_AST_TYPE { - ENTRY = 'ENTRY', - PAGE = 'PAGE', - COMPONENT = 'COMPONENT', - NORMAL = 'NORMAL' -} - -export const DEVICE_RATIO_NAME = 'deviceRatio' -export const isWindows = os.platform() === 'win32' diff --git a/packages/taro-cli/src/mini/entry.ts b/packages/taro-cli/src/mini/entry.ts index feb0b6209535..74ba5b9fc03a 100644 --- a/packages/taro-cli/src/mini/entry.ts +++ b/packages/taro-cli/src/mini/entry.ts @@ -8,7 +8,8 @@ import { REG_SCRIPTS, REG_TYPESCRIPT, CONFIG_MAP, - processTypeEnum + processTypeEnum, + PARSE_AST_TYPE } from '../util/constants' import { isDifferentArray, @@ -19,7 +20,6 @@ import { import { IWxTransformResult } from '../util/types' import { getBuildData, uglifyJS, copyFilesFromSrcToOutput, getDependencyTree } from './helper' -import { PARSE_AST_TYPE } from './constants' import { compileDepScripts, compileScriptFile } from './compileScript' import { compileDepStyles } from './compileStyle' import { parseAst } from './astProcess' diff --git a/packages/taro-cli/src/mini/native.ts b/packages/taro-cli/src/mini/native.ts index 42305af74ced..e5077fa405dd 100644 --- a/packages/taro-cli/src/mini/native.ts +++ b/packages/taro-cli/src/mini/native.ts @@ -4,11 +4,10 @@ import * as path from 'path' import { Config as IConfig } from '@tarojs/taro' import chalk from 'chalk' -import { REG_WXML_IMPORT, processTypeEnum } from '../util/constants' +import { REG_WXML_IMPORT, processTypeEnum, taroJsFramework } from '../util/constants' import { isEmptyObject, printLog, resolveScriptPath, copyFileSync } from '../util' import { buildDepComponents } from './component' -import { taroJsFramework } from './constants' import { compileDepScripts } from './compileScript' import { compileDepStyles } from './compileStyle' import { getBuildData } from './helper' diff --git a/packages/taro-cli/src/mini/page.ts b/packages/taro-cli/src/mini/page.ts index 56dc49613cff..9adad91d1915 100644 --- a/packages/taro-cli/src/mini/page.ts +++ b/packages/taro-cli/src/mini/page.ts @@ -8,7 +8,9 @@ import * as _ from 'lodash' import { REG_TYPESCRIPT, processTypeEnum, - NODE_MODULES_REG + NODE_MODULES_REG, + PARSE_AST_TYPE, + taroJsFramework } from '../util/constants' import { resolveScriptPath, @@ -21,7 +23,6 @@ import { import { IWxTransformResult } from '../util/types' import { IComponentObj } from './interface' -import { PARSE_AST_TYPE, taroJsFramework } from './constants' import { getBuildData, getRealComponentsPathList, diff --git a/packages/taro-cli/src/mini/watch.ts b/packages/taro-cli/src/mini/watch.ts index dc4c73ce81d3..cee2f656299b 100644 --- a/packages/taro-cli/src/mini/watch.ts +++ b/packages/taro-cli/src/mini/watch.ts @@ -8,7 +8,8 @@ import { REG_SCRIPT, REG_STYLE, processTypeEnum, - NODE_MODULES_REG + NODE_MODULES_REG, + isWindows } from '../util/constants' import { printLog, @@ -30,7 +31,6 @@ import { import { buildEntry } from './entry' import { buildPages, buildSinglePage } from './page' import { buildSingleComponent, getComponentsNamedMap } from './component' -import { isWindows } from './constants' export function watchFiles () { const appPath = process.cwd() diff --git a/packages/taro-cli/src/quick/astProcess.ts b/packages/taro-cli/src/quick/astProcess.ts index 6221fadddea2..7069e4e3556f 100644 --- a/packages/taro-cli/src/quick/astProcess.ts +++ b/packages/taro-cli/src/quick/astProcess.ts @@ -8,10 +8,10 @@ import traverse from 'babel-traverse' import _ from 'lodash' import { Config as IConfig } from '@tarojs/taro' -import { PARSE_AST_TYPE } from './constants' -import { getBuildData } from './helper' +import { PARSE_AST_TYPE, taroJsComponents, taroJsQuickAppComponents } from '../util/constants' +import { getBuildData, isQuickAppPkg } from './helper' import { getNotExistNpmList } from '../util/npmExact' -import { traverseObjectNode } from '../util' +import { traverseObjectNode, isAliasPath, replaceAliasPath, isNpmPkg } from '../util' export function parseAst ( type: PARSE_AST_TYPE, @@ -162,6 +162,25 @@ export function parseAst ( if (node.key.name === 'config') { configObj = traverseObjectNode(node, buildAdapter) } + }, + + ImportDeclaration (astPath) { + const node = astPath.node + const source = node.source + let value = source.value + const specifiers = node.specifiers + if (isAliasPath(value, pathAlias)) { + value = replaceAliasPath(sourceFilePath, value, pathAlias) + source.value = value + } + if (isNpmPkg(value) + && !isQuickAppPkg(value) + && !notExistNpmList.has(value)) { + if (value === taroJsComponents) { + source.value = taroJsQuickAppComponents + } + + } } }) return { diff --git a/packages/taro-cli/src/quick/constants.ts b/packages/taro-cli/src/quick/constants.ts index 7feed344bca2..8b137891791f 100644 --- a/packages/taro-cli/src/quick/constants.ts +++ b/packages/taro-cli/src/quick/constants.ts @@ -1,6 +1 @@ -export enum PARSE_AST_TYPE { - ENTRY = 'ENTRY', - PAGE = 'PAGE', - COMPONENT = 'COMPONENT', - NORMAL = 'NORMAL' -} + diff --git a/packages/taro-cli/src/quick/entry.ts b/packages/taro-cli/src/quick/entry.ts index 3227bf257d54..151240a63bb0 100644 --- a/packages/taro-cli/src/quick/entry.ts +++ b/packages/taro-cli/src/quick/entry.ts @@ -4,12 +4,11 @@ import * as path from 'path' import * as wxTransformer from '@tarojs/transformer-wx' import { IWxTransformResult } from '../util/types' -import { processTypeEnum, REG_TYPESCRIPT } from '../util/constants' +import { processTypeEnum, REG_TYPESCRIPT, PARSE_AST_TYPE } from '../util/constants' import { printLog } from '../util' import { getBuildData, setAppConfig, getDependencyTree } from './helper' import { parseAst } from './astProcess' -import { PARSE_AST_TYPE } from './constants' export async function buildEntry () { const { @@ -40,7 +39,7 @@ export async function buildEntry () { const { configObj, code } = parseAst(PARSE_AST_TYPE.ENTRY, transformResult.ast, entryFilePath, outputEntryFilePath) const dependencyTree = getDependencyTree() setAppConfig(configObj) - console.log(transformResult.template) + console.log(code) } catch (err) { console.log(err) } diff --git a/packages/taro-cli/src/quick/helper.ts b/packages/taro-cli/src/quick/helper.ts index 084ca7f68fbd..41201f5c9b7a 100644 --- a/packages/taro-cli/src/quick/helper.ts +++ b/packages/taro-cli/src/quick/helper.ts @@ -103,3 +103,7 @@ export function setManifestJSON (key, value) { export function getDependencyTree (): Map { return dependencyTree } + +export function isQuickAppPkg (name: string): boolean { + return /@system\./.test(name) +} diff --git a/packages/taro-cli/src/util/constants.ts b/packages/taro-cli/src/util/constants.ts index e1c37f31a9f5..3540b4b013fa 100644 --- a/packages/taro-cli/src/util/constants.ts +++ b/packages/taro-cli/src/util/constants.ts @@ -1,3 +1,4 @@ +import * as os from 'os' import chalk, { Chalk } from 'chalk' export const enum processTypeEnum { @@ -272,3 +273,18 @@ export const UPDATE_PACKAGE_LIST = [ '@tarojs/mobx-common', '@tarojs/mobx-prop-types' ] + +export enum PARSE_AST_TYPE { + ENTRY = 'ENTRY', + PAGE = 'PAGE', + COMPONENT = 'COMPONENT', + NORMAL = 'NORMAL' +} + +export const taroJsComponents = '@tarojs/components' +export const taroJsQuickAppComponents = '@tarojs/components-qa' +export const taroJsFramework = '@tarojs/taro' +export const taroJsRedux = '@tarojs/redux' + +export const DEVICE_RATIO_NAME = 'deviceRatio' +export const isWindows = os.platform() === 'win32' diff --git a/packages/taro-quickapp/README.md b/packages/taro-quickapp/README.md new file mode 100644 index 000000000000..c0cfd431f7be --- /dev/null +++ b/packages/taro-quickapp/README.md @@ -0,0 +1,3 @@ +# @tarojs/taro-quickapp + +多端解决方案快应用端基础框架 diff --git a/packages/taro-quickapp/index.js b/packages/taro-quickapp/index.js new file mode 100644 index 000000000000..437a6d4788f4 --- /dev/null +++ b/packages/taro-quickapp/index.js @@ -0,0 +1,2 @@ +module.exports = require('./dist/index.js').default +module.exports.default = module.exports diff --git a/packages/taro-quickapp/package.json b/packages/taro-quickapp/package.json new file mode 100644 index 000000000000..c800e5b32fa0 --- /dev/null +++ b/packages/taro-quickapp/package.json @@ -0,0 +1,29 @@ +{ + "name": "@tarojs/taro-quickapp", + "version": "1.2.13", + "description": "Taro quickapp framework", + "main": "index.js", + "files": [ + "dist", + "src", + "index.js", + "package.json" + ], + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "rollup -c rollup.config.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/NervJS/taro.git" + }, + "keywords": [ + "taro" + ], + "author": "O2Team", + "license": "MIT", + "dependencies": { + "@tarojs/taro": "1.2.13", + "@tarojs/utils": "1.2.13" + } +} diff --git a/packages/taro-quickapp/rollup.config.js b/packages/taro-quickapp/rollup.config.js new file mode 100644 index 000000000000..419b7f40bc33 --- /dev/null +++ b/packages/taro-quickapp/rollup.config.js @@ -0,0 +1,74 @@ +const { join } = require('path') +const resolve = require('rollup-plugin-node-resolve') +const babel = require('rollup-plugin-babel') +const common = require('rollup-plugin-commonjs') +const alias = require('rollup-plugin-alias') +const cwd = __dirname + +const baseConfig = { + input: join(cwd, 'src/index.js'), + external: ['nervjs'], + output: [ + { + file: join(cwd, 'dist/index.js'), + format: 'cjs', + sourcemap: true, + exports: 'named' + }, + { + file: join(cwd, 'dist/taro-quickapp.js'), + format: 'umd', + name: 'TaroAuickapp', + sourcemap: true, + exports: 'named' + } + ], + plugins: [ + alias({ + '@tarojs/taro': join(cwd, '../taro/src/index'), + '@tarojs/utils': join(cwd, '../taro-utils/dist/index') + }), + resolve({ + preferBuiltins: false + }), + + common({ + include: 'node_modules/**' + }), + babel({ + babelrc: false, + presets: [ + ['@babel/preset-env', { + modules: false + }] + ], + plugins: [ + '@babel/plugin-proposal-class-properties', + '@babel/plugin-proposal-object-rest-spread', + ['@babel/plugin-transform-react-jsx', { + 'pragma': 'Nerv.createElement' + }] + ] + }) + ] +} +const esmConfig = Object.assign({}, baseConfig, { + output: Object.assign({}, baseConfig.output, { + sourcemap: true, + format: 'es', + file: join(cwd, 'dist/index.esm.js') + }) +}) + +function rollup () { + const target = process.env.TARGET + + if (target === 'umd') { + return baseConfig + } else if (target === 'esm') { + return esmConfig + } else { + return [baseConfig, esmConfig] + } +} +module.exports = rollup() diff --git a/packages/taro-qapp/src/api/interactive/index.js b/packages/taro-quickapp/src/api/interactive/index.js similarity index 100% rename from packages/taro-qapp/src/api/interactive/index.js rename to packages/taro-quickapp/src/api/interactive/index.js diff --git a/packages/taro-qapp/src/api/request/index.js b/packages/taro-quickapp/src/api/request/index.js similarity index 100% rename from packages/taro-qapp/src/api/request/index.js rename to packages/taro-quickapp/src/api/request/index.js diff --git a/packages/taro-qapp/src/api/router/index.js b/packages/taro-quickapp/src/api/router/index.js similarity index 90% rename from packages/taro-qapp/src/api/router/index.js rename to packages/taro-quickapp/src/api/router/index.js index 82e40db19e6c..8e91e2c89139 100644 --- a/packages/taro-qapp/src/api/router/index.js +++ b/packages/taro-quickapp/src/api/router/index.js @@ -42,7 +42,7 @@ function qappNavigate (options = {}, method = 'push') { try { router[method]({ uri: url, - params, + params }) success && success(res) complete && complete(res) @@ -58,18 +58,18 @@ function qappNavigate (options = {}, method = 'push') { function getUrlParams (url = '') { let params = {} -  url && url.replace(/(\w+)=(\w+)/ig, function (a, b, c) { + url && url.replace(/(\w+)=(\w+)/ig, function (a, b, c) { params[b] = unescape(c) }) -  return params + return params } -export default { +export default { reLaunch, switchTab, navigateTo, redirectTo, navigateBack, - getCurrentPages -} \ No newline at end of file + getCurrentPages +} diff --git a/packages/taro-qapp/src/api/storage/index.js b/packages/taro-quickapp/src/api/storage/index.js similarity index 100% rename from packages/taro-qapp/src/api/storage/index.js rename to packages/taro-quickapp/src/api/storage/index.js diff --git a/packages/taro-qapp/src/api/utils/index.js b/packages/taro-quickapp/src/api/utils/index.js similarity index 100% rename from packages/taro-qapp/src/api/utils/index.js rename to packages/taro-quickapp/src/api/utils/index.js diff --git a/packages/taro-quickapp/src/component.js b/packages/taro-quickapp/src/component.js new file mode 100644 index 000000000000..152a402c3361 --- /dev/null +++ b/packages/taro-quickapp/src/component.js @@ -0,0 +1,87 @@ +import { + internal_safe_get as safeGet +} from '@tarojs/taro' + +export default class BaseComponent { + // _createData的时候生成,小程序中通过data.__createData访问 + __computed = {} + // this.props,小程序中通过data.__props访问 + __props = {} + __isReady = false + // 会在componentDidMount后置为true + __mounted = false + _dirty = true + _disable = true + _pendingStates = [] + _pendingCallbacks = [] + $componentType = '' + $router = { + params: {}, + path: '' + } + + constructor (props = {}, isPage) { + this.state = {} + this.props = {} + this.$componentType = isPage ? 'PAGE' : 'COMPONENT' + this.isTaroComponent = this.$componentType && this.$router && this._pendingStates + } + _constructor (props) { + this.props = props || {} + } + _init (scope) { + this.$scope = scope + } + setState (state, callback) { + + } + + getState () { + const { _pendingStates, state, props } = this + const stateClone = Object.assign({}, state) + delete stateClone.__data + if (!_pendingStates.length) { + return stateClone + } + const queue = _pendingStates.concat() + this._pendingStates.length = 0 + queue.forEach((nextState) => { + if (typeof nextState === 'function') { + nextState = nextState.call(this, stateClone, props) + } + Object.assign(stateClone, nextState) + }) + return stateClone + } + + forceUpdate (callback) { + if (typeof callback === 'function') { + (this._pendingCallbacks = this._pendingCallbacks || []).push(callback) + } + } + + // 会被匿名函数调用 + __triggerPropsFn (key, args) { + const keyChain = key.split('.') + const reduxFnPrefix = '__event_' + const reduxFnName = reduxFnPrefix + keyChain.shift() + // redux标识过的方法,直接调用 + if (reduxFnName in this) { + const scope = args.shift() + let fn + if (keyChain.length > 0) { + fn = safeGet(this[reduxFnName], keyChain.join('.')) + } else { + fn = this[reduxFnName] + } + fn.apply(scope, args) + } else { + // 普通的 + const keyLower = key.toLocaleLowerCase() + this.$scope.triggerEvent(keyLower, { + __isCustomEvt: true, + __arguments: args + }) + } + } +} diff --git a/packages/taro-quickapp/src/create-app.js b/packages/taro-quickapp/src/create-app.js new file mode 100644 index 000000000000..6e7e99351582 --- /dev/null +++ b/packages/taro-quickapp/src/create-app.js @@ -0,0 +1,26 @@ +function createApp (AppClass) { + const app = new AppClass() + const appConf = { + onCreate (options) { + app.$app = this + app.$app.$router = app.$router = { + params: options + } + if (app.componentWillMount) { + app.componentWillMount() + } + if (app.componentDidMount) { + app.componentDidMount() + } + }, + + onDestroy () { + if (app.componentWillUnmount) { + app.componentWillUnmount() + } + } + } + return Object.assign(appConf, app) +} + +export default createApp diff --git a/packages/taro-quickapp/src/create-component.js b/packages/taro-quickapp/src/create-component.js new file mode 100644 index 000000000000..5eb23c89978a --- /dev/null +++ b/packages/taro-quickapp/src/create-component.js @@ -0,0 +1,3 @@ +export default function createComponent (ComponentClass, isPage) { + +} diff --git a/packages/taro-quickapp/src/index.js b/packages/taro-quickapp/src/index.js new file mode 100644 index 000000000000..ef1b9fe07edf --- /dev/null +++ b/packages/taro-quickapp/src/index.js @@ -0,0 +1,39 @@ +/* eslint-disable camelcase */ +import { + getEnv, + Events, + eventCenter, + ENV_TYPE, + render, + internal_safe_get, + internal_safe_set, + internal_inline_style, + internal_get_original +} from '@tarojs/taro' + +import Component from './component' +import PureComponent from './pure-component' +import createApp from './create-app' +import createComponent from './create-component' +import initNativeApi from './native-api' + +export const Taro = { + Component, + PureComponent, + createApp, + initNativeApi, + Events, + eventCenter, + getEnv, + render, + ENV_TYPE, + internal_safe_get, + internal_safe_set, + internal_inline_style, + createComponent, + internal_get_original +} + +export default Taro + +initNativeApi(Taro) diff --git a/packages/taro-qapp/src/native-api.js b/packages/taro-quickapp/src/native-api.js similarity index 100% rename from packages/taro-qapp/src/native-api.js rename to packages/taro-quickapp/src/native-api.js diff --git a/packages/taro-quickapp/src/pure-component.js b/packages/taro-quickapp/src/pure-component.js new file mode 100644 index 000000000000..5aea70022c69 --- /dev/null +++ b/packages/taro-quickapp/src/pure-component.js @@ -0,0 +1,13 @@ +import { shallowEqual } from '@tarojs/utils' + +import Component from './component' + +class PureComponent extends Component { + isPureComponent = true + + shouldComponentUpdate (nextProps, nextState) { + return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState) + } +} + +export default PureComponent From 717723028e7e4085cd8fc62f9e0cc963bc86dfdc Mon Sep 17 00:00:00 2001 From: luckyadam Date: Thu, 14 Mar 2019 16:40:10 +0800 Subject: [PATCH 040/103] =?UTF-8?q?feat:=20=E5=BF=AB=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/src/build.ts | 2 +- packages/taro-cli/src/mini/astProcess.ts | 43 +- packages/taro-cli/src/mini/compileScript.ts | 8 +- packages/taro-cli/src/mini/entry.ts | 89 ++-- packages/taro-cli/src/mini/helper.ts | 3 +- packages/taro-cli/src/mini/index.ts | 6 +- packages/taro-cli/src/quick/astProcess.ts | 492 +++++++++++++++++- packages/taro-cli/src/quick/entry.ts | 8 +- packages/taro-cli/src/quick/helper.ts | 18 +- packages/taro-cli/src/quick/interface.ts | 6 + packages/taro-cli/src/util/constants.ts | 18 +- packages/taro-cli/src/util/index.ts | 33 +- packages/taro-cli/src/util/npm.ts | 23 +- .../taro-cli/src/util/resolve_npm_files.ts | 6 +- .../components/{button.js => button}/img.js | 0 .../components/{button.js => button}/index.ux | 0 16 files changed, 673 insertions(+), 82 deletions(-) rename packages/taro-components-qa/src/components/{button.js => button}/img.js (100%) rename packages/taro-components-qa/src/components/{button.js => button}/index.ux (100%) diff --git a/packages/taro-cli/src/build.ts b/packages/taro-cli/src/build.ts index 746afabad25b..280a389f96e5 100644 --- a/packages/taro-cli/src/build.ts +++ b/packages/taro-cli/src/build.ts @@ -88,7 +88,7 @@ function buildForRN ({ watch }: IBuildConfig) { } function buildForQuickApp ({ watch }: IBuildConfig) { - require('./quick').build({ + require('./mini').build({ watch, adapter: BUILD_TYPES.QUICKAPP }) diff --git a/packages/taro-cli/src/mini/astProcess.ts b/packages/taro-cli/src/mini/astProcess.ts index 86295e171318..3de26a8d8a35 100644 --- a/packages/taro-cli/src/mini/astProcess.ts +++ b/packages/taro-cli/src/mini/astProcess.ts @@ -26,7 +26,8 @@ import { taroJsComponents, taroJsRedux, taroJsFramework, - DEVICE_RATIO_NAME + DEVICE_RATIO_NAME, + taroJsQuickAppComponents } from '../util/constants' import { resolveScriptPath, @@ -35,7 +36,8 @@ import { isNpmPkg, isAliasPath, replaceAliasPath, - traverseObjectNode + traverseObjectNode, + isQuickAppPkg } from '../util' import { convertObjectToAstExpression, convertArrayToAstExpression } from '../util/astConvert' import babylonConfig from '../config/babylon' @@ -227,9 +229,14 @@ export function parseAst ( let taroImportDefaultName let needExportDefault = false let exportTaroReduxConnected: string | null = null + const isQuickApp = buildAdapter === BUILD_TYPES.QUICKAPP + const cannotRemoves = [taroJsFramework, 'react', 'nervjs'] + if (isQuickApp) { + cannotRemoves.push(taroJsComponents) + } ast = babel.transformFromAst(ast, '', { plugins: [ - [require('babel-plugin-danger-remove-unused-import'), { ignore: ['@tarojs/taro', 'react', 'nervjs'] }], + [require('babel-plugin-danger-remove-unused-import'), { ignore: cannotRemoves }], [require('babel-plugin-transform-define').default, constantsReplaceList] ] }).ast as t.File @@ -359,8 +366,11 @@ export function parseAst ( value = replaceAliasPath(sourceFilePath, value, pathAlias) source.value = value } - if (isNpmPkg(value) && !notExistNpmList.has(value)) { + if (isNpmPkg(value) && !isQuickAppPkg(value) && !notExistNpmList.has(value)) { if (value === taroJsComponents) { + if (isQuickApp) { + console.log(specifiers) + } astPath.remove() } else { let isDepComponent = false @@ -466,9 +476,14 @@ export function parseAst ( value = replaceAliasPath(sourceFilePath, value, pathAlias) args[0].value = value } - if (isNpmPkg(value) && !notExistNpmList.has(value)) { + if (isNpmPkg(value) && !isQuickAppPkg(value) && !notExistNpmList.has(value)) { if (value === taroJsComponents) { - astPath.remove() + if (buildAdapter === BUILD_TYPES.QUICKAPP) { + args[0].value = taroJsQuickAppComponents + value = taroJsQuickAppComponents + } else { + astPath.remove() + } } else { let isDepComponent = false if (depComponents && depComponents.length) { @@ -724,7 +739,7 @@ export function parseAst ( }) const node = astPath.node as t.Program const exportVariableName = exportTaroReduxConnected || componentClassName - if (needExportDefault) { + if (needExportDefault && buildAdapter !== BUILD_TYPES.QUICKAPP) { const exportDefault = template(`export default ${exportVariableName}`, babylonConfig as any)() node.body.push(exportDefault as any) } @@ -745,18 +760,28 @@ export function parseAst ( if (projectConfig.hasOwnProperty(DEVICE_RATIO_NAME)) { pxTransformConfig[DEVICE_RATIO_NAME] = projectConfig.deviceRatio } - node.body.push(template(`App(require('${taroMiniAppFrameworkPath}').default.createApp(${exportVariableName}))`, babylonConfig as any)() as any) + if (buildAdapter === BUILD_TYPES.QUICKAPP) { + node.body.push(template(`export default require('${taroMiniAppFrameworkPath}').default.createApp(${exportVariableName})`, babylonConfig as any)() as any) + } else { + node.body.push(template(`App(require('${taroMiniAppFrameworkPath}').default.createApp(${exportVariableName}))`, babylonConfig as any)() as any) + } node.body.push(template(`Taro.initPxTransform(${JSON.stringify(pxTransformConfig)})`, babylonConfig as any)() as any) break case PARSE_AST_TYPE.PAGE: if (buildAdapter === BUILD_TYPES.WEAPP) { node.body.push(template(`Component(require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}, true))`, babylonConfig as any)() as any) + } else if (buildAdapter === BUILD_TYPES.QUICKAPP) { + node.body.push(template(`export default require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}, true)`, babylonConfig as any)() as any) } else { node.body.push(template(`Page(require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}, true))`, babylonConfig as any)() as any) } break case PARSE_AST_TYPE.COMPONENT: - node.body.push(template(`Component(require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}))`, babylonConfig as any)() as any) + if (buildAdapter === BUILD_TYPES.QUICKAPP) { + node.body.push(template(`export default require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName})`, babylonConfig as any)() as any) + } else { + node.body.push(template(`Component(require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}))`, babylonConfig as any)() as any) + } break default: break diff --git a/packages/taro-cli/src/mini/compileScript.ts b/packages/taro-cli/src/mini/compileScript.ts index 73f0ad9b5fef..99e68ce8fada 100644 --- a/packages/taro-cli/src/mini/compileScript.ts +++ b/packages/taro-cli/src/mini/compileScript.ts @@ -35,7 +35,7 @@ export function initCompileScripts () { isBuildingScripts.clear() } -export function compileDepScripts (scriptFiles: string[]) { +export function compileDepScripts (scriptFiles: string[], needUseBabel?: boolean) { const { nodeModulesPath, npmOutputDir, @@ -86,7 +86,9 @@ export function compileDepScripts (scriptFiles: string[]) { const res = parseAst(PARSE_AST_TYPE.NORMAL, ast, [], item, outputItem) const fileDep = dependencyTree.get(item) || {} as IDependency let resCode = res.code - resCode = await compileScriptFile(res.code, item, outputItem, buildAdapter) + if (needUseBabel) { + resCode = await compileScriptFile(res.code, item, outputItem, buildAdapter) + } fs.ensureDirSync(path.dirname(outputItem)) if (isProduction) { uglifyJS(resCode, item) @@ -97,7 +99,7 @@ export function compileDepScripts (scriptFiles: string[]) { printLog(processTypeEnum.GENERATE, '依赖文件', modifyOutput) // 编译依赖的脚本文件 if (isDifferentArray(fileDep['script'], res.scriptFiles)) { - compileDepScripts(res.scriptFiles) + compileDepScripts(res.scriptFiles, needUseBabel) } // 拷贝依赖文件 if (isDifferentArray(fileDep['json'], res.jsonFiles)) { diff --git a/packages/taro-cli/src/mini/entry.ts b/packages/taro-cli/src/mini/entry.ts index 74ba5b9fc03a..6b43014e791b 100644 --- a/packages/taro-cli/src/mini/entry.ts +++ b/packages/taro-cli/src/mini/entry.ts @@ -9,13 +9,16 @@ import { REG_TYPESCRIPT, CONFIG_MAP, processTypeEnum, - PARSE_AST_TYPE + PARSE_AST_TYPE, + BUILD_TYPES } from '../util/constants' import { isDifferentArray, printLog, isEmptyObject, - resolveScriptPath + resolveScriptPath, + promoteRelativePath, + generateQuickAppUx } from '../util' import { IWxTransformResult } from '../util/types' @@ -107,21 +110,11 @@ export async function buildEntry (): Promise { // app.js的template忽略 const res = parseAst(PARSE_AST_TYPE.ENTRY, transformResult.ast, [], entryFilePath, outputEntryFilePath) let resCode = res.code - resCode = await compileScriptFile(resCode, entryFilePath, outputEntryFilePath, buildAdapter) - if (isProduction) { - resCode = uglifyJS(resCode, entryFilePath) - } - if (appOutput) { - fs.writeFileSync(path.join(outputDir, 'app.json'), JSON.stringify(res.configObj, null, 2)) - printLog(processTypeEnum.GENERATE, '入口配置', `${outputDirName}/app.json`) - fs.writeFileSync(path.join(outputDir, 'app.js'), resCode) - printLog(processTypeEnum.GENERATE, '入口文件', `${outputDirName}/app.js`) - } - if (res.configObj.workers) { - buildWorkers(res.configObj.workers) - } - if (res.configObj.tabBar && res.configObj.tabBar.custom) { - await buildCustomTabbar() + if (buildAdapter !== BUILD_TYPES.QUICKAPP) { + resCode = await compileScriptFile(resCode, entryFilePath, outputEntryFilePath, buildAdapter) + if (isProduction) { + resCode = uglifyJS(resCode, entryFilePath) + } } const dependencyTree = getDependencyTree() const fileDep = dependencyTree.get(entryFilePath) || { @@ -132,7 +125,7 @@ export async function buildEntry (): Promise { } // 编译依赖的脚本文件 if (isDifferentArray(fileDep['script'], res.scriptFiles)) { - compileDepScripts(res.scriptFiles) + compileDepScripts(res.scriptFiles, buildAdapter !== BUILD_TYPES.QUICKAPP) } // 编译样式文件 if (isDifferentArray(fileDep['style'], res.styleFiles) && appOutput) { @@ -144,25 +137,6 @@ export async function buildEntry (): Promise { copyFilesFromSrcToOutput(res.jsonFiles) } - // 处理res.configObj 中的tabBar配置 - const tabBar = res.configObj.tabBar - if (tabBar && typeof tabBar === 'object' && !isEmptyObject(tabBar)) { - const { - list: listConfig, - iconPath: pathConfig, - selectedIconPath: selectedPathConfig - } = CONFIG_MAP[buildAdapter] - const list = tabBar[listConfig] || [] - let tabBarIcons: string[] = [] - list.forEach(item => { - item[pathConfig] && tabBarIcons.push(item[pathConfig]) - item[selectedPathConfig] && tabBarIcons.push(item[selectedPathConfig]) - }) - tabBarIcons = tabBarIcons.map(item => path.resolve(sourceDir, item)) - if (tabBarIcons && tabBarIcons.length) { - res.mediaFiles = res.mediaFiles.concat(tabBarIcons) - } - } if (isDifferentArray(fileDep['media'], res.mediaFiles)) { copyFilesFromSrcToOutput(res.mediaFiles) } @@ -171,6 +145,47 @@ export async function buildEntry (): Promise { fileDep['json'] = res.jsonFiles fileDep['media'] = res.mediaFiles dependencyTree.set(entryFilePath, fileDep) + if (buildAdapter === BUILD_TYPES.QUICKAPP) { + // 生成 快应用 ux 文件 + const styleRelativePath = promoteRelativePath(path.relative(outputEntryFilePath, path.join(outputDir, `app${outputFilesTypes.STYLE}`))) + const uxTxt = generateQuickAppUx({ + script: resCode, + style: styleRelativePath + }) + fs.writeFileSync(path.join(outputDir, `app${outputFilesTypes.TEMPL}`), uxTxt) + } else { + if (res.configObj.workers) { + buildWorkers(res.configObj.workers) + } + if (res.configObj.tabBar && res.configObj.tabBar.custom) { + await buildCustomTabbar() + } + // 处理res.configObj 中的tabBar配置 + const tabBar = res.configObj.tabBar + if (tabBar && typeof tabBar === 'object' && !isEmptyObject(tabBar)) { + const { + list: listConfig, + iconPath: pathConfig, + selectedIconPath: selectedPathConfig + } = CONFIG_MAP[buildAdapter] + const list = tabBar[listConfig] || [] + let tabBarIcons: string[] = [] + list.forEach(item => { + item[pathConfig] && tabBarIcons.push(item[pathConfig]) + item[selectedPathConfig] && tabBarIcons.push(item[selectedPathConfig]) + }) + tabBarIcons = tabBarIcons.map(item => path.resolve(sourceDir, item)) + if (tabBarIcons && tabBarIcons.length) { + res.mediaFiles = res.mediaFiles.concat(tabBarIcons) + } + } + if (appOutput) { + fs.writeFileSync(path.join(outputDir, 'app.json'), JSON.stringify(res.configObj, null, 2)) + printLog(processTypeEnum.GENERATE, '入口配置', `${outputDirName}/app.json`) + fs.writeFileSync(path.join(outputDir, 'app.js'), resCode) + printLog(processTypeEnum.GENERATE, '入口文件', `${outputDirName}/app.js`) + } + } return res.configObj } catch (err) { console.log(err) diff --git a/packages/taro-cli/src/mini/helper.ts b/packages/taro-cli/src/mini/helper.ts index 285e862da73b..d48c4d765b50 100644 --- a/packages/taro-cli/src/mini/helper.ts +++ b/packages/taro-cli/src/mini/helper.ts @@ -11,7 +11,8 @@ import { PROJECT_CONFIG, processTypeEnum, REG_SCRIPTS, - NODE_MODULES_REG + NODE_MODULES_REG, + REG_STYLE } from '../util/constants' import { resolveScriptPath, diff --git a/packages/taro-cli/src/mini/index.ts b/packages/taro-cli/src/mini/index.ts index c95dd922cc5d..f53dd3ad35ea 100644 --- a/packages/taro-cli/src/mini/index.ts +++ b/packages/taro-cli/src/mini/index.ts @@ -109,7 +109,7 @@ export async function build ({ watch, adapter = BUILD_TYPES.WEAPP }: IMiniAppBui const appConfig = await buildEntry() setAppConfig(appConfig) await buildPages() - if (watch) { - watchFiles() - } + // if (watch) { + // watchFiles() + // } } diff --git a/packages/taro-cli/src/quick/astProcess.ts b/packages/taro-cli/src/quick/astProcess.ts index 7069e4e3556f..5a10381b89d7 100644 --- a/packages/taro-cli/src/quick/astProcess.ts +++ b/packages/taro-cli/src/quick/astProcess.ts @@ -8,10 +8,175 @@ import traverse from 'babel-traverse' import _ from 'lodash' import { Config as IConfig } from '@tarojs/taro' -import { PARSE_AST_TYPE, taroJsComponents, taroJsQuickAppComponents } from '../util/constants' -import { getBuildData, isQuickAppPkg } from './helper' -import { getNotExistNpmList } from '../util/npmExact' -import { traverseObjectNode, isAliasPath, replaceAliasPath, isNpmPkg } from '../util' +const template = require('babel-template') + +import { + PARSE_AST_TYPE, + taroJsComponents, + taroJsQuickAppComponents, + taroJsFramework, + CSS_EXT, + processTypeEnum, + REG_SCRIPT, + REG_TYPESCRIPT, + REG_JSON, + REG_FONT, + REG_IMAGE, + REG_MEDIA, + NODE_MODULES_REG, + REG_STYLE, + taroJsRedux, + DEVICE_RATIO_NAME, + BUILD_TYPES +} from '../util/constants' +import babylonConfig from '../config/babylon' +import { getNotExistNpmList, getExactedNpmFilePath } from '../util/npmExact' +import { + traverseObjectNode, + isAliasPath, + replaceAliasPath, + isNpmPkg, + printLog, + resolveScriptPath, + promoteRelativePath +} from '../util' +import { convertArrayToAstExpression, convertObjectToAstExpression } from '../util/astConvert' +import { getBuildData, isQuickAppPkg, isFileToBePage } from './helper' + +interface IAnalyzeImportUrlOptions { + astPath: any, + value: string, + sourceFilePath: string, + filePath: string, + styleFiles: string[], + scriptFiles: string[], + jsonFiles: string[], + mediaFiles: string[] +} + +function analyzeImportUrl ({ + astPath, + value, + sourceFilePath, + filePath, + styleFiles, + scriptFiles, + jsonFiles, + mediaFiles +}: IAnalyzeImportUrlOptions): void { + const valueExtname = path.extname(value) + const node = astPath.node + const { + nodeModulesPath, + npmOutputDir, + sourceDir, + outputDir + } = getBuildData() + if (value.indexOf('.') === 0) { + let importPath = path.resolve(path.dirname(sourceFilePath), value) + importPath = resolveScriptPath(importPath) + if (isFileToBePage(importPath)) { + astPath.remove() + } else { + if (REG_SCRIPT.test(valueExtname) || REG_TYPESCRIPT.test(valueExtname)) { + const vpath = path.resolve(sourceFilePath, '..', value) + let fPath = value + if (fs.existsSync(vpath) && vpath !== sourceFilePath) { + fPath = vpath + } + if (scriptFiles.indexOf(fPath) < 0) { + scriptFiles.push(fPath) + } + } else if (REG_JSON.test(valueExtname)) { + const vpath = path.resolve(sourceFilePath, '..', value) + if (jsonFiles.indexOf(vpath) < 0) { + jsonFiles.push(vpath) + } + if (fs.existsSync(vpath)) { + const obj = JSON.parse(fs.readFileSync(vpath).toString()) + const specifiers = node.specifiers + let defaultSpecifier = null + specifiers.forEach(item => { + if (item.type === 'ImportDefaultSpecifier') { + defaultSpecifier = item.local.name + } + }) + if (defaultSpecifier) { + let objArr: t.NullLiteral | t.Expression = t.nullLiteral() + if (Array.isArray(obj)) { + objArr = t.arrayExpression(convertArrayToAstExpression(obj)) + } else { + objArr = t.objectExpression(convertObjectToAstExpression(obj)) + } + astPath.replaceWith(t.variableDeclaration('const', [t.variableDeclarator(t.identifier(defaultSpecifier), objArr)])) + } + } + } else if (REG_FONT.test(valueExtname) || REG_IMAGE.test(valueExtname) || REG_MEDIA.test(valueExtname)) { + const vpath = path.resolve(sourceFilePath, '..', value) + if (!fs.existsSync(vpath)) { + printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 不存在!`) + return + } + if (mediaFiles.indexOf(vpath) < 0) { + mediaFiles.push(vpath) + } + const specifiers = node.specifiers + let defaultSpecifier = null + specifiers.forEach(item => { + if (item.type === 'ImportDefaultSpecifier') { + defaultSpecifier = item.local.name + } + }) + let sourceDirPath = sourceDir + if (NODE_MODULES_REG.test(vpath)) { + sourceDirPath = nodeModulesPath + } + + if (defaultSpecifier) { + astPath.replaceWith(t.variableDeclaration('const', [t.variableDeclarator(t.identifier(defaultSpecifier), t.stringLiteral(vpath.replace(sourceDirPath, '').replace(/\\/g, '/')))])) + } else { + astPath.remove() + } + } else if (REG_STYLE.test(valueExtname)) { + const stylePath = path.resolve(path.dirname(sourceFilePath), value) + if (styleFiles.indexOf(stylePath) < 0) { + styleFiles.push(stylePath) + } + astPath.remove() + } else { + let vpath = resolveScriptPath(path.resolve(sourceFilePath, '..', value)) + let outputVpath + if (NODE_MODULES_REG.test(vpath)) { + outputVpath = vpath.replace(nodeModulesPath, npmOutputDir) + } else { + outputVpath = vpath.replace(sourceDir, outputDir) + } + let relativePath = path.relative(filePath, outputVpath) + if (vpath && vpath !== sourceFilePath) { + if (!fs.existsSync(vpath)) { + printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 不存在!`) + } else { + if (fs.lstatSync(vpath).isDirectory()) { + if (fs.existsSync(path.join(vpath, 'index.js'))) { + vpath = path.join(vpath, 'index.js') + relativePath = path.join(relativePath, 'index.js') + } else { + printLog(processTypeEnum.ERROR, '引用目录', `文件 ${sourceFilePath} 中引用了目录 ${value}!`) + return + } + } + if (scriptFiles.indexOf(vpath) < 0) { + scriptFiles.push(vpath) + } + relativePath = promoteRelativePath(relativePath) + relativePath = relativePath.replace(path.extname(relativePath), '.js') + node.source.value = relativePath + } + } + } + } + } +} export function parseAst ( type: PARSE_AST_TYPE, @@ -39,9 +204,12 @@ export function parseAst ( } = getBuildData() const notExistNpmList = getNotExistNpmList() const taroMiniAppFramework = `@tarojs/taro-${buildAdapter}` + let taroImportDefaultName let needExportDefault = false let configObj: IConfig = {} + let taroJsReduxConnect: string = '' let componentClassName: string = '' + let exportTaroReduxConnected: string | null = null ast = babel.transformFromAst(ast, '', { plugins: [ [require('babel-plugin-danger-remove-unused-import'), { ignore: ['@tarojs/taro', 'react', 'nervjs'] }], @@ -178,8 +346,324 @@ export function parseAst ( && !notExistNpmList.has(value)) { if (value === taroJsComponents) { source.value = taroJsQuickAppComponents + value = taroJsQuickAppComponents + } else if (value === taroJsFramework) { + let defaultSpecifier: string | null = null + specifiers.forEach(item => { + if (item.type === 'ImportDefaultSpecifier') { + defaultSpecifier = item.local.name + } + }) + if (defaultSpecifier) { + taroImportDefaultName = defaultSpecifier + } + value = taroMiniAppFramework + } else if (value === taroJsRedux) { + specifiers.forEach(item => { + if (item.type === 'ImportSpecifier') { + const local = item.local + if (local.type === 'Identifier' && local.name === 'connect') { + taroJsReduxConnect = item.imported.name + } + } + }) + } + if (!npmSkip) { + source.value = getExactedNpmFilePath({ + npmName: value, + filePath, + isProduction, + npmConfig, + buildAdapter, + npmOutputDir, + compileInclude: [] + }) + } else { + source.value = value } + } else if (CSS_EXT.indexOf(path.extname(value)) !== -1 && specifiers.length > 0) { // 对 使用 import style from './style.css' 语法引入的做转化处理 + } else if (path.isAbsolute(value)) { + printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 是绝对路径!`) + } + }, + + CallExpression (astPath) { + const node = astPath.node + const callee = node.callee as (t.Identifier | t.MemberExpression) + if (t.isMemberExpression(callee)) { + if (taroImportDefaultName && (callee.object as t.Identifier).name === taroImportDefaultName && (callee.property as t.Identifier).name === 'render') { + astPath.remove() + } + } else if (callee.name === 'require') { + const args = node.arguments as t.StringLiteral[] + let value = args[0].value + if (isAliasPath(value, pathAlias)) { + value = replaceAliasPath(sourceFilePath, value, pathAlias) + args[0].value = value + } + if (isNpmPkg(value) + && !isQuickAppPkg(value) + && !notExistNpmList.has(value)) { + if (value === taroJsComponents) { + args[0].value = taroJsQuickAppComponents + value = taroJsQuickAppComponents + } else if (t.isVariableDeclaration(astPath.parentPath.parentPath)) { + const parentNode = astPath.parentPath.parentPath.node as t.VariableDeclaration + if (parentNode.declarations.length === 1 && parentNode.declarations[0].init) { + const id = parentNode.declarations[0].id + if (value === taroJsFramework && id.type === 'Identifier') { + taroImportDefaultName = id.name + value = taroMiniAppFramework + } else if (value === taroJsRedux) { + const declarations = parentNode.declarations + declarations.forEach(item => { + const id = item.id + if (id.type === 'ObjectPattern') { + const properties = id.properties as any + properties.forEach(p => { + if (p.type === 'ObjectProperty') { + if (p.value.type === 'Identifier' && p.value.name === 'connect') { + taroJsReduxConnect = p.key.name + } + } + }) + } + }) + } + } + } + if (!npmSkip) { + args[0].value = getExactedNpmFilePath({ + npmName: value, + filePath, + isProduction, + npmConfig, + buildAdapter, + npmOutputDir, + compileInclude: [] + }) + } else { + args[0].value = value + } + } else if (CSS_EXT.indexOf(path.extname(value)) !== -1 && t.isVariableDeclarator(astPath.parentPath)) { // 对 使用 const style = require('./style.css') 语法引入的做转化处理 + + } else if (path.isAbsolute(value)) { + printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 是绝对路径!`) + } + } + }, + + ExportDefaultDeclaration (astPath) { + const node = astPath.node + const declaration = node.declaration + needExportDefault = false + if ( + declaration && + (declaration.type === 'ClassDeclaration' || declaration.type === 'ClassExpression') + ) { + const superClass = declaration.superClass + if (superClass) { + let hasCreateData = false + astPath.traverse({ + ClassMethod (astPath) { + if (astPath.get('key').isIdentifier({ name: '_createData' })) { + hasCreateData = true + } + } + }) + if (hasCreateData) { + needExportDefault = true + if (declaration.id === null) { + componentClassName = '_TaroComponentClass' + } else if (declaration.id.name === 'App') { + componentClassName = '_App' + } else { + componentClassName = declaration.id.name + } + const isClassDcl = declaration.type === 'ClassDeclaration' + const classDclProps = [t.identifier(componentClassName), superClass, declaration.body, declaration.decorators || []] + astPath.replaceWith(isClassDcl ? t.classDeclaration.apply(null, classDclProps) : t.classExpression.apply(null, classDclProps)) + } + } + } else if (declaration.type === 'CallExpression') { + const callee = declaration.callee + if (callee && callee.type === 'CallExpression') { + const subCallee = callee.callee + if (subCallee.type === 'Identifier' && subCallee.name === taroJsReduxConnect) { + const args = declaration.arguments as t.Identifier[] + if (args.length === 1 && args[0].name === componentClassName) { + needExportDefault = true + exportTaroReduxConnected = `${componentClassName}__Connected` + astPath.replaceWith(t.variableDeclaration('const', [t.variableDeclarator(t.identifier(`${componentClassName}__Connected`), t.callExpression(declaration.callee as t.Expression, declaration.arguments as Array))])) + } + } + } + } + }, + + ExportNamedDeclaration (astPath) { + const node = astPath.node + const source = node.source + if (source && source.type === 'StringLiteral') { + const value = source.value + analyzeImportUrl({ astPath, value, sourceFilePath, filePath, styleFiles, scriptFiles, jsonFiles, mediaFiles }) + } + }, + + ExportAllDeclaration (astPath) { + const node = astPath.node + const source = node.source + if (source && source.type === 'StringLiteral') { + const value = source.value + analyzeImportUrl({ astPath, value, sourceFilePath, filePath, styleFiles, scriptFiles, jsonFiles, mediaFiles }) + } + }, + Program: { + exit (astPath) { + astPath.traverse({ + ImportDeclaration (astPath) { + const node = astPath.node + const source = node.source + const value = source.value + analyzeImportUrl({ astPath, value, sourceFilePath, filePath, styleFiles, scriptFiles, jsonFiles, mediaFiles }) + }, + CallExpression (astPath) { + const node = astPath.node + const callee = node.callee as t.Identifier + if (callee.name === 'require') { + const args = node.arguments as t.StringLiteral[] + const value = args[0].value + const valueExtname = path.extname(value) + if (value.indexOf('.') === 0) { + let importPath = path.resolve(path.dirname(sourceFilePath), value) + importPath = resolveScriptPath(importPath) + if (isFileToBePage(importPath)) { + if (astPath.parent.type === 'AssignmentExpression' || 'ExpressionStatement') { + astPath.parentPath.remove() + } else if (astPath.parent.type === 'VariableDeclarator') { + astPath.parentPath.parentPath.remove() + } else { + astPath.remove() + } + } else { + if (REG_STYLE.test(valueExtname)) { + const stylePath = path.resolve(path.dirname(sourceFilePath), value) + if (styleFiles.indexOf(stylePath) < 0) { + styleFiles.push(stylePath) + } + if (astPath.parent.type === 'AssignmentExpression' || 'ExpressionStatement') { + astPath.parentPath.remove() + } else if (astPath.parent.type === 'VariableDeclarator') { + astPath.parentPath.parentPath.remove() + } else { + astPath.remove() + } + } else if (REG_JSON.test(valueExtname)) { + const vpath = path.resolve(sourceFilePath, '..', value) + if (jsonFiles.indexOf(vpath) < 0) { + jsonFiles.push(vpath) + } + if (fs.existsSync(vpath)) { + const obj = JSON.parse(fs.readFileSync(vpath).toString()) + let objArr: t.NullLiteral | t.Expression = t.nullLiteral() + if (Array.isArray(obj)) { + objArr = t.arrayExpression(convertArrayToAstExpression(obj)) + } else { + objArr = t.objectExpression(convertObjectToAstExpression(obj)) + } + astPath.replaceWith(t.objectExpression(objArr as any)) + } + } else if (REG_SCRIPT.test(valueExtname) || REG_TYPESCRIPT.test(valueExtname)) { + const vpath = path.resolve(sourceFilePath, '..', value) + let fPath = value + if (fs.existsSync(vpath) && vpath !== sourceFilePath) { + fPath = vpath + } + if (scriptFiles.indexOf(fPath) < 0) { + scriptFiles.push(fPath) + } + } else if (REG_FONT.test(valueExtname) || REG_IMAGE.test(valueExtname) || REG_MEDIA.test(valueExtname)) { + const vpath = path.resolve(sourceFilePath, '..', value) + if (mediaFiles.indexOf(vpath) < 0) { + mediaFiles.push(vpath) + } + let sourceDirPath = sourceDir + if (NODE_MODULES_REG.test(vpath)) { + sourceDirPath = nodeModulesPath + } + astPath.replaceWith(t.stringLiteral(vpath.replace(sourceDirPath, '').replace(/\\/g, '/'))) + } else { + let vpath = resolveScriptPath(path.resolve(sourceFilePath, '..', value)) + let outputVpath + if (NODE_MODULES_REG.test(vpath)) { + outputVpath = vpath.replace(nodeModulesPath, npmOutputDir) + } else { + outputVpath = vpath.replace(sourceDir, outputDir) + } + let relativePath = path.relative(filePath, outputVpath) + if (vpath) { + if (!fs.existsSync(vpath)) { + printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 不存在!`) + } else { + if (fs.lstatSync(vpath).isDirectory()) { + if (fs.existsSync(path.join(vpath, 'index.js'))) { + vpath = path.join(vpath, 'index.js') + relativePath = path.join(relativePath, 'index.js') + } else { + printLog(processTypeEnum.ERROR, '引用目录', `文件 ${sourceFilePath} 中引用了目录 ${value}!`) + return + } + } + if (scriptFiles.indexOf(vpath) < 0) { + scriptFiles.push(vpath) + } + relativePath = promoteRelativePath(relativePath) + relativePath = relativePath.replace(path.extname(relativePath), '.js') + args[0].value = relativePath + } + } + } + } + } + } + } + }) + const node = astPath.node as t.Program + const exportVariableName = exportTaroReduxConnected || componentClassName + if (needExportDefault) { + const exportDefault = template(`export default ${exportVariableName}`, babylonConfig as any)() + node.body.push(exportDefault as any) + } + const taroMiniAppFrameworkPath = !npmSkip ? getExactedNpmFilePath({ + npmName: taroMiniAppFramework, + filePath, + isProduction, + npmConfig, + buildAdapter, + npmOutputDir, + compileInclude: [] + }) : taroMiniAppFramework + switch (type) { + case PARSE_AST_TYPE.ENTRY: + const pxTransformConfig = { + designWidth: projectConfig.designWidth || 750 + } + if (projectConfig.hasOwnProperty(DEVICE_RATIO_NAME)) { + pxTransformConfig[DEVICE_RATIO_NAME] = projectConfig.deviceRatio + } + node.body.push(template(`export default require('${taroMiniAppFrameworkPath}').default.createApp(${exportVariableName})`, babylonConfig as any)() as any) + node.body.push(template(`Taro.initPxTransform(${JSON.stringify(pxTransformConfig)})`, babylonConfig as any)() as any) + break + case PARSE_AST_TYPE.PAGE: + node.body.push(template(`export default require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}, true)`, babylonConfig as any)() as any) + break + case PARSE_AST_TYPE.COMPONENT: + node.body.push(template(`export default require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName})`, babylonConfig as any)() as any) + break + default: + break + } } } }) diff --git a/packages/taro-cli/src/quick/entry.ts b/packages/taro-cli/src/quick/entry.ts index 151240a63bb0..4002e4516605 100644 --- a/packages/taro-cli/src/quick/entry.ts +++ b/packages/taro-cli/src/quick/entry.ts @@ -8,7 +8,7 @@ import { processTypeEnum, REG_TYPESCRIPT, PARSE_AST_TYPE } from '../util/constan import { printLog } from '../util' import { getBuildData, setAppConfig, getDependencyTree } from './helper' -import { parseAst } from './astProcess' +import { parseAst } from '../mini/astProcess' export async function buildEntry () { const { @@ -36,10 +36,10 @@ export async function buildEntry () { adapter: buildAdapter, env: constantsReplaceList }) - const { configObj, code } = parseAst(PARSE_AST_TYPE.ENTRY, transformResult.ast, entryFilePath, outputEntryFilePath) + const res = parseAst(PARSE_AST_TYPE.ENTRY, transformResult.ast, [], entryFilePath, outputEntryFilePath) const dependencyTree = getDependencyTree() - setAppConfig(configObj) - console.log(code) + setAppConfig(res.configObj) + console.log(res) } catch (err) { console.log(err) } diff --git a/packages/taro-cli/src/quick/helper.ts b/packages/taro-cli/src/quick/helper.ts index 41201f5c9b7a..0551389cf61a 100644 --- a/packages/taro-cli/src/quick/helper.ts +++ b/packages/taro-cli/src/quick/helper.ts @@ -5,7 +5,8 @@ import { AppConfig } from '@tarojs/taro' import { BUILD_TYPES, - PROJECT_CONFIG + PROJECT_CONFIG, + REG_SCRIPTS } from '../util/constants' import CONFIG from '../config' import { @@ -104,6 +105,17 @@ export function getDependencyTree (): Map { return dependencyTree } -export function isQuickAppPkg (name: string): boolean { - return /@system\./.test(name) +export function isFileToBePage (filePath: string): boolean { + let isPage = false + const { appConfig, sourceDir } = BuildData + const extname = path.extname(filePath) + const pages = appConfig.pages || [] + const filePathWithoutExt = filePath.replace(extname, '') + pages.forEach(page => { + if (filePathWithoutExt === path.join(sourceDir, page)) { + isPage = true + } + }) + return isPage && REG_SCRIPTS.test(extname) } + diff --git a/packages/taro-cli/src/quick/interface.ts b/packages/taro-cli/src/quick/interface.ts index db83f46215ee..8c9bd99c94b4 100644 --- a/packages/taro-cli/src/quick/interface.ts +++ b/packages/taro-cli/src/quick/interface.ts @@ -4,3 +4,9 @@ export interface IDependency { json: string[], media: string[] } + +export interface IComponentObj { + name?: string, + path: string | null, + type?: string +} diff --git a/packages/taro-cli/src/util/constants.ts b/packages/taro-cli/src/util/constants.ts index 3540b4b013fa..67f727d5c632 100644 --- a/packages/taro-cli/src/util/constants.ts +++ b/packages/taro-cli/src/util/constants.ts @@ -105,28 +105,32 @@ export const enum TEMPLATE_TYPES { WEAPP = '.wxml', SWAN = '.swan', ALIPAY = '.axml', - TT = '.ttml' + TT = '.ttml', + QUICKAPP = '.ux' } export const enum STYLE_TYPES { WEAPP = '.wxss', SWAN = '.css', ALIPAY = '.acss', - TT = '.ttss' + TT = '.ttss', + QUICKAPP = '.css' } export const enum SCRIPT_TYPES { WEAPP = '.js', SWAN = '.js', ALIPAY = '.js', - TT = '.js' + TT = '.js', + QUICKAPP = '.js' } export const enum CONFIG_TYPES { WEAPP = '.json', SWAN = '.json', ALIPAY = '.json', - TT = '.json' + TT = '.json', + QUICKAPP = '.json' } export type IMINI_APP_FILE_TYPE = { @@ -163,6 +167,12 @@ export const MINI_APP_FILES: IMINI_APP_FILES = { STYLE: STYLE_TYPES.TT, SCRIPT: SCRIPT_TYPES.TT, CONFIG: CONFIG_TYPES.TT + }, + [BUILD_TYPES.QUICKAPP]: { + TEMPL: TEMPLATE_TYPES.QUICKAPP, + STYLE: STYLE_TYPES.QUICKAPP, + SCRIPT: SCRIPT_TYPES.QUICKAPP, + CONFIG: CONFIG_TYPES.QUICKAPP } } diff --git a/packages/taro-cli/src/util/index.ts b/packages/taro-cli/src/util/index.ts index 9f5cce9ba7e0..566591b4f63e 100644 --- a/packages/taro-cli/src/util/index.ts +++ b/packages/taro-cli/src/util/index.ts @@ -17,7 +17,8 @@ import { processTypeEnum, MINI_APP_FILES, BUILD_TYPES, - CONFIG_MAP + CONFIG_MAP, + REG_STYLE } from './constants' import { ICopyArgOptions, ICopyOptions } from './types' @@ -482,3 +483,33 @@ export function copyFiles (appPath: string, copyConfig: ICopyOptions | void) { }) } } + +export function isQuickAppPkg (name: string): boolean { + return /@system\./.test(name) +} + +export function generateQuickAppUx ({ + script, + template, + style +}: { + script?: string, + template?: string, + style?: string +}) { + let uxTxt = '' + if (style) { + if (REG_STYLE.test(style)) { + uxTxt += `\n` + } else { + uxTxt += `\n` + } + } + if (template) { + uxTxt += `\n` + } + if (script) { + uxTxt += `\n` + } + return uxTxt +} diff --git a/packages/taro-cli/src/util/npm.ts b/packages/taro-cli/src/util/npm.ts index accb12051e75..96c5abaa6c17 100644 --- a/packages/taro-cli/src/util/npm.ts +++ b/packages/taro-cli/src/util/npm.ts @@ -43,17 +43,18 @@ export function resolveNpmSync (pluginName: string): string { } return npmCached[pluginName] } catch (err) { - if (err.code === 'MODULE_NOT_FOUND') { - console.log(chalk.cyan(`缺少npm包${pluginName},开始安装...`)) - const installOptions: IInstallOptions = { - dev: false - } - if (pluginName.indexOf(taroPluginPrefix) >= 0) { - installOptions.dev = true - } - installNpmPkg(pluginName, installOptions) - return resolveNpmSync(pluginName) - } + console.log(err) + // if (err.code === 'MODULE_NOT_FOUND') { + // console.log(chalk.cyan(`缺少npm包${pluginName},开始安装...`)) + // const installOptions: IInstallOptions = { + // dev: false + // } + // if (pluginName.indexOf(taroPluginPrefix) >= 0) { + // installOptions.dev = true + // } + // installNpmPkg(pluginName, installOptions) + // return resolveNpmSync(pluginName) + // } return '' } } diff --git a/packages/taro-cli/src/util/resolve_npm_files.ts b/packages/taro-cli/src/util/resolve_npm_files.ts index 0bba2c0698b0..39707027d8a7 100644 --- a/packages/taro-cli/src/util/resolve_npm_files.ts +++ b/packages/taro-cli/src/util/resolve_npm_files.ts @@ -13,7 +13,8 @@ import { promoteRelativePath, printLog, recursiveFindNodeModules, - generateEnvList + generateEnvList, + isQuickAppPkg } from './index' import { @@ -138,6 +139,9 @@ function parseAst ( const args = node.arguments as Array let requirePath = args[0].value if (excludeRequire.indexOf(requirePath) < 0) { + if (!isQuickAppPkg(requirePath)) { + return + } if (isNpmPkg(requirePath)) { if (excludeNpmPkgs.indexOf(requirePath) < 0) { const res = resolveNpmFilesPath(requirePath, isProduction, npmConfig, buildAdapter, path.dirname(recursiveFindNodeModules(filePath)), compileInclude) diff --git a/packages/taro-components-qa/src/components/button.js/img.js b/packages/taro-components-qa/src/components/button/img.js similarity index 100% rename from packages/taro-components-qa/src/components/button.js/img.js rename to packages/taro-components-qa/src/components/button/img.js diff --git a/packages/taro-components-qa/src/components/button.js/index.ux b/packages/taro-components-qa/src/components/button/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/button.js/index.ux rename to packages/taro-components-qa/src/components/button/index.ux From 4752c29af9e2797c5db96dfb2657646a5c1985e1 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Thu, 14 Mar 2019 21:41:18 +0800 Subject: [PATCH 041/103] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E5=BF=AB?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E5=85=A5=E5=8F=A3=E6=96=87=E4=BB=B6=E5=8F=8A?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E7=BC=96=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/src/mini/astProcess.ts | 36 +- packages/taro-cli/src/mini/entry.ts | 1 + packages/taro-cli/src/mini/page.ts | 146 +++-- packages/taro-cli/src/quick/astProcess.ts | 679 ---------------------- packages/taro-cli/src/quick/constants.ts | 1 - packages/taro-cli/src/quick/entry.ts | 46 -- packages/taro-cli/src/quick/helper.ts | 121 ---- packages/taro-cli/src/quick/index.ts | 22 - packages/taro-cli/src/quick/interface.ts | 12 - packages/taro-cli/src/util/index.ts | 28 +- 10 files changed, 140 insertions(+), 952 deletions(-) delete mode 100644 packages/taro-cli/src/quick/astProcess.ts delete mode 100644 packages/taro-cli/src/quick/constants.ts delete mode 100644 packages/taro-cli/src/quick/entry.ts delete mode 100644 packages/taro-cli/src/quick/helper.ts delete mode 100644 packages/taro-cli/src/quick/index.ts delete mode 100644 packages/taro-cli/src/quick/interface.ts diff --git a/packages/taro-cli/src/mini/astProcess.ts b/packages/taro-cli/src/mini/astProcess.ts index 3de26a8d8a35..d3637d62de1a 100644 --- a/packages/taro-cli/src/mini/astProcess.ts +++ b/packages/taro-cli/src/mini/astProcess.ts @@ -5,7 +5,7 @@ import * as babel from 'babel-core' import * as t from 'babel-types' import generate from 'babel-generator' import traverse from 'babel-traverse' -import _ from 'lodash' +import * as _ from 'lodash' import { Config as IConfig } from '@tarojs/taro' const template = require('babel-template') @@ -26,8 +26,7 @@ import { taroJsComponents, taroJsRedux, taroJsFramework, - DEVICE_RATIO_NAME, - taroJsQuickAppComponents + DEVICE_RATIO_NAME } from '../util/constants' import { resolveScriptPath, @@ -192,7 +191,8 @@ export interface IParseAstReturn { jsonFiles: string[], mediaFiles: string[] configObj: IConfig, - componentClassName: string + componentClassName: string, + taroSelfComponents: Set } export function parseAst ( @@ -234,6 +234,7 @@ export function parseAst ( if (isQuickApp) { cannotRemoves.push(taroJsComponents) } + const taroSelfComponents = new Set() ast = babel.transformFromAst(ast, '', { plugins: [ [require('babel-plugin-danger-remove-unused-import'), { ignore: cannotRemoves }], @@ -369,7 +370,9 @@ export function parseAst ( if (isNpmPkg(value) && !isQuickAppPkg(value) && !notExistNpmList.has(value)) { if (value === taroJsComponents) { if (isQuickApp) { - console.log(specifiers) + specifiers.forEach(specifier => { + taroSelfComponents.add(_.kebabCase(specifier.local.name)) + }) } astPath.remove() } else { @@ -472,6 +475,7 @@ export function parseAst ( } else if (callee.name === 'require') { const args = node.arguments as t.StringLiteral[] let value = args[0].value + const parentNode = astPath.parentPath.parentPath.node as t.VariableDeclaration if (isAliasPath(value, pathAlias)) { value = replaceAliasPath(sourceFilePath, value, pathAlias) args[0].value = value @@ -479,11 +483,21 @@ export function parseAst ( if (isNpmPkg(value) && !isQuickAppPkg(value) && !notExistNpmList.has(value)) { if (value === taroJsComponents) { if (buildAdapter === BUILD_TYPES.QUICKAPP) { - args[0].value = taroJsQuickAppComponents - value = taroJsQuickAppComponents - } else { - astPath.remove() + if (isQuickApp) { + if (parentNode.declarations.length === 1 && parentNode.declarations[0].init) { + const id = parentNode.declarations[0].id + if (id.type === 'ObjectPattern') { + const properties = id.properties as any + properties.forEach(p => { + if (p.type === 'ObjectProperty' && p.value.type === 'Identifier') { + taroSelfComponents.add(_.kebabCase(p.value.name)) + } + }) + } + } + } } + astPath.remove() } else { let isDepComponent = false if (depComponents && depComponents.length) { @@ -497,7 +511,6 @@ export function parseAst ( astPath.remove() } else { if (t.isVariableDeclaration(astPath.parentPath.parentPath)) { - const parentNode = astPath.parentPath.parentPath.node as t.VariableDeclaration if (parentNode.declarations.length === 1 && parentNode.declarations[0].init) { const id = parentNode.declarations[0].id if (value === taroJsFramework && id.type === 'Identifier') { @@ -796,7 +809,8 @@ export function parseAst ( jsonFiles, configObj, mediaFiles, - componentClassName + componentClassName, + taroSelfComponents } } diff --git a/packages/taro-cli/src/mini/entry.ts b/packages/taro-cli/src/mini/entry.ts index 6b43014e791b..55c63a21d640 100644 --- a/packages/taro-cli/src/mini/entry.ts +++ b/packages/taro-cli/src/mini/entry.ts @@ -153,6 +153,7 @@ export async function buildEntry (): Promise { style: styleRelativePath }) fs.writeFileSync(path.join(outputDir, `app${outputFilesTypes.TEMPL}`), uxTxt) + printLog(processTypeEnum.GENERATE, '入口文件', `${outputDirName}/app${outputFilesTypes.TEMPL}`) } else { if (res.configObj.workers) { buildWorkers(res.configObj.workers) diff --git a/packages/taro-cli/src/mini/page.ts b/packages/taro-cli/src/mini/page.ts index 9adad91d1915..1b072a8d1b2d 100644 --- a/packages/taro-cli/src/mini/page.ts +++ b/packages/taro-cli/src/mini/page.ts @@ -10,7 +10,9 @@ import { processTypeEnum, NODE_MODULES_REG, PARSE_AST_TYPE, - taroJsFramework + taroJsFramework, + BUILD_TYPES, + taroJsQuickAppComponents } from '../util/constants' import { resolveScriptPath, @@ -18,7 +20,9 @@ import { isEmptyObject, promoteRelativePath, isDifferentArray, - copyFileSync + copyFileSync, + getInstalledNpmPkgPath, + generateQuickAppUx } from '../util' import { IWxTransformResult } from '../util/types' @@ -57,6 +61,7 @@ export async function buildSinglePage (page: string) { const pageJs = resolveScriptPath(pagePath) const dependencyTree = getDependencyTree() const depComponents = getDepComponents() + const isQuickApp = buildAdapter === BUILD_TYPES.QUICKAPP printLog(processTypeEnum.COMPILE, '页面文件', `${sourceDirName}/${page}`) if (!fs.existsSync(pageJs)) { @@ -100,11 +105,8 @@ export async function buildSinglePage (page: string) { const pageWXMLContent = isProduction ? transformResult.compressedTemplate : transformResult.template const res = parseAst(PARSE_AST_TYPE.PAGE, transformResult.ast, pageDepComponents, pageJs, outputPageJSPath) let resCode = res.code - resCode = await compileScriptFile(resCode, pageJs, outputPageJSPath, buildAdapter) - if (isProduction) { - uglifyJS(resCode, pageJs) - } fs.ensureDirSync(outputPagePath) + // 解析原生组件 const { usingComponents = {} }: IConfig = res.configObj if (usingComponents && !isEmptyObject(usingComponents)) { const keys = Object.keys(usingComponents) @@ -118,56 +120,18 @@ export async function buildSinglePage (page: string) { transfromNativeComponents(outputPageJSONPath.replace(outputDir, sourceDir), res.configObj) } const fileDep = dependencyTree.get(pageJs) || {} - // 编译依赖的组件文件 - let realComponentsPathList: IComponentObj[] = [] - if (pageDepComponents.length) { - realComponentsPathList = getRealComponentsPathList(pageJs, pageDepComponents) - res.scriptFiles = res.scriptFiles.map(item => { - for (let i = 0; i < realComponentsPathList.length; i++) { - const componentObj = realComponentsPathList[i] - const componentPath = componentObj.path - if (item === componentPath) { - return '' - } - } - return item - }).filter(item => item) - await buildDepComponents(realComponentsPathList) - } - const componentExportsMap = getComponentExportsMap() - if (!isEmptyObject(componentExportsMap) && realComponentsPathList.length) { - const mapKeys = Object.keys(componentExportsMap) - realComponentsPathList.forEach(component => { - if (mapKeys.indexOf(component.path as string) >= 0) { - const componentMap = componentExportsMap.get(component.path as string) - componentMap && componentMap.forEach(component => { - pageDepComponents.forEach(depComponent => { - if (depComponent.name === component.name) { - let componentPath = component.path - let realPath - if (NODE_MODULES_REG.test(componentPath as string)) { - componentPath = (componentPath as string).replace(nodeModulesPath, npmOutputDir) - realPath = promoteRelativePath(path.relative(outputPageJSPath, componentPath)) - } else { - realPath = promoteRelativePath(path.relative(pageJs, componentPath as string)) - } - depComponent.path = realPath.replace(path.extname(realPath), '') - } - }) - }) - } - }) + if (!isQuickApp) { + fs.writeFileSync(outputPageJSONPath, JSON.stringify(_.merge({}, buildUsingComponents(pageJs, pageDepComponents), res.configObj), null, 2)) + printLog(processTypeEnum.GENERATE, '页面配置', `${outputDirName}/${page}${outputFilesTypes.CONFIG}`) + fs.writeFileSync(outputPageJSPath, resCode) + printLog(processTypeEnum.GENERATE, '页面逻辑', `${outputDirName}/${page}${outputFilesTypes.SCRIPT}`) + fs.writeFileSync(outputPageWXMLPath, pageWXMLContent) + processNativeWxml(outputPageWXMLPath.replace(outputDir, sourceDir), pageWXMLContent, outputPageWXMLPath) + printLog(processTypeEnum.GENERATE, '页面模板', `${outputDirName}/${page}${outputFilesTypes.TEMPL}`) } - fs.writeFileSync(outputPageJSONPath, JSON.stringify(_.merge({}, buildUsingComponents(pageJs, pageDepComponents), res.configObj), null, 2)) - printLog(processTypeEnum.GENERATE, '页面配置', `${outputDirName}/${page}${outputFilesTypes.CONFIG}`) - fs.writeFileSync(outputPageJSPath, resCode) - printLog(processTypeEnum.GENERATE, '页面逻辑', `${outputDirName}/${page}${outputFilesTypes.SCRIPT}`) - fs.writeFileSync(outputPageWXMLPath, pageWXMLContent) - processNativeWxml(outputPageWXMLPath.replace(outputDir, sourceDir), pageWXMLContent, outputPageWXMLPath) - printLog(processTypeEnum.GENERATE, '页面模板', `${outputDirName}/${page}${outputFilesTypes.TEMPL}`) // 编译依赖的脚本文件 if (isDifferentArray(fileDep['script'], res.scriptFiles)) { - compileDepScripts(res.scriptFiles) + compileDepScripts(res.scriptFiles, buildAdapter !== BUILD_TYPES.QUICKAPP) } // 编译样式文件 if (isDifferentArray(fileDep['style'], res.styleFiles) || isDifferentArray(depComponents.get(pageJs) || [], pageDepComponents)) { @@ -181,12 +145,86 @@ export async function buildSinglePage (page: string) { if (isDifferentArray(fileDep['media'], res.mediaFiles)) { copyFilesFromSrcToOutput(res.mediaFiles) } - depComponents.set(pageJs, pageDepComponents) fileDep['style'] = res.styleFiles fileDep['script'] = res.scriptFiles fileDep['json'] = res.jsonFiles fileDep['media'] = res.mediaFiles dependencyTree[pageJs] = fileDep + if (!isQuickApp) { + resCode = await compileScriptFile(resCode, pageJs, outputPageJSPath, buildAdapter) + if (isProduction) { + uglifyJS(resCode, pageJs) + } + // 编译依赖的组件文件 + let realComponentsPathList: IComponentObj[] = [] + if (pageDepComponents.length) { + realComponentsPathList = getRealComponentsPathList(pageJs, pageDepComponents) + res.scriptFiles = res.scriptFiles.map(item => { + for (let i = 0; i < realComponentsPathList.length; i++) { + const componentObj = realComponentsPathList[i] + const componentPath = componentObj.path + if (item === componentPath) { + return '' + } + } + return item + }).filter(item => item) + await buildDepComponents(realComponentsPathList) + } + const componentExportsMap = getComponentExportsMap() + if (!isEmptyObject(componentExportsMap) && realComponentsPathList.length) { + const mapKeys = Object.keys(componentExportsMap) + realComponentsPathList.forEach(component => { + if (mapKeys.indexOf(component.path as string) >= 0) { + const componentMap = componentExportsMap.get(component.path as string) + componentMap && componentMap.forEach(component => { + pageDepComponents.forEach(depComponent => { + if (depComponent.name === component.name) { + let componentPath = component.path + let realPath + if (NODE_MODULES_REG.test(componentPath as string)) { + componentPath = (componentPath as string).replace(nodeModulesPath, npmOutputDir) + realPath = promoteRelativePath(path.relative(outputPageJSPath, componentPath)) + } else { + realPath = promoteRelativePath(path.relative(pageJs, componentPath as string)) + } + depComponent.path = realPath.replace(path.extname(realPath), '') + } + }) + }) + } + }) + } + depComponents.set(pageJs, pageDepComponents) + } else { + // 快应用编译,搜集创建页面 ux 文件 + const importTaroSelfComponents = new Set<{ path: string, name: string }>() + const taroJsQuickAppComponentsPkg = getInstalledNpmPkgPath(taroJsQuickAppComponents, nodeModulesPath) + if (!taroJsQuickAppComponentsPkg) { + printLog(processTypeEnum.ERROR, '包安装', `缺少包 ${taroJsQuickAppComponents},请安装!`) + process.exit(0) + } + const taroJsQuickAppComponentsPath = path.join(path.dirname(taroJsQuickAppComponentsPkg as string), 'src/components') + res.taroSelfComponents.forEach(c => { + const cPath = path.join(taroJsQuickAppComponentsPath, c, 'index') + const cRelativePath = promoteRelativePath(path.relative(outputPageJSPath, cPath.replace(nodeModulesPath, npmOutputDir))) + importTaroSelfComponents.add({ + path: cRelativePath, + name: c + }) + }) + // 快应用编译组件 + // TODO + const styleRelativePath = promoteRelativePath(path.relative(outputPageJSPath, outputPageWXSSPath)) + const uxTxt = generateQuickAppUx({ + script: resCode, + style: styleRelativePath, + imports: importTaroSelfComponents, + template: pageWXMLContent + }) + fs.writeFileSync(outputPageWXMLPath, uxTxt) + printLog(processTypeEnum.GENERATE, '页面文件', `${outputDirName}/${page}${outputFilesTypes.TEMPL}`) + } } catch (err) { printLog(processTypeEnum.ERROR, '页面编译', `页面${pagePath}编译失败!`) console.log(err) diff --git a/packages/taro-cli/src/quick/astProcess.ts b/packages/taro-cli/src/quick/astProcess.ts deleted file mode 100644 index 5a10381b89d7..000000000000 --- a/packages/taro-cli/src/quick/astProcess.ts +++ /dev/null @@ -1,679 +0,0 @@ -import * as fs from 'fs-extra' -import * as path from 'path' - -import * as babel from 'babel-core' -import * as t from 'babel-types' -import generate from 'babel-generator' -import traverse from 'babel-traverse' -import _ from 'lodash' -import { Config as IConfig } from '@tarojs/taro' - -const template = require('babel-template') - -import { - PARSE_AST_TYPE, - taroJsComponents, - taroJsQuickAppComponents, - taroJsFramework, - CSS_EXT, - processTypeEnum, - REG_SCRIPT, - REG_TYPESCRIPT, - REG_JSON, - REG_FONT, - REG_IMAGE, - REG_MEDIA, - NODE_MODULES_REG, - REG_STYLE, - taroJsRedux, - DEVICE_RATIO_NAME, - BUILD_TYPES -} from '../util/constants' -import babylonConfig from '../config/babylon' -import { getNotExistNpmList, getExactedNpmFilePath } from '../util/npmExact' -import { - traverseObjectNode, - isAliasPath, - replaceAliasPath, - isNpmPkg, - printLog, - resolveScriptPath, - promoteRelativePath -} from '../util' -import { convertArrayToAstExpression, convertObjectToAstExpression } from '../util/astConvert' -import { getBuildData, isQuickAppPkg, isFileToBePage } from './helper' - -interface IAnalyzeImportUrlOptions { - astPath: any, - value: string, - sourceFilePath: string, - filePath: string, - styleFiles: string[], - scriptFiles: string[], - jsonFiles: string[], - mediaFiles: string[] -} - -function analyzeImportUrl ({ - astPath, - value, - sourceFilePath, - filePath, - styleFiles, - scriptFiles, - jsonFiles, - mediaFiles -}: IAnalyzeImportUrlOptions): void { - const valueExtname = path.extname(value) - const node = astPath.node - const { - nodeModulesPath, - npmOutputDir, - sourceDir, - outputDir - } = getBuildData() - if (value.indexOf('.') === 0) { - let importPath = path.resolve(path.dirname(sourceFilePath), value) - importPath = resolveScriptPath(importPath) - if (isFileToBePage(importPath)) { - astPath.remove() - } else { - if (REG_SCRIPT.test(valueExtname) || REG_TYPESCRIPT.test(valueExtname)) { - const vpath = path.resolve(sourceFilePath, '..', value) - let fPath = value - if (fs.existsSync(vpath) && vpath !== sourceFilePath) { - fPath = vpath - } - if (scriptFiles.indexOf(fPath) < 0) { - scriptFiles.push(fPath) - } - } else if (REG_JSON.test(valueExtname)) { - const vpath = path.resolve(sourceFilePath, '..', value) - if (jsonFiles.indexOf(vpath) < 0) { - jsonFiles.push(vpath) - } - if (fs.existsSync(vpath)) { - const obj = JSON.parse(fs.readFileSync(vpath).toString()) - const specifiers = node.specifiers - let defaultSpecifier = null - specifiers.forEach(item => { - if (item.type === 'ImportDefaultSpecifier') { - defaultSpecifier = item.local.name - } - }) - if (defaultSpecifier) { - let objArr: t.NullLiteral | t.Expression = t.nullLiteral() - if (Array.isArray(obj)) { - objArr = t.arrayExpression(convertArrayToAstExpression(obj)) - } else { - objArr = t.objectExpression(convertObjectToAstExpression(obj)) - } - astPath.replaceWith(t.variableDeclaration('const', [t.variableDeclarator(t.identifier(defaultSpecifier), objArr)])) - } - } - } else if (REG_FONT.test(valueExtname) || REG_IMAGE.test(valueExtname) || REG_MEDIA.test(valueExtname)) { - const vpath = path.resolve(sourceFilePath, '..', value) - if (!fs.existsSync(vpath)) { - printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 不存在!`) - return - } - if (mediaFiles.indexOf(vpath) < 0) { - mediaFiles.push(vpath) - } - const specifiers = node.specifiers - let defaultSpecifier = null - specifiers.forEach(item => { - if (item.type === 'ImportDefaultSpecifier') { - defaultSpecifier = item.local.name - } - }) - let sourceDirPath = sourceDir - if (NODE_MODULES_REG.test(vpath)) { - sourceDirPath = nodeModulesPath - } - - if (defaultSpecifier) { - astPath.replaceWith(t.variableDeclaration('const', [t.variableDeclarator(t.identifier(defaultSpecifier), t.stringLiteral(vpath.replace(sourceDirPath, '').replace(/\\/g, '/')))])) - } else { - astPath.remove() - } - } else if (REG_STYLE.test(valueExtname)) { - const stylePath = path.resolve(path.dirname(sourceFilePath), value) - if (styleFiles.indexOf(stylePath) < 0) { - styleFiles.push(stylePath) - } - astPath.remove() - } else { - let vpath = resolveScriptPath(path.resolve(sourceFilePath, '..', value)) - let outputVpath - if (NODE_MODULES_REG.test(vpath)) { - outputVpath = vpath.replace(nodeModulesPath, npmOutputDir) - } else { - outputVpath = vpath.replace(sourceDir, outputDir) - } - let relativePath = path.relative(filePath, outputVpath) - if (vpath && vpath !== sourceFilePath) { - if (!fs.existsSync(vpath)) { - printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 不存在!`) - } else { - if (fs.lstatSync(vpath).isDirectory()) { - if (fs.existsSync(path.join(vpath, 'index.js'))) { - vpath = path.join(vpath, 'index.js') - relativePath = path.join(relativePath, 'index.js') - } else { - printLog(processTypeEnum.ERROR, '引用目录', `文件 ${sourceFilePath} 中引用了目录 ${value}!`) - return - } - } - if (scriptFiles.indexOf(vpath) < 0) { - scriptFiles.push(vpath) - } - relativePath = promoteRelativePath(relativePath) - relativePath = relativePath.replace(path.extname(relativePath), '.js') - node.source.value = relativePath - } - } - } - } - } -} - -export function parseAst ( - type: PARSE_AST_TYPE, - ast: t.File, - sourceFilePath: string, - filePath: string, - npmSkip: boolean = false -) { - const styleFiles: string[] = [] - const scriptFiles: string[] = [] - const jsonFiles: string[] = [] - const mediaFiles: string[] = [] - - const { - nodeModulesPath, - npmOutputDir, - sourceDir, - outputDir, - buildAdapter, - constantsReplaceList, - isProduction, - npmConfig, - alias: pathAlias, - projectConfig - } = getBuildData() - const notExistNpmList = getNotExistNpmList() - const taroMiniAppFramework = `@tarojs/taro-${buildAdapter}` - let taroImportDefaultName - let needExportDefault = false - let configObj: IConfig = {} - let taroJsReduxConnect: string = '' - let componentClassName: string = '' - let exportTaroReduxConnected: string | null = null - ast = babel.transformFromAst(ast, '', { - plugins: [ - [require('babel-plugin-danger-remove-unused-import'), { ignore: ['@tarojs/taro', 'react', 'nervjs'] }], - [require('babel-plugin-transform-define').default, constantsReplaceList] - ] - }).ast as t.File - traverse(ast, { - ClassDeclaration (astPath) { - const node = astPath.node - let hasCreateData = false - if (astPath.isProperty({ superClass: true })) { - astPath.traverse({ - ClassMethod (astPath) { - if (astPath.get('key').isIdentifier({ name: '_createData' })) { - hasCreateData = true - } - } - }) - if (hasCreateData) { - needExportDefault = true - astPath.traverse({ - ClassMethod (astPath) { - const node = astPath.node - if (node.kind === 'constructor') { - astPath.traverse({ - ExpressionStatement (astPath) { - const node = astPath.node - if (node.expression && - node.expression.type === 'AssignmentExpression' && - node.expression.operator === '=') { - const left = node.expression.left - if (left.type === 'MemberExpression' && - left.object.type === 'ThisExpression' && - left.property.type === 'Identifier' && - left.property.name === 'config') { - configObj = traverseObjectNode(node.expression.right, buildAdapter) - } - } - } - }) - } - } - }) - if (node.id === null) { - componentClassName = '_TaroComponentClass' - astPath.replaceWith( - t.classDeclaration( - t.identifier(componentClassName), - node.superClass as t.Expression, - node.body as t.ClassBody, - node.decorators as t.Decorator[] || [] - ) - ) - } else if (node.id.name === 'App') { - componentClassName = '_App' - astPath.replaceWith( - t.classDeclaration( - t.identifier(componentClassName), - node.superClass as t.Expression, - node.body as t.ClassBody, - node.decorators as t.Decorator[] || [] - ) - ) - } else { - componentClassName = node.id.name - } - } - } - }, - - ClassExpression (astPath) { - const node = astPath.node - if (node.superClass) { - let hasCreateData = false - astPath.traverse({ - ClassMethod (astPath) { - if (astPath.get('key').isIdentifier({ name: '_createData' })) { - hasCreateData = true - } - } - }) - if (hasCreateData) { - needExportDefault = true - if (node.id === null) { - const parentNode = astPath.parentPath.node as any - if (t.isVariableDeclarator(astPath.parentPath)) { - componentClassName = parentNode.id.name - } else { - componentClassName = '_TaroComponentClass' - } - astPath.replaceWith( - t.classExpression( - t.identifier(componentClassName), - node.superClass as t.Expression, - node.body as t.ClassBody, - node.decorators as t.Decorator[] || [] - ) - ) - } else if (node.id.name === 'App') { - componentClassName = '_App' - astPath.replaceWith( - t.classExpression( - t.identifier(componentClassName), - node.superClass as t.Expression, - node.body as t.ClassBody, - node.decorators as t.Decorator[] || [] - ) - ) - } else { - componentClassName = node.id.name - } - } - } - }, - - ClassProperty (astPath) { - const node = astPath.node - if (node.key.name === 'config') { - configObj = traverseObjectNode(node, buildAdapter) - } - }, - - ImportDeclaration (astPath) { - const node = astPath.node - const source = node.source - let value = source.value - const specifiers = node.specifiers - if (isAliasPath(value, pathAlias)) { - value = replaceAliasPath(sourceFilePath, value, pathAlias) - source.value = value - } - if (isNpmPkg(value) - && !isQuickAppPkg(value) - && !notExistNpmList.has(value)) { - if (value === taroJsComponents) { - source.value = taroJsQuickAppComponents - value = taroJsQuickAppComponents - } else if (value === taroJsFramework) { - let defaultSpecifier: string | null = null - specifiers.forEach(item => { - if (item.type === 'ImportDefaultSpecifier') { - defaultSpecifier = item.local.name - } - }) - if (defaultSpecifier) { - taroImportDefaultName = defaultSpecifier - } - value = taroMiniAppFramework - } else if (value === taroJsRedux) { - specifiers.forEach(item => { - if (item.type === 'ImportSpecifier') { - const local = item.local - if (local.type === 'Identifier' && local.name === 'connect') { - taroJsReduxConnect = item.imported.name - } - } - }) - } - if (!npmSkip) { - source.value = getExactedNpmFilePath({ - npmName: value, - filePath, - isProduction, - npmConfig, - buildAdapter, - npmOutputDir, - compileInclude: [] - }) - } else { - source.value = value - } - } else if (CSS_EXT.indexOf(path.extname(value)) !== -1 && specifiers.length > 0) { // 对 使用 import style from './style.css' 语法引入的做转化处理 - - } else if (path.isAbsolute(value)) { - printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 是绝对路径!`) - } - }, - - CallExpression (astPath) { - const node = astPath.node - const callee = node.callee as (t.Identifier | t.MemberExpression) - if (t.isMemberExpression(callee)) { - if (taroImportDefaultName && (callee.object as t.Identifier).name === taroImportDefaultName && (callee.property as t.Identifier).name === 'render') { - astPath.remove() - } - } else if (callee.name === 'require') { - const args = node.arguments as t.StringLiteral[] - let value = args[0].value - if (isAliasPath(value, pathAlias)) { - value = replaceAliasPath(sourceFilePath, value, pathAlias) - args[0].value = value - } - if (isNpmPkg(value) - && !isQuickAppPkg(value) - && !notExistNpmList.has(value)) { - if (value === taroJsComponents) { - args[0].value = taroJsQuickAppComponents - value = taroJsQuickAppComponents - } else if (t.isVariableDeclaration(astPath.parentPath.parentPath)) { - const parentNode = astPath.parentPath.parentPath.node as t.VariableDeclaration - if (parentNode.declarations.length === 1 && parentNode.declarations[0].init) { - const id = parentNode.declarations[0].id - if (value === taroJsFramework && id.type === 'Identifier') { - taroImportDefaultName = id.name - value = taroMiniAppFramework - } else if (value === taroJsRedux) { - const declarations = parentNode.declarations - declarations.forEach(item => { - const id = item.id - if (id.type === 'ObjectPattern') { - const properties = id.properties as any - properties.forEach(p => { - if (p.type === 'ObjectProperty') { - if (p.value.type === 'Identifier' && p.value.name === 'connect') { - taroJsReduxConnect = p.key.name - } - } - }) - } - }) - } - } - } - if (!npmSkip) { - args[0].value = getExactedNpmFilePath({ - npmName: value, - filePath, - isProduction, - npmConfig, - buildAdapter, - npmOutputDir, - compileInclude: [] - }) - } else { - args[0].value = value - } - } else if (CSS_EXT.indexOf(path.extname(value)) !== -1 && t.isVariableDeclarator(astPath.parentPath)) { // 对 使用 const style = require('./style.css') 语法引入的做转化处理 - - } else if (path.isAbsolute(value)) { - printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 是绝对路径!`) - } - } - }, - - ExportDefaultDeclaration (astPath) { - const node = astPath.node - const declaration = node.declaration - needExportDefault = false - if ( - declaration && - (declaration.type === 'ClassDeclaration' || declaration.type === 'ClassExpression') - ) { - const superClass = declaration.superClass - if (superClass) { - let hasCreateData = false - astPath.traverse({ - ClassMethod (astPath) { - if (astPath.get('key').isIdentifier({ name: '_createData' })) { - hasCreateData = true - } - } - }) - if (hasCreateData) { - needExportDefault = true - if (declaration.id === null) { - componentClassName = '_TaroComponentClass' - } else if (declaration.id.name === 'App') { - componentClassName = '_App' - } else { - componentClassName = declaration.id.name - } - const isClassDcl = declaration.type === 'ClassDeclaration' - const classDclProps = [t.identifier(componentClassName), superClass, declaration.body, declaration.decorators || []] - astPath.replaceWith(isClassDcl ? t.classDeclaration.apply(null, classDclProps) : t.classExpression.apply(null, classDclProps)) - } - } - } else if (declaration.type === 'CallExpression') { - const callee = declaration.callee - if (callee && callee.type === 'CallExpression') { - const subCallee = callee.callee - if (subCallee.type === 'Identifier' && subCallee.name === taroJsReduxConnect) { - const args = declaration.arguments as t.Identifier[] - if (args.length === 1 && args[0].name === componentClassName) { - needExportDefault = true - exportTaroReduxConnected = `${componentClassName}__Connected` - astPath.replaceWith(t.variableDeclaration('const', [t.variableDeclarator(t.identifier(`${componentClassName}__Connected`), t.callExpression(declaration.callee as t.Expression, declaration.arguments as Array))])) - } - } - } - } - }, - - ExportNamedDeclaration (astPath) { - const node = astPath.node - const source = node.source - if (source && source.type === 'StringLiteral') { - const value = source.value - analyzeImportUrl({ astPath, value, sourceFilePath, filePath, styleFiles, scriptFiles, jsonFiles, mediaFiles }) - } - }, - - ExportAllDeclaration (astPath) { - const node = astPath.node - const source = node.source - if (source && source.type === 'StringLiteral') { - const value = source.value - analyzeImportUrl({ astPath, value, sourceFilePath, filePath, styleFiles, scriptFiles, jsonFiles, mediaFiles }) - } - }, - Program: { - exit (astPath) { - astPath.traverse({ - ImportDeclaration (astPath) { - const node = astPath.node - const source = node.source - const value = source.value - analyzeImportUrl({ astPath, value, sourceFilePath, filePath, styleFiles, scriptFiles, jsonFiles, mediaFiles }) - }, - CallExpression (astPath) { - const node = astPath.node - const callee = node.callee as t.Identifier - if (callee.name === 'require') { - const args = node.arguments as t.StringLiteral[] - const value = args[0].value - const valueExtname = path.extname(value) - if (value.indexOf('.') === 0) { - let importPath = path.resolve(path.dirname(sourceFilePath), value) - importPath = resolveScriptPath(importPath) - if (isFileToBePage(importPath)) { - if (astPath.parent.type === 'AssignmentExpression' || 'ExpressionStatement') { - astPath.parentPath.remove() - } else if (astPath.parent.type === 'VariableDeclarator') { - astPath.parentPath.parentPath.remove() - } else { - astPath.remove() - } - } else { - if (REG_STYLE.test(valueExtname)) { - const stylePath = path.resolve(path.dirname(sourceFilePath), value) - if (styleFiles.indexOf(stylePath) < 0) { - styleFiles.push(stylePath) - } - if (astPath.parent.type === 'AssignmentExpression' || 'ExpressionStatement') { - astPath.parentPath.remove() - } else if (astPath.parent.type === 'VariableDeclarator') { - astPath.parentPath.parentPath.remove() - } else { - astPath.remove() - } - } else if (REG_JSON.test(valueExtname)) { - const vpath = path.resolve(sourceFilePath, '..', value) - if (jsonFiles.indexOf(vpath) < 0) { - jsonFiles.push(vpath) - } - if (fs.existsSync(vpath)) { - const obj = JSON.parse(fs.readFileSync(vpath).toString()) - let objArr: t.NullLiteral | t.Expression = t.nullLiteral() - if (Array.isArray(obj)) { - objArr = t.arrayExpression(convertArrayToAstExpression(obj)) - } else { - objArr = t.objectExpression(convertObjectToAstExpression(obj)) - } - astPath.replaceWith(t.objectExpression(objArr as any)) - } - } else if (REG_SCRIPT.test(valueExtname) || REG_TYPESCRIPT.test(valueExtname)) { - const vpath = path.resolve(sourceFilePath, '..', value) - let fPath = value - if (fs.existsSync(vpath) && vpath !== sourceFilePath) { - fPath = vpath - } - if (scriptFiles.indexOf(fPath) < 0) { - scriptFiles.push(fPath) - } - } else if (REG_FONT.test(valueExtname) || REG_IMAGE.test(valueExtname) || REG_MEDIA.test(valueExtname)) { - const vpath = path.resolve(sourceFilePath, '..', value) - if (mediaFiles.indexOf(vpath) < 0) { - mediaFiles.push(vpath) - } - let sourceDirPath = sourceDir - if (NODE_MODULES_REG.test(vpath)) { - sourceDirPath = nodeModulesPath - } - astPath.replaceWith(t.stringLiteral(vpath.replace(sourceDirPath, '').replace(/\\/g, '/'))) - } else { - let vpath = resolveScriptPath(path.resolve(sourceFilePath, '..', value)) - let outputVpath - if (NODE_MODULES_REG.test(vpath)) { - outputVpath = vpath.replace(nodeModulesPath, npmOutputDir) - } else { - outputVpath = vpath.replace(sourceDir, outputDir) - } - let relativePath = path.relative(filePath, outputVpath) - if (vpath) { - if (!fs.existsSync(vpath)) { - printLog(processTypeEnum.ERROR, '引用文件', `文件 ${sourceFilePath} 中引用 ${value} 不存在!`) - } else { - if (fs.lstatSync(vpath).isDirectory()) { - if (fs.existsSync(path.join(vpath, 'index.js'))) { - vpath = path.join(vpath, 'index.js') - relativePath = path.join(relativePath, 'index.js') - } else { - printLog(processTypeEnum.ERROR, '引用目录', `文件 ${sourceFilePath} 中引用了目录 ${value}!`) - return - } - } - if (scriptFiles.indexOf(vpath) < 0) { - scriptFiles.push(vpath) - } - relativePath = promoteRelativePath(relativePath) - relativePath = relativePath.replace(path.extname(relativePath), '.js') - args[0].value = relativePath - } - } - } - } - } - } - } - }) - const node = astPath.node as t.Program - const exportVariableName = exportTaroReduxConnected || componentClassName - if (needExportDefault) { - const exportDefault = template(`export default ${exportVariableName}`, babylonConfig as any)() - node.body.push(exportDefault as any) - } - const taroMiniAppFrameworkPath = !npmSkip ? getExactedNpmFilePath({ - npmName: taroMiniAppFramework, - filePath, - isProduction, - npmConfig, - buildAdapter, - npmOutputDir, - compileInclude: [] - }) : taroMiniAppFramework - switch (type) { - case PARSE_AST_TYPE.ENTRY: - const pxTransformConfig = { - designWidth: projectConfig.designWidth || 750 - } - if (projectConfig.hasOwnProperty(DEVICE_RATIO_NAME)) { - pxTransformConfig[DEVICE_RATIO_NAME] = projectConfig.deviceRatio - } - node.body.push(template(`export default require('${taroMiniAppFrameworkPath}').default.createApp(${exportVariableName})`, babylonConfig as any)() as any) - node.body.push(template(`Taro.initPxTransform(${JSON.stringify(pxTransformConfig)})`, babylonConfig as any)() as any) - break - case PARSE_AST_TYPE.PAGE: - node.body.push(template(`export default require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}, true)`, babylonConfig as any)() as any) - break - case PARSE_AST_TYPE.COMPONENT: - node.body.push(template(`export default require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName})`, babylonConfig as any)() as any) - break - default: - break - } - } - } - }) - return { - code: generate(ast).code, - styleFiles, - scriptFiles, - jsonFiles, - configObj, - mediaFiles, - componentClassName - } -} diff --git a/packages/taro-cli/src/quick/constants.ts b/packages/taro-cli/src/quick/constants.ts deleted file mode 100644 index 8b137891791f..000000000000 --- a/packages/taro-cli/src/quick/constants.ts +++ /dev/null @@ -1 +0,0 @@ - diff --git a/packages/taro-cli/src/quick/entry.ts b/packages/taro-cli/src/quick/entry.ts deleted file mode 100644 index 4002e4516605..000000000000 --- a/packages/taro-cli/src/quick/entry.ts +++ /dev/null @@ -1,46 +0,0 @@ -import * as fs from 'fs-extra' -import * as path from 'path' - -import * as wxTransformer from '@tarojs/transformer-wx' - -import { IWxTransformResult } from '../util/types' -import { processTypeEnum, REG_TYPESCRIPT, PARSE_AST_TYPE } from '../util/constants' -import { printLog } from '../util' - -import { getBuildData, setAppConfig, getDependencyTree } from './helper' -import { parseAst } from '../mini/astProcess' - -export async function buildEntry () { - const { - buildAdapter, - constantsReplaceList, - entryFilePath, - outputDir, - entryFileName, - sourceDirName, - projectConfig - } = getBuildData() - - const quickAppConf = projectConfig.quickApp - const entryFileCode = fs.readFileSync(entryFilePath).toString() - const outputEntryFilePath = path.join(outputDir, entryFileName) - - printLog(processTypeEnum.COMPILE, '入口文件', `${sourceDirName}/${entryFileName}`) - try { - const transformResult: IWxTransformResult = wxTransformer({ - code: entryFileCode, - sourcePath: entryFilePath, - outputPath: outputEntryFilePath, - isApp: true, - isTyped: REG_TYPESCRIPT.test(entryFilePath), - adapter: buildAdapter, - env: constantsReplaceList - }) - const res = parseAst(PARSE_AST_TYPE.ENTRY, transformResult.ast, [], entryFilePath, outputEntryFilePath) - const dependencyTree = getDependencyTree() - setAppConfig(res.configObj) - console.log(res) - } catch (err) { - console.log(err) - } -} diff --git a/packages/taro-cli/src/quick/helper.ts b/packages/taro-cli/src/quick/helper.ts deleted file mode 100644 index 0551389cf61a..000000000000 --- a/packages/taro-cli/src/quick/helper.ts +++ /dev/null @@ -1,121 +0,0 @@ -import * as path from 'path' - -import * as _ from 'lodash' -import { AppConfig } from '@tarojs/taro' - -import { - BUILD_TYPES, - PROJECT_CONFIG, - REG_SCRIPTS -} from '../util/constants' -import CONFIG from '../config' -import { - resolveScriptPath, - generateEnvList, - generateConstantsList -} from '../util' -import { IProjectConfig, INpmConfig, IOption } from '../util/types' -import { getNodeModulesPath, getNpmOutputDir } from '../util/npmExact' -import { IDependency } from './interface' - -const appPath = process.cwd() -const configDir = path.join(appPath, PROJECT_CONFIG) -const projectConfig = require(configDir)(_.merge) -const sourceDirName = projectConfig.sourceRoot || CONFIG.SOURCE_DIR -const outputDirName = projectConfig.outputRoot || CONFIG.OUTPUT_DIR -const sourceDir = path.join(appPath, sourceDirName) -const outputDir = path.join(appPath, outputDirName) -const entryFilePath = resolveScriptPath(path.join(sourceDir, CONFIG.ENTRY)) -const entryFileName = path.basename(entryFilePath) - -const pathAlias = projectConfig.alias || {} -const quickAppConf = projectConfig.quickApp || {} -const npmConfig = Object.assign({ - name: CONFIG.NPM_DIR, - dir: null -}, quickAppConf.npm) - -const minifestJSON = {} -const dependencyTree: Map = new Map() - -export interface IBuildData { - appPath: string, - configDir: string, - sourceDirName: string, - outputDirName: string, - sourceDir: string, - outputDir: string, - entryFilePath: string, - entryFileName: string, - projectConfig: IProjectConfig, - npmConfig: INpmConfig, - appConfig: AppConfig, - alias: IOption, - isProduction: boolean, - buildAdapter: BUILD_TYPES, - constantsReplaceList: IOption, - nodeModulesPath: string, - npmOutputDir: string -} - -const BuildData: IBuildData = { - appPath, - configDir, - sourceDirName, - outputDirName, - sourceDir, - outputDir, - entryFilePath, - entryFileName, - projectConfig, - npmConfig, - alias: pathAlias, - isProduction: false, - appConfig: {}, - buildAdapter: BUILD_TYPES.WEAPP, - constantsReplaceList: {}, - nodeModulesPath: getNodeModulesPath(), - npmOutputDir: getNpmOutputDir(outputDir, configDir, npmConfig) -} - -export function setAppConfig (appConfig: AppConfig) { - BuildData.appConfig = appConfig -} - -export function setIsProduction (isProduction: boolean) { - BuildData.isProduction = isProduction -} - -export function setBuildAdapter (adapter: BUILD_TYPES) { - BuildData.buildAdapter = adapter - BuildData.constantsReplaceList = Object.assign({}, generateEnvList(projectConfig.env || {}), generateConstantsList(projectConfig.defineConstants || {}), { - 'process.env.TARO_ENV': adapter - }) -} - -export function getBuildData (): IBuildData { - return BuildData -} - -export function setManifestJSON (key, value) { - minifestJSON[key] = value -} - -export function getDependencyTree (): Map { - return dependencyTree -} - -export function isFileToBePage (filePath: string): boolean { - let isPage = false - const { appConfig, sourceDir } = BuildData - const extname = path.extname(filePath) - const pages = appConfig.pages || [] - const filePathWithoutExt = filePath.replace(extname, '') - pages.forEach(page => { - if (filePathWithoutExt === path.join(sourceDir, page)) { - isPage = true - } - }) - return isPage && REG_SCRIPTS.test(extname) -} - diff --git a/packages/taro-cli/src/quick/index.ts b/packages/taro-cli/src/quick/index.ts deleted file mode 100644 index 69a02a8669eb..000000000000 --- a/packages/taro-cli/src/quick/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { BUILD_TYPES } from '../util/constants' -import { IMiniAppBuildConfig } from '../util/types' - -import { - getBuildData, - setIsProduction, - setBuildAdapter, - setAppConfig -} from './helper' -import { copyFiles } from '../util' - -import { buildEntry } from './entry' - -export async function build ({ watch, adapter = BUILD_TYPES.QUICKAPP }: IMiniAppBuildConfig) { - const { projectConfig, appPath } = getBuildData() - process.env.TARO_ENV = adapter - setIsProduction(process.env.NODE_ENV === 'production' || !watch) - setBuildAdapter(adapter) - copyFiles(appPath, projectConfig.copy) - const appConfig = await buildEntry() - // setAppConfig(appConfig) -} diff --git a/packages/taro-cli/src/quick/interface.ts b/packages/taro-cli/src/quick/interface.ts deleted file mode 100644 index 8c9bd99c94b4..000000000000 --- a/packages/taro-cli/src/quick/interface.ts +++ /dev/null @@ -1,12 +0,0 @@ -export interface IDependency { - style: string[], - script: string[], - json: string[], - media: string[] -} - -export interface IComponentObj { - name?: string, - path: string | null, - type?: string -} diff --git a/packages/taro-cli/src/util/index.ts b/packages/taro-cli/src/util/index.ts index 566591b4f63e..5e4a430fa149 100644 --- a/packages/taro-cli/src/util/index.ts +++ b/packages/taro-cli/src/util/index.ts @@ -383,17 +383,23 @@ export function recursiveFindNodeModules (filePath: string): string { export const pascalCase: (str: string) => string = (str: string): string => str.charAt(0).toUpperCase() + _.camelCase(str.substr(1)) -export function getInstalledNpmPkgVersion (pkgName: string, basedir: string): string | null { +export function getInstalledNpmPkgPath (pkgName: string, basedir: string): string | null { const resolvePath = require('resolve') try { - const pkg = resolvePath.sync(`${pkgName}/package.json`, { basedir }) - const pkgJson = fs.readJSONSync(pkg) - return pkgJson.version + return resolvePath.sync(`${pkgName}/package.json`, { basedir }) } catch (err) { return null } } +export function getInstalledNpmPkgVersion (pkgName: string, basedir: string): string | null { + const pkgPath = getInstalledNpmPkgPath(pkgName, basedir) + if (!pkgPath) { + return null + } + return fs.readJSONSync(pkgPath).version +} + export function traverseObjectNode (node, buildAdapter: string) { if (node.type === 'ClassProperty' || node.type === 'ObjectProperty') { const properties = node.value.properties @@ -491,13 +497,23 @@ export function isQuickAppPkg (name: string): boolean { export function generateQuickAppUx ({ script, template, - style + style, + imports }: { script?: string, template?: string, - style?: string + style?: string, + imports?: Set<{ + path: string, + name: string + }> }) { let uxTxt = '' + if (imports && imports.size) { + imports.forEach(item => { + uxTxt += `\n` + }) + } if (style) { if (REG_STYLE.test(style)) { uxTxt += `\n` From c1d5ebef8fc6142645033382b2ceb5880773c837 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Thu, 14 Mar 2019 21:58:25 +0800 Subject: [PATCH 042/103] =?UTF-8?q?feat:=20=E7=BC=96=E8=AF=91=E5=BF=AB?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E9=A1=B5=E9=9D=A2=E6=97=B6=20copy=20?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E4=BE=9D=E8=B5=96=E7=9A=84=20taro=20?= =?UTF-8?q?=E5=86=85=E7=BD=AE=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/src/mini/page.ts | 7 +++++-- packages/taro-cli/src/util/npm.ts | 23 +++++++++++------------ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/taro-cli/src/mini/page.ts b/packages/taro-cli/src/mini/page.ts index 1b072a8d1b2d..9c84c8403854 100644 --- a/packages/taro-cli/src/mini/page.ts +++ b/packages/taro-cli/src/mini/page.ts @@ -206,8 +206,11 @@ export async function buildSinglePage (page: string) { } const taroJsQuickAppComponentsPath = path.join(path.dirname(taroJsQuickAppComponentsPkg as string), 'src/components') res.taroSelfComponents.forEach(c => { - const cPath = path.join(taroJsQuickAppComponentsPath, c, 'index') - const cRelativePath = promoteRelativePath(path.relative(outputPageJSPath, cPath.replace(nodeModulesPath, npmOutputDir))) + const cPath = path.join(taroJsQuickAppComponentsPath, c) + const cMainPath = path.join(cPath, 'index') + const cFiles = fs.readdirSync(cPath).map(item => path.join(cPath, item)) + copyFilesFromSrcToOutput(cFiles) + const cRelativePath = promoteRelativePath(path.relative(outputPageJSPath, cMainPath.replace(nodeModulesPath, npmOutputDir))) importTaroSelfComponents.add({ path: cRelativePath, name: c diff --git a/packages/taro-cli/src/util/npm.ts b/packages/taro-cli/src/util/npm.ts index 96c5abaa6c17..accb12051e75 100644 --- a/packages/taro-cli/src/util/npm.ts +++ b/packages/taro-cli/src/util/npm.ts @@ -43,18 +43,17 @@ export function resolveNpmSync (pluginName: string): string { } return npmCached[pluginName] } catch (err) { - console.log(err) - // if (err.code === 'MODULE_NOT_FOUND') { - // console.log(chalk.cyan(`缺少npm包${pluginName},开始安装...`)) - // const installOptions: IInstallOptions = { - // dev: false - // } - // if (pluginName.indexOf(taroPluginPrefix) >= 0) { - // installOptions.dev = true - // } - // installNpmPkg(pluginName, installOptions) - // return resolveNpmSync(pluginName) - // } + if (err.code === 'MODULE_NOT_FOUND') { + console.log(chalk.cyan(`缺少npm包${pluginName},开始安装...`)) + const installOptions: IInstallOptions = { + dev: false + } + if (pluginName.indexOf(taroPluginPrefix) >= 0) { + installOptions.dev = true + } + installNpmPkg(pluginName, installOptions) + return resolveNpmSync(pluginName) + } return '' } } From be495580bc18db8f4417ae5665bb33c8bca08457 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Thu, 14 Mar 2019 22:02:58 +0800 Subject: [PATCH 043/103] =?UTF-8?q?feat:=20=E4=B8=BA=E4=BA=86=E9=81=BF?= =?UTF-8?q?=E5=85=8D=E5=BF=AB=E5=BA=94=E7=94=A8=E5=9F=BA=E7=A1=80=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E4=B8=8E=E5=8E=9F=E7=94=9F=E7=BB=84=E4=BB=B6=E5=90=8D?= =?UTF-8?q?=E5=86=B2=E7=AA=81=EF=BC=8C=E9=83=A8=E5=88=86=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20taro=20=E5=89=8D=E7=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-components-qa/index.js | 1 + packages/taro-components-qa/package.json | 12 ++++++++++++ .../src/components/{rich_text => rich-text}/index.ux | 0 .../src/components/{camera => taro-camera}/index.ux | 0 .../src/components/{image => taro-image}/index.ux | 0 .../src/components/{input => taro-input}/index.ux | 0 .../src/components/{label => taro-label}/index.ux | 0 .../src/components/{picker => taro-picker}/index.ux | 0 .../components/{progress => taro-progress}/index.ux | 0 .../src/components/{slider => taro-slider}/index.ux | 0 .../src/components/{swiper => taro-swiper}/index.ux | 0 .../src/components/{switch => taro-switch}/index.ux | 0 .../src/components/{text => taro-text}/index.ux | 0 .../components/{textarea => taro-textarea}/index.ux | 0 .../src/components/{video => taro-video}/index.ux | 0 15 files changed, 13 insertions(+) create mode 100644 packages/taro-components-qa/index.js create mode 100644 packages/taro-components-qa/package.json rename packages/taro-components-qa/src/components/{rich_text => rich-text}/index.ux (100%) rename packages/taro-components-qa/src/components/{camera => taro-camera}/index.ux (100%) rename packages/taro-components-qa/src/components/{image => taro-image}/index.ux (100%) rename packages/taro-components-qa/src/components/{input => taro-input}/index.ux (100%) rename packages/taro-components-qa/src/components/{label => taro-label}/index.ux (100%) rename packages/taro-components-qa/src/components/{picker => taro-picker}/index.ux (100%) rename packages/taro-components-qa/src/components/{progress => taro-progress}/index.ux (100%) rename packages/taro-components-qa/src/components/{slider => taro-slider}/index.ux (100%) rename packages/taro-components-qa/src/components/{swiper => taro-swiper}/index.ux (100%) rename packages/taro-components-qa/src/components/{switch => taro-switch}/index.ux (100%) rename packages/taro-components-qa/src/components/{text => taro-text}/index.ux (100%) rename packages/taro-components-qa/src/components/{textarea => taro-textarea}/index.ux (100%) rename packages/taro-components-qa/src/components/{video => taro-video}/index.ux (100%) diff --git a/packages/taro-components-qa/index.js b/packages/taro-components-qa/index.js new file mode 100644 index 000000000000..9e362c0ef8a9 --- /dev/null +++ b/packages/taro-components-qa/index.js @@ -0,0 +1 @@ +// 空的占位文件 diff --git a/packages/taro-components-qa/package.json b/packages/taro-components-qa/package.json new file mode 100644 index 000000000000..6aafe86b8638 --- /dev/null +++ b/packages/taro-components-qa/package.json @@ -0,0 +1,12 @@ +{ + "name": "@tarojs/components-qa", + "version": "1.2.13", + "description": "多端解决方案基础组件(快应用)", + "main": "./index.js", + "files": [ + "src", + "index.js" + ], + "author": "O2Team", + "license": "MIT" +} diff --git a/packages/taro-components-qa/src/components/rich_text/index.ux b/packages/taro-components-qa/src/components/rich-text/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/rich_text/index.ux rename to packages/taro-components-qa/src/components/rich-text/index.ux diff --git a/packages/taro-components-qa/src/components/camera/index.ux b/packages/taro-components-qa/src/components/taro-camera/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/camera/index.ux rename to packages/taro-components-qa/src/components/taro-camera/index.ux diff --git a/packages/taro-components-qa/src/components/image/index.ux b/packages/taro-components-qa/src/components/taro-image/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/image/index.ux rename to packages/taro-components-qa/src/components/taro-image/index.ux diff --git a/packages/taro-components-qa/src/components/input/index.ux b/packages/taro-components-qa/src/components/taro-input/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/input/index.ux rename to packages/taro-components-qa/src/components/taro-input/index.ux diff --git a/packages/taro-components-qa/src/components/label/index.ux b/packages/taro-components-qa/src/components/taro-label/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/label/index.ux rename to packages/taro-components-qa/src/components/taro-label/index.ux diff --git a/packages/taro-components-qa/src/components/picker/index.ux b/packages/taro-components-qa/src/components/taro-picker/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/picker/index.ux rename to packages/taro-components-qa/src/components/taro-picker/index.ux diff --git a/packages/taro-components-qa/src/components/progress/index.ux b/packages/taro-components-qa/src/components/taro-progress/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/progress/index.ux rename to packages/taro-components-qa/src/components/taro-progress/index.ux diff --git a/packages/taro-components-qa/src/components/slider/index.ux b/packages/taro-components-qa/src/components/taro-slider/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/slider/index.ux rename to packages/taro-components-qa/src/components/taro-slider/index.ux diff --git a/packages/taro-components-qa/src/components/swiper/index.ux b/packages/taro-components-qa/src/components/taro-swiper/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/swiper/index.ux rename to packages/taro-components-qa/src/components/taro-swiper/index.ux diff --git a/packages/taro-components-qa/src/components/switch/index.ux b/packages/taro-components-qa/src/components/taro-switch/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/switch/index.ux rename to packages/taro-components-qa/src/components/taro-switch/index.ux diff --git a/packages/taro-components-qa/src/components/text/index.ux b/packages/taro-components-qa/src/components/taro-text/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/text/index.ux rename to packages/taro-components-qa/src/components/taro-text/index.ux diff --git a/packages/taro-components-qa/src/components/textarea/index.ux b/packages/taro-components-qa/src/components/taro-textarea/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/textarea/index.ux rename to packages/taro-components-qa/src/components/taro-textarea/index.ux diff --git a/packages/taro-components-qa/src/components/video/index.ux b/packages/taro-components-qa/src/components/taro-video/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/video/index.ux rename to packages/taro-components-qa/src/components/taro-video/index.ux From ab6047548dfc68e81550b9859bf4bb10b5cf7a17 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Fri, 15 Mar 2019 11:45:00 +0800 Subject: [PATCH 044/103] =?UTF-8?q?feat:=20=E7=BC=96=E8=AF=91=E5=BF=AB?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E4=BE=9D=E8=B5=96=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/src/mini/component.ts | 54 ++++++--- packages/taro-cli/src/mini/helper.ts | 31 ++++- packages/taro-cli/src/mini/page.ts | 143 +++++++++++------------- 3 files changed, 132 insertions(+), 96 deletions(-) diff --git a/packages/taro-cli/src/mini/component.ts b/packages/taro-cli/src/mini/component.ts index 6008ca7963d1..e0eac96e80d4 100644 --- a/packages/taro-cli/src/mini/component.ts +++ b/packages/taro-cli/src/mini/component.ts @@ -12,13 +12,17 @@ import { processTypeEnum, NODE_MODULES_REG, NODE_MODULES, - PARSE_AST_TYPE + PARSE_AST_TYPE, + BUILD_TYPES, + taroJsQuickAppComponents } from '../util/constants' import { printLog, isEmptyObject, promoteRelativePath, - isDifferentArray + isDifferentArray, + getInstalledNpmPkgPath, + generateQuickAppUx } from '../util' import { parseComponentExportAst, parseAst } from './astProcess' @@ -35,7 +39,8 @@ import { getComponentsBuildResult, getDependencyTree, buildUsingComponents, - getDepComponents + getDepComponents, + getImportTaroSelfComponents } from './helper' import { compileScriptFile, compileDepScripts } from './compileScript' import { compileDepStyles } from './compileStyle' @@ -139,6 +144,7 @@ export async function buildSingleComponent ( outputFilesTypes, isProduction } = getBuildData() + const isQuickApp = buildAdapter === BUILD_TYPES.QUICKAPP if (componentObj.path) { componentsNamedMap.set(componentObj.path, { @@ -221,11 +227,8 @@ export async function buildSingleComponent ( const componentDepComponents = transformResult.components const res = parseAst(PARSE_AST_TYPE.COMPONENT, transformResult.ast, componentDepComponents, component, outputComponentJSPath, buildConfig.npmSkip) let resCode = res.code - resCode = await compileScriptFile(resCode, component, outputComponentJSPath, buildAdapter) fs.ensureDirSync(path.dirname(outputComponentJSPath)) - if (isProduction) { - uglifyJS(resCode, component) - } + // 解析原生组件 const { usingComponents = {} }: IConfig = res.configObj if (usingComponents && !isEmptyObject(usingComponents)) { const keys = Object.keys(usingComponents) @@ -238,6 +241,25 @@ export async function buildSingleComponent ( }) transfromNativeComponents(outputComponentJSONPath.replace(buildConfig.outputDir || buildOutputDir, sourceDirPath), res.configObj) } + if (!isQuickApp) { + resCode = await compileScriptFile(resCode, component, outputComponentJSPath, buildAdapter) + if (isProduction) { + uglifyJS(resCode, component) + } + } else { + // 快应用编译,搜集创建组件 ux 文件 + const importTaroSelfComponents = getImportTaroSelfComponents(outputComponentJSPath, res.taroSelfComponents) + const styleRelativePath = promoteRelativePath(path.relative(outputComponentJSPath, outputComponentWXSSPath)) + const uxTxt = generateQuickAppUx({ + script: resCode, + style: styleRelativePath, + imports: importTaroSelfComponents, + template: componentWXMLContent + }) + fs.writeFileSync(outputComponentWXMLPath, uxTxt) + printLog(processTypeEnum.GENERATE, '组件文件', `${outputDirName}/${componentObj.name}${outputFilesTypes.TEMPL}`) + } + const dependencyTree = getDependencyTree() const fileDep = dependencyTree.get(component) || {} // 编译依赖的组件文件 @@ -280,16 +302,18 @@ export async function buildSingleComponent ( } }) } - fs.writeFileSync(outputComponentJSONPath, JSON.stringify(_.merge({}, buildUsingComponents(component, componentDepComponents, true), res.configObj), null, 2)) - printLog(processTypeEnum.GENERATE, '组件配置', `${outputDirName}/${outputComponentShowPath}${outputFilesTypes.CONFIG}`) - fs.writeFileSync(outputComponentJSPath, resCode) - printLog(processTypeEnum.GENERATE, '组件逻辑', `${outputDirName}/${outputComponentShowPath}${outputFilesTypes.SCRIPT}`) - fs.writeFileSync(outputComponentWXMLPath, componentWXMLContent) - processNativeWxml(outputComponentWXMLPath.replace(outputDir, sourceDir), componentWXMLContent, outputComponentWXMLPath) - printLog(processTypeEnum.GENERATE, '组件模板', `${outputDirName}/${outputComponentShowPath}${outputFilesTypes.TEMPL}`) + if (!isQuickApp) { + fs.writeFileSync(outputComponentJSONPath, JSON.stringify(_.merge({}, buildUsingComponents(component, componentDepComponents, true), res.configObj), null, 2)) + printLog(processTypeEnum.GENERATE, '组件配置', `${outputDirName}/${outputComponentShowPath}${outputFilesTypes.CONFIG}`) + fs.writeFileSync(outputComponentJSPath, resCode) + printLog(processTypeEnum.GENERATE, '组件逻辑', `${outputDirName}/${outputComponentShowPath}${outputFilesTypes.SCRIPT}`) + fs.writeFileSync(outputComponentWXMLPath, componentWXMLContent) + processNativeWxml(outputComponentWXMLPath.replace(outputDir, sourceDir), componentWXMLContent, outputComponentWXMLPath) + printLog(processTypeEnum.GENERATE, '组件模板', `${outputDirName}/${outputComponentShowPath}${outputFilesTypes.TEMPL}`) + } // 编译依赖的脚本文件 if (isDifferentArray(fileDep['script'], res.scriptFiles)) { - compileDepScripts(res.scriptFiles) + compileDepScripts(res.scriptFiles, !isQuickApp) } const depComponents = getDepComponents() // 编译样式文件 diff --git a/packages/taro-cli/src/mini/helper.ts b/packages/taro-cli/src/mini/helper.ts index d48c4d765b50..288e7f4f7daf 100644 --- a/packages/taro-cli/src/mini/helper.ts +++ b/packages/taro-cli/src/mini/helper.ts @@ -12,7 +12,7 @@ import { processTypeEnum, REG_SCRIPTS, NODE_MODULES_REG, - REG_STYLE + taroJsQuickAppComponents } from '../util/constants' import { resolveScriptPath, @@ -23,7 +23,8 @@ import { printLog, generateEnvList, generateConstantsList, - isEmptyObject + isEmptyObject, + getInstalledNpmPkgPath } from '../util' import { callPluginSync } from '../util/npm' import { resolveNpmPkgMainPath } from '../util/resolve_npm_files' @@ -325,3 +326,29 @@ export function copyFilesFromSrcToOutput (files: string[]) { } }) } + +export function getTaroJsQuickAppComponentsPath () { + const taroJsQuickAppComponentsPkg = getInstalledNpmPkgPath(taroJsQuickAppComponents, getNodeModulesPath()) + if (!taroJsQuickAppComponentsPkg) { + printLog(processTypeEnum.ERROR, '包安装', `缺少包 ${taroJsQuickAppComponents},请安装!`) + process.exit(0) + } + return path.join(path.dirname(taroJsQuickAppComponentsPkg as string), 'src/components') +} + +export function getImportTaroSelfComponents (filePath, taroSelfComponents) { + const importTaroSelfComponents = new Set<{ path: string, name: string }>() + const taroJsQuickAppComponentsPath = getTaroJsQuickAppComponentsPath() + taroSelfComponents.forEach(c => { + const cPath = path.join(taroJsQuickAppComponentsPath, c) + const cMainPath = path.join(cPath, 'index') + const cFiles = fs.readdirSync(cPath).map(item => path.join(cPath, item)) + copyFilesFromSrcToOutput(cFiles) + const cRelativePath = promoteRelativePath(path.relative(filePath, cMainPath.replace(getNodeModulesPath(), BuildData.npmOutputDir))) + importTaroSelfComponents.add({ + path: cRelativePath, + name: c + }) + }) + return importTaroSelfComponents +} diff --git a/packages/taro-cli/src/mini/page.ts b/packages/taro-cli/src/mini/page.ts index 9c84c8403854..5c5de904ffc7 100644 --- a/packages/taro-cli/src/mini/page.ts +++ b/packages/taro-cli/src/mini/page.ts @@ -35,7 +35,9 @@ import { copyFilesFromSrcToOutput, getDependencyTree, getComponentExportsMap, - getDepComponents + getDepComponents, + getTaroJsQuickAppComponentsPath, + getImportTaroSelfComponents } from './helper' import { compileDepScripts, compileScriptFile } from './compileScript' import { compileDepStyles } from './compileStyle' @@ -119,6 +121,66 @@ export async function buildSinglePage (page: string) { }) transfromNativeComponents(outputPageJSONPath.replace(outputDir, sourceDir), res.configObj) } + + if (!isQuickApp) { + resCode = await compileScriptFile(resCode, pageJs, outputPageJSPath, buildAdapter) + if (isProduction) { + uglifyJS(resCode, pageJs) + } + } else { + // 快应用编译,搜集创建页面 ux 文件 + const importTaroSelfComponents = getImportTaroSelfComponents(outputPageJSPath, res.taroSelfComponents) + // 生成页面 ux 文件 + const styleRelativePath = promoteRelativePath(path.relative(outputPageJSPath, outputPageWXSSPath)) + const uxTxt = generateQuickAppUx({ + script: resCode, + style: styleRelativePath, + imports: importTaroSelfComponents, + template: pageWXMLContent + }) + fs.writeFileSync(outputPageWXMLPath, uxTxt) + printLog(processTypeEnum.GENERATE, '页面文件', `${outputDirName}/${page}${outputFilesTypes.TEMPL}`) + } + // 编译依赖的组件文件 + let realComponentsPathList: IComponentObj[] = [] + if (pageDepComponents.length) { + realComponentsPathList = getRealComponentsPathList(pageJs, pageDepComponents) + res.scriptFiles = res.scriptFiles.map(item => { + for (let i = 0; i < realComponentsPathList.length; i++) { + const componentObj = realComponentsPathList[i] + const componentPath = componentObj.path + if (item === componentPath) { + return '' + } + } + return item + }).filter(item => item) + await buildDepComponents(realComponentsPathList) + } + const componentExportsMap = getComponentExportsMap() + if (!isEmptyObject(componentExportsMap) && realComponentsPathList.length) { + const mapKeys = Object.keys(componentExportsMap) + realComponentsPathList.forEach(component => { + if (mapKeys.indexOf(component.path as string) >= 0) { + const componentMap = componentExportsMap.get(component.path as string) + componentMap && componentMap.forEach(component => { + pageDepComponents.forEach(depComponent => { + if (depComponent.name === component.name) { + let componentPath = component.path + let realPath + if (NODE_MODULES_REG.test(componentPath as string)) { + componentPath = (componentPath as string).replace(nodeModulesPath, npmOutputDir) + realPath = promoteRelativePath(path.relative(outputPageJSPath, componentPath)) + } else { + realPath = promoteRelativePath(path.relative(pageJs, componentPath as string)) + } + depComponent.path = realPath.replace(path.extname(realPath), '') + } + }) + }) + } + }) + } const fileDep = dependencyTree.get(pageJs) || {} if (!isQuickApp) { fs.writeFileSync(outputPageJSONPath, JSON.stringify(_.merge({}, buildUsingComponents(pageJs, pageDepComponents), res.configObj), null, 2)) @@ -145,89 +207,12 @@ export async function buildSinglePage (page: string) { if (isDifferentArray(fileDep['media'], res.mediaFiles)) { copyFilesFromSrcToOutput(res.mediaFiles) } + depComponents.set(pageJs, pageDepComponents) fileDep['style'] = res.styleFiles fileDep['script'] = res.scriptFiles fileDep['json'] = res.jsonFiles fileDep['media'] = res.mediaFiles dependencyTree[pageJs] = fileDep - if (!isQuickApp) { - resCode = await compileScriptFile(resCode, pageJs, outputPageJSPath, buildAdapter) - if (isProduction) { - uglifyJS(resCode, pageJs) - } - // 编译依赖的组件文件 - let realComponentsPathList: IComponentObj[] = [] - if (pageDepComponents.length) { - realComponentsPathList = getRealComponentsPathList(pageJs, pageDepComponents) - res.scriptFiles = res.scriptFiles.map(item => { - for (let i = 0; i < realComponentsPathList.length; i++) { - const componentObj = realComponentsPathList[i] - const componentPath = componentObj.path - if (item === componentPath) { - return '' - } - } - return item - }).filter(item => item) - await buildDepComponents(realComponentsPathList) - } - const componentExportsMap = getComponentExportsMap() - if (!isEmptyObject(componentExportsMap) && realComponentsPathList.length) { - const mapKeys = Object.keys(componentExportsMap) - realComponentsPathList.forEach(component => { - if (mapKeys.indexOf(component.path as string) >= 0) { - const componentMap = componentExportsMap.get(component.path as string) - componentMap && componentMap.forEach(component => { - pageDepComponents.forEach(depComponent => { - if (depComponent.name === component.name) { - let componentPath = component.path - let realPath - if (NODE_MODULES_REG.test(componentPath as string)) { - componentPath = (componentPath as string).replace(nodeModulesPath, npmOutputDir) - realPath = promoteRelativePath(path.relative(outputPageJSPath, componentPath)) - } else { - realPath = promoteRelativePath(path.relative(pageJs, componentPath as string)) - } - depComponent.path = realPath.replace(path.extname(realPath), '') - } - }) - }) - } - }) - } - depComponents.set(pageJs, pageDepComponents) - } else { - // 快应用编译,搜集创建页面 ux 文件 - const importTaroSelfComponents = new Set<{ path: string, name: string }>() - const taroJsQuickAppComponentsPkg = getInstalledNpmPkgPath(taroJsQuickAppComponents, nodeModulesPath) - if (!taroJsQuickAppComponentsPkg) { - printLog(processTypeEnum.ERROR, '包安装', `缺少包 ${taroJsQuickAppComponents},请安装!`) - process.exit(0) - } - const taroJsQuickAppComponentsPath = path.join(path.dirname(taroJsQuickAppComponentsPkg as string), 'src/components') - res.taroSelfComponents.forEach(c => { - const cPath = path.join(taroJsQuickAppComponentsPath, c) - const cMainPath = path.join(cPath, 'index') - const cFiles = fs.readdirSync(cPath).map(item => path.join(cPath, item)) - copyFilesFromSrcToOutput(cFiles) - const cRelativePath = promoteRelativePath(path.relative(outputPageJSPath, cMainPath.replace(nodeModulesPath, npmOutputDir))) - importTaroSelfComponents.add({ - path: cRelativePath, - name: c - }) - }) - // 快应用编译组件 - // TODO - const styleRelativePath = promoteRelativePath(path.relative(outputPageJSPath, outputPageWXSSPath)) - const uxTxt = generateQuickAppUx({ - script: resCode, - style: styleRelativePath, - imports: importTaroSelfComponents, - template: pageWXMLContent - }) - fs.writeFileSync(outputPageWXMLPath, uxTxt) - printLog(processTypeEnum.GENERATE, '页面文件', `${outputDirName}/${page}${outputFilesTypes.TEMPL}`) - } } catch (err) { printLog(processTypeEnum.ERROR, '页面编译', `页面${pagePath}编译失败!`) console.log(err) From 203b7e87363b59d6c9e852b2521b7f59ab78a611 Mon Sep 17 00:00:00 2001 From: yuche Date: Fri, 15 Mar 2019 16:44:36 +0800 Subject: [PATCH 045/103] =?UTF-8?q?refactor(transformer):=20=E5=9C=A8?= =?UTF-8?q?=E5=BF=AB=E5=BA=94=E7=94=A8=E4=B8=AD=E4=BD=BF=E7=94=A8=20div=20?= =?UTF-8?q?=E6=9B=BF=E4=BB=A3=20block?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/index.ts | 1 + packages/taro-transformer-wx/src/jsx.ts | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/taro-transformer-wx/src/index.ts b/packages/taro-transformer-wx/src/index.ts index 142ded937b65..c983121a702b 100644 --- a/packages/taro-transformer-wx/src/index.ts +++ b/packages/taro-transformer-wx/src/index.ts @@ -149,6 +149,7 @@ interface TransformResult extends Result { export default function transform (options: Options): TransformResult { if (options.adapter) { setAdapter(options.adapter) + if (Adapter.type === Adapters.quickapp) DEFAULT_Component_SET.add('div') } if (Adapter.type === Adapters.swan) { setLoopOriginal('privateOriginal') diff --git a/packages/taro-transformer-wx/src/jsx.ts b/packages/taro-transformer-wx/src/jsx.ts index ee54c5d0a176..88fc4757a1c9 100644 --- a/packages/taro-transformer-wx/src/jsx.ts +++ b/packages/taro-transformer-wx/src/jsx.ts @@ -113,9 +113,10 @@ export function isAllLiteral (...args) { } export function buildBlockElement () { + const blockName = Adapter.type === Adapters.quickapp ? 'div' : 'block' return t.jSXElement( - t.jSXOpeningElement(t.jSXIdentifier('block'), []), - t.jSXClosingElement(t.jSXIdentifier('block')), + t.jSXOpeningElement(t.jSXIdentifier(blockName), []), + t.jSXClosingElement(t.jSXIdentifier(blockName)), [] ) } From 1012e7e121c31cf08acd35dfb6ba674c4935735b Mon Sep 17 00:00:00 2001 From: yuche Date: Fri, 15 Mar 2019 16:59:48 +0800 Subject: [PATCH 046/103] =?UTF-8?q?refactor(transformer):=20=E4=B8=8E?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=86=85=E7=BD=AE=E7=BB=84=E4=BB=B6=E9=87=8D?= =?UTF-8?q?=E5=90=8D=E7=9A=84=E5=BF=AB=E5=BA=94=E7=94=A8=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E9=87=8D=E5=91=BD=E5=90=8D=E4=B8=BA=20Taro=20=E5=BC=80?= =?UTF-8?q?=E5=A4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/constant.ts | 17 +++++++++++++++++ packages/taro-transformer-wx/src/index.ts | 15 ++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/taro-transformer-wx/src/constant.ts b/packages/taro-transformer-wx/src/constant.ts index 8b99b01e83b6..c986a565f897 100644 --- a/packages/taro-transformer-wx/src/constant.ts +++ b/packages/taro-transformer-wx/src/constant.ts @@ -117,3 +117,20 @@ TRANSFORM_COMPONENT_PROPS.set(Adapters.alipay, { }) export const lessThanSignPlacehold = '__LESS_THAN_SIGN_PLACEHOLDER__' + +export const quickappComponentName = new Set([ + 'Swiper', + 'Image', + 'Progress', + 'Text', + 'Input', + 'Label', + 'Picker', + 'Slider', + 'Switch', + 'Textarea', + 'Video', + 'Camera', + 'Canvas', + 'Map' +]) diff --git a/packages/taro-transformer-wx/src/index.ts b/packages/taro-transformer-wx/src/index.ts index c983121a702b..9aaa288d632a 100644 --- a/packages/taro-transformer-wx/src/index.ts +++ b/packages/taro-transformer-wx/src/index.ts @@ -14,7 +14,7 @@ import { getSuperClassCode } from './utils' import * as t from 'babel-types' -import { DEFAULT_Component_SET, INTERNAL_SAFE_GET, TARO_PACKAGE_NAME, REDUX_PACKAGE_NAME, MOBX_PACKAGE_NAME, IMAGE_COMPONENTS, INTERNAL_INLINE_STYLE, THIRD_PARTY_COMPONENTS, INTERNAL_GET_ORIGNAL, setLoopOriginal, GEL_ELEMENT_BY_ID, lessThanSignPlacehold } from './constant' +import { DEFAULT_Component_SET, INTERNAL_SAFE_GET, TARO_PACKAGE_NAME, REDUX_PACKAGE_NAME, MOBX_PACKAGE_NAME, IMAGE_COMPONENTS, INTERNAL_INLINE_STYLE, THIRD_PARTY_COMPONENTS, INTERNAL_GET_ORIGNAL, setLoopOriginal, GEL_ELEMENT_BY_ID, lessThanSignPlacehold, COMPONENTS_PACKAGE_NAME, quickappComponentName } from './constant' import { Adapters, setAdapter, Adapter } from './adapter' import { Options, setTransformOptions, buildBabelTransformOptions } from './options' import { get as safeGet } from 'lodash' @@ -488,6 +488,19 @@ export default function transform (options: Options): TransformResult { importSources.add(source) } const names: string[] = [] + if (source === COMPONENTS_PACKAGE_NAME && Adapters.quickapp === Adapter.type) { + path.node.specifiers.forEach((s) => { + if (t.isImportSpecifier(s)) { + const originalName = s.imported.name + if (quickappComponentName.has(originalName)) { + const importedName = `Taro${originalName}` + s.imported.name = importedName + s.local.name = importedName + path.scope.rename(originalName, importedName) + } + } + }) + } if (source === TARO_PACKAGE_NAME) { isImportTaro = true path.node.specifiers.push( From 8548aa818997fce229a161a061449f359e64eab9 Mon Sep 17 00:00:00 2001 From: yuche Date: Mon, 18 Mar 2019 17:27:14 +0800 Subject: [PATCH 047/103] =?UTF-8?q?refactor(transformer):=20=20=E5=BF=AB?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E7=89=B9=E6=AE=8A=E7=BB=84=E4=BB=B6=E4=B8=8D?= =?UTF-8?q?=E7=94=A8=E5=8A=A0=E5=85=A5=E8=BF=94=E5=9B=9E=E7=9A=84=20compon?= =?UTF-8?q?ents?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/class.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/taro-transformer-wx/src/class.ts b/packages/taro-transformer-wx/src/class.ts index 9253fe0b5296..b825454b10dc 100644 --- a/packages/taro-transformer-wx/src/class.ts +++ b/packages/taro-transformer-wx/src/class.ts @@ -13,7 +13,7 @@ import { incrementId, isContainStopPropagation } from './utils' -import { DEFAULT_Component_SET } from './constant' +import { DEFAULT_Component_SET, COMPONENTS_PACKAGE_NAME } from './constant' import { kebabCase, uniqueId, get as safeGet, set as safeSet } from 'lodash' import { RenderParser } from './render' import { findJSXAttrByName } from './jsx' @@ -652,6 +652,9 @@ class Transformer { setComponents () { this.customComponents.forEach((component, name) => { + if (name.startsWith('Taro') && component.sourcePath === COMPONENTS_PACKAGE_NAME) { + return + } this.result.components.push({ path: pathResolver(component.sourcePath, this.sourcePath), name: kebabCase(name), From d9c8fc1c401e7390a9c5212a680605e76f5fe13c Mon Sep 17 00:00:00 2001 From: yuche Date: Mon, 18 Mar 2019 20:36:19 +0800 Subject: [PATCH 048/103] =?UTF-8?q?refactor(transformer):=20=E7=BD=AE?= =?UTF-8?q?=E6=8D=A2=E7=89=B9=E6=AE=8A=E7=BB=84=E4=BB=B6=E6=94=BE=E5=88=B0?= =?UTF-8?q?=E6=9C=80=E5=90=8E=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../taro-transformer-wx/src/create-html-element.ts | 11 +++++++++++ packages/taro-transformer-wx/src/index.ts | 1 - 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/taro-transformer-wx/src/create-html-element.ts b/packages/taro-transformer-wx/src/create-html-element.ts index e0af61a9cdfc..7349e2748699 100644 --- a/packages/taro-transformer-wx/src/create-html-element.ts +++ b/packages/taro-transformer-wx/src/create-html-element.ts @@ -1,3 +1,6 @@ +import { Adapters, Adapter } from './adapter' +import { quickappComponentName } from './constant' + const voidHtmlTags = new Set([ // 'image', 'img', @@ -52,6 +55,14 @@ export const createHTMLElement = (options: Options) => { options ) + if (Adapters.quickapp === Adapter.type) { + const name = options.name + const nameCapitalized = name.charAt(0).toUpperCase() + name.slice(1) + if (quickappComponentName.has(nameCapitalized)) { + options.name = `taro-${name}` + } + } + const isVoidTag = voidHtmlTags.has(options.name) let ret = `<${options.name}${stringifyAttributes(options.attributes)}${isVoidTag ? `/` : '' }>` diff --git a/packages/taro-transformer-wx/src/index.ts b/packages/taro-transformer-wx/src/index.ts index 9aaa288d632a..c9c42fc236b1 100644 --- a/packages/taro-transformer-wx/src/index.ts +++ b/packages/taro-transformer-wx/src/index.ts @@ -496,7 +496,6 @@ export default function transform (options: Options): TransformResult { const importedName = `Taro${originalName}` s.imported.name = importedName s.local.name = importedName - path.scope.rename(originalName, importedName) } } }) From 4be247070f35cba2fb39bcbd30b696fea10b7799 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Wed, 20 Mar 2019 17:45:58 +0800 Subject: [PATCH 049/103] =?UTF-8?q?feat(quickapp):=20=E5=BF=AB=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E8=BF=90=E8=A1=8C=E6=97=B6=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/src/mini/component.ts | 4 +- packages/taro-cli/src/mini/page.ts | 5 +- .../taro-cli/src/util/resolve_npm_files.ts | 2 +- packages/taro-quickapp/package.json | 4 +- packages/taro-quickapp/src/component.js | 13 +- .../taro-quickapp/src/create-component.js | 149 ++++++++++++ packages/taro-quickapp/src/data-cache.js | 15 ++ packages/taro-quickapp/src/lifecycle.js | 97 ++++++++ packages/taro-quickapp/src/next-tick.js | 7 + packages/taro-quickapp/src/render-queue.js | 23 ++ packages/taro-quickapp/src/util.js | 226 ++++++++++++++++++ 11 files changed, 535 insertions(+), 10 deletions(-) create mode 100644 packages/taro-quickapp/src/data-cache.js create mode 100644 packages/taro-quickapp/src/lifecycle.js create mode 100644 packages/taro-quickapp/src/next-tick.js create mode 100644 packages/taro-quickapp/src/render-queue.js create mode 100644 packages/taro-quickapp/src/util.js diff --git a/packages/taro-cli/src/mini/component.ts b/packages/taro-cli/src/mini/component.ts index e0eac96e80d4..b0c8c4244871 100644 --- a/packages/taro-cli/src/mini/component.ts +++ b/packages/taro-cli/src/mini/component.ts @@ -13,15 +13,13 @@ import { NODE_MODULES_REG, NODE_MODULES, PARSE_AST_TYPE, - BUILD_TYPES, - taroJsQuickAppComponents + BUILD_TYPES } from '../util/constants' import { printLog, isEmptyObject, promoteRelativePath, isDifferentArray, - getInstalledNpmPkgPath, generateQuickAppUx } from '../util' diff --git a/packages/taro-cli/src/mini/page.ts b/packages/taro-cli/src/mini/page.ts index 5c5de904ffc7..be91440b89f8 100644 --- a/packages/taro-cli/src/mini/page.ts +++ b/packages/taro-cli/src/mini/page.ts @@ -11,8 +11,7 @@ import { NODE_MODULES_REG, PARSE_AST_TYPE, taroJsFramework, - BUILD_TYPES, - taroJsQuickAppComponents + BUILD_TYPES } from '../util/constants' import { resolveScriptPath, @@ -21,7 +20,6 @@ import { promoteRelativePath, isDifferentArray, copyFileSync, - getInstalledNpmPkgPath, generateQuickAppUx } from '../util' import { IWxTransformResult } from '../util/types' @@ -36,7 +34,6 @@ import { getDependencyTree, getComponentExportsMap, getDepComponents, - getTaroJsQuickAppComponentsPath, getImportTaroSelfComponents } from './helper' import { compileDepScripts, compileScriptFile } from './compileScript' diff --git a/packages/taro-cli/src/util/resolve_npm_files.ts b/packages/taro-cli/src/util/resolve_npm_files.ts index 39707027d8a7..e57325a2ef47 100644 --- a/packages/taro-cli/src/util/resolve_npm_files.ts +++ b/packages/taro-cli/src/util/resolve_npm_files.ts @@ -139,7 +139,7 @@ function parseAst ( const args = node.arguments as Array let requirePath = args[0].value if (excludeRequire.indexOf(requirePath) < 0) { - if (!isQuickAppPkg(requirePath)) { + if (isQuickAppPkg(requirePath)) { return } if (isNpmPkg(requirePath)) { diff --git a/packages/taro-quickapp/package.json b/packages/taro-quickapp/package.json index c800e5b32fa0..8116513d5d0e 100644 --- a/packages/taro-quickapp/package.json +++ b/packages/taro-quickapp/package.json @@ -24,6 +24,8 @@ "license": "MIT", "dependencies": { "@tarojs/taro": "1.2.13", - "@tarojs/utils": "1.2.13" + "@tarojs/utils": "1.2.13", + "lodash": "^4.17.10", + "prop-types": "^15.6.1" } } diff --git a/packages/taro-quickapp/src/component.js b/packages/taro-quickapp/src/component.js index 152a402c3361..605bc98b096e 100644 --- a/packages/taro-quickapp/src/component.js +++ b/packages/taro-quickapp/src/component.js @@ -1,6 +1,8 @@ import { internal_safe_get as safeGet } from '@tarojs/taro' +import { enqueueRender } from './render-queue' +import { updateComponent } from './lifecycle' export default class BaseComponent { // _createData的时候生成,小程序中通过data.__createData访问 @@ -33,7 +35,15 @@ export default class BaseComponent { this.$scope = scope } setState (state, callback) { - + if (state) { + (this._pendingStates = this._pendingStates || []).push(state) + } + if (typeof callback === 'function') { + (this._pendingCallbacks = this._pendingCallbacks || []).push(callback) + } + if (!this._disable) { + enqueueRender(this) + } } getState () { @@ -58,6 +68,7 @@ export default class BaseComponent { if (typeof callback === 'function') { (this._pendingCallbacks = this._pendingCallbacks || []).push(callback) } + updateComponent(this) } // 会被匿名函数调用 diff --git a/packages/taro-quickapp/src/create-component.js b/packages/taro-quickapp/src/create-component.js index 5eb23c89978a..fe6f5fdc5714 100644 --- a/packages/taro-quickapp/src/create-component.js +++ b/packages/taro-quickapp/src/create-component.js @@ -1,3 +1,152 @@ +import { isEmptyObject, queryToJson } from './util' +import { cacheDataGet, cacheDataHas } from './data-cache' +import { updateComponent } from './lifecycle' + +const privatePropValName = '__triggerObserer' +const componentFnReg = /^__fn_/ +const PRELOAD_DATA_KEY = 'preload' +const pageExtraFns = ['onBackPress', 'onMenuPress'] + +function filterProps (properties, defaultProps = {}, componentProps = {}, componentData) { + let newProps = Object.assign({}, componentProps) + for (const propName in properties) { + if (propName === privatePropValName) { + continue + } + if (typeof componentProps[propName] === 'function') { + newProps[propName] = componentProps[propName] + } else if (propName in componentData) { + newProps[propName] = componentData[propName] + } + if (componentFnReg.test(propName)) { + if (componentData[propName] === true) { + const fnName = propName.replace(componentFnReg, '') + newProps[fnName] = noop + } + delete newProps[propName] + } + } + if (!isEmptyObject(defaultProps)) { + for (const propName in defaultProps) { + if (newProps[propName] === undefined || newProps[propName] === null) { + newProps[propName] = defaultProps[propName] + } + } + } + return newProps +} + +function getPageUrlParams (url) { + const queryStr = url.replace(/^.*\?&?/, '') + const params = queryToJson(queryStr) + return params +} + +let hasPageInited = false + +function initComponent (ComponentClass, isPage) { + if (this.$component.__isReady) return + this.$component.__isReady = true + if (isPage && !hasPageInited) { + hasPageInited = true + } + if (hasPageInited && !isPage) { + const nextProps = filterProps(ComponentClass.properties, ComponentClass.defaultProps, this.$component.props, this) + this.$component.props = nextProps + } + if (hasPageInited || isPage) { + updateComponent(this.$component) + } +} + +export function componentTrigger (component, key, args) { + args = args || [] + + component[key] && typeof component[key] === 'function' && component[key].call(component, ...args) + if (key === 'componentWillMount') { + component._dirty = false + component._disable = false + component.state = component.getState() + } + if (key === 'componentWillUnmount') { + component._dirty = true + component._disable = true + component.$router = { + params: {}, + path: '' + } + component._pendingStates = [] + component._pendingCallbacks = [] + } +} + export default function createComponent (ComponentClass, isPage) { + let initData = {} + const componentProps = filterProps(ComponentClass.properties, ComponentClass.defaultProps) + const componentInstance = new ComponentClass(componentProps) + componentInstance._constructor && componentInstance._constructor(componentProps) + try { + componentInstance.state = componentInstance._createData() || componentInstance.state + } catch (err) { + if (isPage) { + console.warn(`[Taro warn] 请给页面提供初始 \`state\` 以提高初次渲染性能!`) + } else { + console.warn(`[Taro warn] 请给组件提供一个 \`defaultProps\` 以提高初次渲染性能!`) + } + console.warn(err) + } + initData = Object.assign({}, initData, componentInstance.props, componentInstance.state) + const componentConf = { + data: initData, + onInit () { + isPage && (hasPageInited = false) + this.$component = new ComponentClass({}, isPage) + this.$component._init(this) + this.$component.render = this.$component._createData + this.$component.__propTypes = ComponentClass.propTypes + Object.assign(this.$component.$router.params, getPageUrlParams(this.$page.uri)) + if (isPage) { + if (cacheDataHas(PRELOAD_DATA_KEY)) { + const data = cacheDataGet(PRELOAD_DATA_KEY, true) + this.$component.$router.preload = data + } + // this.$component.$router.path = getCurrentPageUrl() + initComponent.apply(this, [ComponentClass, isPage]) + } + }, + + onReady () { + if (!isPage) { + initComponent.apply(this, [ComponentClass, isPage]) + } + const component = this.$component + if (!component.__mounted) { + component.__mounted = true + componentTrigger(component, 'componentDidMount') + } + }, + onDestroy () { + componentTrigger(this.$component, 'componentWillUnmount') + } + } + if (isPage) { + componentConf['onShow'] = function () { + componentTrigger(this.$component, 'componentDidShow') + } + componentConf['onHide'] = function () { + componentTrigger(this.$component, 'componentDidHide') + } + pageExtraFns.forEach(fn => { + if (componentInstance[fn] && typeof componentInstance[fn] === 'function') { + componentConf[fn] = function () { + const component = this.$component + if (component[fn] && typeof component[fn] === 'function') { + return component[fn](...arguments) + } + } + } + }) + } + return componentConf } diff --git a/packages/taro-quickapp/src/data-cache.js b/packages/taro-quickapp/src/data-cache.js new file mode 100644 index 000000000000..f11a760035da --- /dev/null +++ b/packages/taro-quickapp/src/data-cache.js @@ -0,0 +1,15 @@ +const data = {} + +export function cacheDataSet (key, val) { + data[key] = val +} + +export function cacheDataGet (key, delelteAfterGet) { + const temp = data[key] + delelteAfterGet && delete data[key] + return temp +} + +export function cacheDataHas (key) { + return key in data +} diff --git a/packages/taro-quickapp/src/lifecycle.js b/packages/taro-quickapp/src/lifecycle.js new file mode 100644 index 000000000000..0bb63bfebb99 --- /dev/null +++ b/packages/taro-quickapp/src/lifecycle.js @@ -0,0 +1,97 @@ +import PropTypes from 'prop-types' +import { + internal_safe_get as safeGet, + internal_safe_set as safeSet +} from '@tarojs/taro' +import { componentTrigger } from './create-component' +import { shakeFnFromObject, isEmptyObject } from './util' + +const isDEV = typeof process === 'undefined' || + !process.env || + process.env.NODE_ENV !== 'production' +const privatePropKeyName = '_triggerObserer' + +export function updateComponent (component) { + const { props, __propTypes } = component + if (isDEV && __propTypes) { + const componentName = component.constructor.name || component.constructor.toString().match(/^function\s*([^\s(]+)/)[1] + PropTypes.checkPropTypes(__propTypes, props, 'prop', componentName) + } + const prevProps = component.prevProps || props + component.props = prevProps + if (component.__mounted && component._unsafeCallUpdate === true && component.componentWillReceiveProps) { + component._disable = true + component.componentWillReceiveProps(props) + component._disable = false + } + // 在willMount前执行构造函数的副本 + if (!component.__componentWillMountTriggered) { + component._constructor && component._constructor(props) + } + let state = component.getState() + + const prevState = component.prevState || state + + let skip = false + if (component.__mounted) { + if (typeof component.shouldComponentUpdate === 'function' && + component.shouldComponentUpdate(props, state) === false) { + skip = true + } else if (typeof component.componentWillUpdate === 'function') { + component.componentWillUpdate(props, state) + } + } + component.props = props + component.state = state + component._dirty = false + if (!component.__componentWillMountTriggered) { + component.__componentWillMountTriggered = true + componentTrigger(component, 'componentWillMount') + } + if (!skip) { + doUpdate(component, prevProps, prevState) + } + component.prevProps = component.props + component.prevState = component.state +} + +function doUpdate (component, prevProps, prevState) { + const { state, props = {} } = component + let data = state || {} + if (component._createData) { + // 返回null或undefined则保持不变 + data = component._createData(state, props) || data + } + let privatePropKeyVal = component.$scope[privatePropKeyName] || false + + data = Object.assign({}, props, data) + if (component.$usedState && component.$usedState.length) { + const _data = {} + component.$usedState.forEach(key => { + let val = safeGet(data, key) + if (typeof val === 'undefined') { + return + } + if (typeof val === 'object') { + if (isEmptyObject(val)) return safeSet(_data, key, val) + + val = shakeFnFromObject(val) + // 避免筛选完 Fn 后产生了空对象还去渲染 + if (!isEmptyObject(val)) safeSet(_data, key, val) + } else { + safeSet(_data, key, val) + } + }) + data = _data + } + // 改变这个私有的props用来触发(observer)子组件的更新 + data[privatePropKeyName] = !privatePropKeyVal + + const __mounted = component.__mounted + // 每次 setData 都独立生成一个 callback 数组 + let cbs = [] + if (component._pendingCallbacks && component._pendingCallbacks.length) { + cbs = component._pendingCallbacks + component._pendingCallbacks = [] + } +} diff --git a/packages/taro-quickapp/src/next-tick.js b/packages/taro-quickapp/src/next-tick.js new file mode 100644 index 000000000000..567665ffe8ad --- /dev/null +++ b/packages/taro-quickapp/src/next-tick.js @@ -0,0 +1,7 @@ +const nextTick = (fn, ...args) => { + fn = typeof fn === 'function' ? fn.bind(null, ...args) : fn + const timerFunc = setTimeout + timerFunc(fn) +} + +export default nextTick diff --git a/packages/taro-quickapp/src/render-queue.js b/packages/taro-quickapp/src/render-queue.js new file mode 100644 index 000000000000..9f2c40f7767e --- /dev/null +++ b/packages/taro-quickapp/src/render-queue.js @@ -0,0 +1,23 @@ +import nextTick from './next-tick' +import { updateComponent } from './lifecycle' + +let items = [] + +export function enqueueRender (component) { + // tslint:disable-next-line:no-conditional-assignment + if (!component._dirty && (component._dirty = true) && items.push(component) === 1) { + nextTick(rerender) + } +} + +export function rerender () { + let p + const list = items + items = [] + // tslint:disable-next-line:no-conditional-assignment + while ((p = list.pop())) { + if (p._dirty) { + updateComponent(p, true) + } + } +} diff --git a/packages/taro-quickapp/src/util.js b/packages/taro-quickapp/src/util.js new file mode 100644 index 000000000000..dec47b85ecde --- /dev/null +++ b/packages/taro-quickapp/src/util.js @@ -0,0 +1,226 @@ +import isPlainObject from 'lodash/isPlainObject' + +export function isEmptyObject (obj) { + if (!obj || !isPlainObject(obj)) { + return false + } + for (const n in obj) { + if (obj.hasOwnProperty(n)) { + return false + } + } + return true +} + +/** + * JSON 克隆 + * @param {Object | Json} jsonObj json对象 + * @return {Object | Json} 新的json对象 + */ +export function objClone (jsonObj) { + let buf + if (Array.isArray(jsonObj)) { + buf = [] + let i = jsonObj.length + while (i--) { + buf[i] = objClone(jsonObj[i]) + } + return buf + } else if (isPlainObject(jsonObj)) { + buf = {} + for (const k in jsonObj) { + buf[k] = objClone(jsonObj[k]) + } + return buf + } else { + return jsonObj + } +} + +export function getPrototype (obj) { + /* eslint-disable */ + if (Object.getPrototypeOf) { + return Object.getPrototypeOf(obj) + } else if (obj.__proto__) { + return obj.__proto__ + } + /* eslint-enable */ + return obj.constructor.prototype +} + +export function getPrototypeChain (obj) { + const protoChain = [] + while ((obj = getPrototype(obj))) { + protoChain.push(obj) + } + return protoChain +} + +export function noop () {} + +export function isFunction (arg) { + return typeof arg === 'function' +} + +export function isArray (arg) { + return Array.isArray(arg) +} + +export function shakeFnFromObject (obj) { + let newObj + if (isArray(obj)) { + newObj = [] + const len = obj.length + for (let i = 0; i < len; i++) { + newObj.push(shakeFnFromObject(obj[i])) + } + } else if (isPlainObject(obj)) { + newObj = {} + for (const key in obj) { + if (isFunction(obj[key])) { + continue + } + const ret = shakeFnFromObject(obj[key]) + newObj[key] = ret + } + } else { + return obj + } + return newObj +} + +const keyList = Object.keys +const hasProp = Object.prototype.hasOwnProperty + +function diffArrToPath (to, from, res = {}, keyPrev = '') { + const len = to.length + for (let i = 0; i < len; i++) { + const toItem = to[i] + const fromItem = from[i] + const targetKey = `${keyPrev}[${i}]` + if (toItem === fromItem) { + continue + } else if (typeof toItem !== typeof fromItem) { + res[targetKey] = toItem + } else { + if (typeof toItem !== 'object') { + res[targetKey] = toItem + } else { + const arrTo = isArray(toItem) + const arrFrom = isArray(fromItem) + if (arrTo !== arrFrom) { + res[targetKey] = toItem + } else if (arrTo && arrFrom) { + if (toItem.length < fromItem.length) { + res[targetKey] = toItem + } else { + // 数组 + diffArrToPath(toItem, fromItem, res, `${targetKey}`) + } + } else { + if (!toItem || !fromItem || keyList(toItem).length < keyList(fromItem).length) { + res[targetKey] = toItem + } else { + // 对象 + diffObjToPath(toItem, fromItem, res, `${targetKey}.`) + } + } + } + } + } + return res +} + +// 比较的对象均为plainObject,且函数已被过滤 +export function diffObjToPath (to, from, res = {}, keyPrev = '') { + const keys = keyList(to) + const len = keys.length + + for (let i = 0; i < len; i++) { + const key = keys[i] + const toItem = to[key] + const fromItem = from[key] + const targetKey = `${keyPrev}${key}` + if (toItem === fromItem) { + continue + } else + if (!hasProp.call(from, key)) { + res[targetKey] = toItem + } else + if (typeof toItem !== typeof fromItem) { + res[targetKey] = toItem + } else { + if (typeof toItem !== 'object') { + res[targetKey] = toItem + } else { + const arrTo = isArray(toItem) + const arrFrom = isArray(fromItem) + if (arrTo !== arrFrom) { + res[targetKey] = toItem + } else if (arrTo && arrFrom) { + if (toItem.length < fromItem.length) { + res[targetKey] = toItem + } else { + // 数组 + diffArrToPath(toItem, fromItem, res, `${targetKey}`) + } + } else { + // null + if (!toItem || !fromItem || keyList(toItem).length < keyList(fromItem).length) { + res[targetKey] = toItem + } else { + // 对象 + diffObjToPath(toItem, fromItem, res, `${targetKey}.`) + } + } + } + } + } + return res +} + +export function queryToJson (str) { + const dec = decodeURIComponent + const qp = str.split('&') + let ret = {} + let name + let val + for (let i = 0, l = qp.length, item; i < l; ++i) { + item = qp[i] + if (item.length) { + const s = item.indexOf('=') + if (s < 0) { + name = dec(item) + val = '' + } else { + name = dec(item.slice(0, s)) + val = dec(item.slice(s + 1)) + } + if (typeof ret[name] === 'string') { // inline'd type check + ret[name] = [ret[name]] + } + + if (isArray(ret[name])) { + ret[name].push(val) + } else { + ret[name] = val + } + } + } + return ret // Object +} + +const _loadTime = (new Date()).getTime().toString() +let _i = 1 +export function getUniqueKey () { + return _loadTime + (_i++) +} + +export function getObjChainValue (obj, keyChain) { + const keys = keyChain.split('.') + for (let i = 0, len = keys.length; i < len; i++) { + const key = keys[i] + if (i === len - 1) return obj[key] + obj = obj[key] + } +} From decb7e30e424e426a5c5ba9aa03e653e25f688bf Mon Sep 17 00:00:00 2001 From: luckyadam Date: Tue, 26 Mar 2019 22:25:43 +0800 Subject: [PATCH 050/103] =?UTF-8?q?feat(cli):=20=E5=BF=AB=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E7=BC=96=E8=AF=91=E7=8E=AF=E5=A2=83=E5=87=86=E5=A4=87?= =?UTF-8?q?=EF=BC=8C=E4=B8=80=E9=94=AE=E5=90=AF=E5=8A=A8=E5=BF=AB=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E7=BC=96=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/package.json | 7 +- packages/taro-cli/src/build.ts | 6 +- .../taro-cli/src/config/manifest.default.json | 20 + packages/taro-cli/src/mini/helper.ts | 16 +- packages/taro-cli/src/mini/index.ts | 160 +- packages/taro-cli/src/mini/page.ts | 5 +- packages/taro-cli/src/util/dowload.ts | 48 + packages/taro-cli/src/util/index.ts | 48 + .../taro-cli/src/util/resolve_npm_files.ts | 2 +- packages/taro-cli/yarn.lock | 1609 ++++++++++++++--- 10 files changed, 1673 insertions(+), 248 deletions(-) create mode 100644 packages/taro-cli/src/config/manifest.default.json create mode 100644 packages/taro-cli/src/util/dowload.ts diff --git a/packages/taro-cli/package.json b/packages/taro-cli/package.json index a641b767d69e..bcc2ccafba85 100644 --- a/packages/taro-cli/package.json +++ b/packages/taro-cli/package.json @@ -32,6 +32,7 @@ "dependencies": { "@tarojs/taroize": "1.2.13", "@tarojs/transformer-wx": "1.2.13", + "@types/request": "^2.48.1", "autoprefixer": "^8.4.1", "babel-core": "^6.26.3", "babel-eslint": "^8.2.3", @@ -84,16 +85,18 @@ "postcss-url": "^7.3.2", "prettier": "^1.16.4", "prop-types": "^15.6.2", + "request": "^2.88.0", "resolve": "^1.6.0", "semver": "^5.5.0", "shelljs": "^0.8.1", "through2": "^2.0.3", "vinyl": "^2.1.0", - "vinyl-fs": "^3.0.2" + "vinyl-fs": "^3.0.2", + "yauzl": "2.10.0" }, "devDependencies": { - "@types/autoprefixer": "^9.1.1", "@tarojs/taro": "^1.2.2", + "@types/autoprefixer": "^9.1.1", "@types/babel-core": "^6.25.5", "@types/babel-generator": "^6.25.2", "@types/babel-traverse": "^6.25.4", diff --git a/packages/taro-cli/src/build.ts b/packages/taro-cli/src/build.ts index 280a389f96e5..f4013fa53c7a 100644 --- a/packages/taro-cli/src/build.ts +++ b/packages/taro-cli/src/build.ts @@ -16,10 +16,8 @@ export default function build (args, buildConfig: IBuildConfig) { const outputPath = path.join(appPath, configDir.outputRoot || CONFIG.OUTPUT_DIR) if (!fs.existsSync(outputPath)) { fs.mkdirSync(outputPath) - } else { - if (type !== BUILD_TYPES.H5) { - Util.emptyDirectory(outputPath) - } + } else if (type !== BUILD_TYPES.H5 && (type !== BUILD_TYPES.QUICKAPP || !watch)) { + Util.emptyDirectory(outputPath) } switch (type) { case BUILD_TYPES.H5: diff --git a/packages/taro-cli/src/config/manifest.default.json b/packages/taro-cli/src/config/manifest.default.json new file mode 100644 index 000000000000..9d5845985a90 --- /dev/null +++ b/packages/taro-cli/src/config/manifest.default.json @@ -0,0 +1,20 @@ +{ + "package": "com.application.demo", + "name": "TaroQuickApp", + "versionName": "1.0.0", + "versionCode": "1", + "minPlatformVersion": "101", + "features": [ + { "name": "system.prompt" }, + { "name": "system.router" }, + { "name": "system.shortcut" }, + { "name": "system.fetch" }, + { "name": "system.storage" } + ], + "permissions": [ + { "origin": "*" } + ], + "config": { + "logLevel": "debug" + } +} diff --git a/packages/taro-cli/src/mini/helper.ts b/packages/taro-cli/src/mini/helper.ts index 288e7f4f7daf..8f09d64d6afa 100644 --- a/packages/taro-cli/src/mini/helper.ts +++ b/packages/taro-cli/src/mini/helper.ts @@ -2,7 +2,7 @@ import * as fs from 'fs-extra' import * as path from 'path' import * as _ from 'lodash' -import { AppConfig } from '@tarojs/taro' +import { Config } from '@tarojs/taro' import { BUILD_TYPES, @@ -78,11 +78,13 @@ export interface IBuildData { outputDirName: string, sourceDir: string, outputDir: string, + originalOutputDir: string, entryFilePath: string, entryFileName: string, projectConfig: IProjectConfig, npmConfig: INpmConfig, - appConfig: AppConfig, + appConfig: Config, + pageConfigs: Map, alias: IOption, compileInclude: string[], isProduction: boolean, @@ -100,6 +102,7 @@ const BuildData: IBuildData = { outputDirName, sourceDir, outputDir, + originalOutputDir: outputDir, entryFilePath, entryFileName, projectConfig, @@ -107,6 +110,7 @@ const BuildData: IBuildData = { alias: pathAlias, isProduction: false, appConfig: {}, + pageConfigs: new Map(), compileInclude, buildAdapter: BUILD_TYPES.WEAPP, outputFilesTypes: MINI_APP_FILES[BUILD_TYPES.WEAPP], @@ -129,7 +133,7 @@ export const shouldTransformAgain = (function () { return false })() -export function setAppConfig (appConfig: AppConfig) { +export function setAppConfig (appConfig: Config) { BuildData.appConfig = appConfig } @@ -147,6 +151,12 @@ export function setBuildAdapter (adapter: BUILD_TYPES) { BuildData.constantsReplaceList = Object.assign({}, generateEnvList(projectConfig.env || {}), generateConstantsList(projectConfig.defineConstants || {}), { 'process.env.TARO_ENV': adapter }) + if (adapter === BUILD_TYPES.QUICKAPP) { + BuildData.originalOutputDir = outputDir + BuildData.outputDirName = `${outputDirName}/src` + BuildData.outputDir = path.join(appPath, BuildData.outputDirName) + BuildData.npmOutputDir = getNpmOutputDir(BuildData.outputDir, configDir, npmConfig) + } } export function getBuildData (): IBuildData { diff --git a/packages/taro-cli/src/mini/index.ts b/packages/taro-cli/src/mini/index.ts index f53dd3ad35ea..adf4f6f20422 100644 --- a/packages/taro-cli/src/mini/index.ts +++ b/packages/taro-cli/src/mini/index.ts @@ -3,12 +3,17 @@ import * as path from 'path' import chalk from 'chalk' import * as _ from 'lodash' +import * as ora from 'ora' +import * as shelljs from 'shelljs' import { printLog, getInstalledNpmPkgVersion, getPkgVersion, - copyFiles + copyFiles, + unzip, + shouldUseYarn, + shouldUseCnpm } from '../util' import { processTypeEnum, BUILD_TYPES } from '../util/constants' import { IMiniAppBuildConfig } from '../util/types' @@ -22,25 +27,10 @@ import { import { buildEntry } from './entry' import { buildPages } from './page' import { watchFiles } from './watch' +import { downloadGithubRepoLatestRelease } from '../util/dowload' const appPath = process.cwd() -// async function checkCliAndFrameworkVersion () { -// const { buildAdapter, nodeModulesPath } = getBuildData() -// const frameworkName = `@tarojs/taro-${buildAdapter}` -// const frameworkVersion = getInstalledNpmPkgVersion(frameworkName, nodeModulesPath) -// if (frameworkVersion) { -// if (frameworkVersion !== getPkgVersion()) { -// printLog(processTypeEnum.ERROR, '版本问题', `Taro CLI 与本地安装的小程序框架 ${frameworkName} 版本不一致,请确保一致`) -// console.log(`Taro CLI: ${getPkgVersion()}`) -// console.log(`${frameworkName}: ${frameworkVersion}`) -// process.exit(1) -// } -// } else { -// printLog(processTypeEnum.WARNING, '依赖安装', chalk.red(`项目依赖 ${frameworkName} 未安装,或安装有误!`)) -// } -// } - function buildProjectConfig () { const { buildAdapter, sourceDir, outputDir, outputDirName } = getBuildData() let projectConfigFileName = `project.${buildAdapter}.json` @@ -97,18 +87,144 @@ async function buildFrameworkInfo () { } } +function generateQuickAppManifest () { + const { appConfig, pageConfigs, appPath, outputDir } = getBuildData() + // 生成 router + const pages = appConfig.pages as string[] + const routerPages = {} + pages.forEach(element => { + routerPages[path.dirname(element)] = { + component: path.basename(element), + filter: { + view: { + uri: 'https?://.*' + } + } + } + }) + const routerEntry = pages.shift() + const router = { + entry: path.dirname(routerEntry as string), + pages: routerPages + } + // 生成 display + const display = JSON.parse(JSON.stringify(appConfig.window || {})) + display.pages = {} + pageConfigs.forEach((item, page) => { + if (item) { + display.pages[path.dirname(page)] = item + } + }) + // 读取 project.quickapp.json + const quickappJSONPath = path.join(appPath, 'project.quickapp.json') + let quickappJSON + if (fs.existsSync(quickappJSONPath)) { + quickappJSON = fs.readJSONSync(quickappJSONPath) + } else { + quickappJSON = fs.readJSONSync('../config/manifest.default.json') + } + quickappJSON.router = router + quickappJSON.display = display + fs.writeFileSync(path.join(outputDir, 'manifest.json'), JSON.stringify(quickappJSON, null, 2)) +} + +async function prepareQuickAppEnvironment (isWatch, buildData) { + let isReady = false + let needDownload = false + let needInstall = false + const originalOutputDir = buildData.originalOutputDir + console.log() + if (isWatch) { + if (fs.existsSync(path.join(buildData.originalOutputDir, 'sign'))) { + needDownload = false + } else { + needDownload = true + } + } else { + needDownload = true + } + if (needDownload) { + const getSpinner = ora('开始下载快应用运行容器...').start() + await downloadGithubRepoLatestRelease('NervJS/quickapp-container', originalOutputDir) + await unzip(path.join(originalOutputDir, 'download_temp.zip')) + getSpinner.succeed('快应用运行容器下载完成') + } else { + console.log(`${chalk.green('✔ ')} 快应用容器已经准备好`) + } + + console.log() + process.chdir(originalOutputDir) + if (isWatch) { + if (fs.existsSync(path.join(originalOutputDir, 'node_modules'))) { + needInstall = false + } else { + needInstall = true + } + } else { + needInstall = true + } + if (needInstall) { + let command + if (shouldUseYarn) { + command = 'yarn install' + } else if (shouldUseCnpm()) { + command = 'cnpm install' + } else { + command = 'npm install' + } + const installSpinner = ora(`安装快应用依赖环境, 需要一会儿...`).start() + const install = shelljs.exec(command, { silent: true }) + if (install.code === 0) { + installSpinner.color = 'green' + installSpinner.succeed('安装成功') + console.log(`${install.stderr}${install.stdout}`) + isReady = true + } else { + installSpinner.color = 'red' + installSpinner.fail(chalk.red(`快应用依赖环境安装失败,请进入 ${path.basename(originalOutputDir)} 重新安装!`)) + console.log(`${install.stderr}${install.stdout}`) + isReady = false + } + } else { + console.log(`${chalk.green('✔ ')} 快应用依赖已经安装好`) + isReady = true + } + return isReady +} + +async function runQuickApp (isWatch) { + if (isWatch) { + shelljs.exec('npm run server -- --port 12306', { silent: false }) + // shelljs.exec('npm run watch', { silent: false }) + } +} + export async function build ({ watch, adapter = BUILD_TYPES.WEAPP }: IMiniAppBuildConfig) { - const { projectConfig } = getBuildData() + const buildData = getBuildData() + const isQuickApp = adapter === BUILD_TYPES.QUICKAPP process.env.TARO_ENV = adapter setIsProduction(process.env.NODE_ENV === 'production' || !watch) setBuildAdapter(adapter) - // await checkCliAndFrameworkVersion() - buildProjectConfig() - await buildFrameworkInfo() - copyFiles(appPath, projectConfig.copy) + fs.ensureDirSync(buildData.outputDir) + if (!isQuickApp) { + buildProjectConfig() + await buildFrameworkInfo() + } + copyFiles(appPath, buildData.projectConfig.copy) const appConfig = await buildEntry() setAppConfig(appConfig) await buildPages() + if (isQuickApp) { + generateQuickAppManifest() + const isReady = await prepareQuickAppEnvironment(watch, buildData) + if (!isReady) { + console.log() + console.log(chalk.red('快应用环境准备失败,请重试!')) + process.exit(0) + return + } + await runQuickApp(watch) + } // if (watch) { // watchFiles() // } diff --git a/packages/taro-cli/src/mini/page.ts b/packages/taro-cli/src/mini/page.ts index be91440b89f8..4405c7fd23bc 100644 --- a/packages/taro-cli/src/mini/page.ts +++ b/packages/taro-cli/src/mini/page.ts @@ -54,7 +54,8 @@ export async function buildSinglePage (page: string) { isProduction, outputFilesTypes, nodeModulesPath, - npmOutputDir + npmOutputDir, + pageConfigs } = getBuildData() const pagePath = path.join(sourceDir, `${page}`) const pageJs = resolveScriptPath(pagePath) @@ -105,6 +106,7 @@ export async function buildSinglePage (page: string) { const res = parseAst(PARSE_AST_TYPE.PAGE, transformResult.ast, pageDepComponents, pageJs, outputPageJSPath) let resCode = res.code fs.ensureDirSync(outputPagePath) + pageConfigs.set(page, res.configObj) // 解析原生组件 const { usingComponents = {} }: IConfig = res.configObj if (usingComponents && !isEmptyObject(usingComponents)) { @@ -178,6 +180,7 @@ export async function buildSinglePage (page: string) { } }) } + const fileDep = dependencyTree.get(pageJs) || {} if (!isQuickApp) { fs.writeFileSync(outputPageJSONPath, JSON.stringify(_.merge({}, buildUsingComponents(pageJs, pageDepComponents), res.configObj), null, 2)) diff --git a/packages/taro-cli/src/util/dowload.ts b/packages/taro-cli/src/util/dowload.ts new file mode 100644 index 000000000000..a52a5b982595 --- /dev/null +++ b/packages/taro-cli/src/util/dowload.ts @@ -0,0 +1,48 @@ +import * as fs from 'fs-extra' +import * as path from 'path' +import * as request from 'request' + +const GITHUB_API = 'https://api.github.com/' +const GITHUB = 'https://github.com/' + +export function getGithubRepoLatestReleaseVersion (repoName) { + const latestReleaseApi = `${GITHUB_API}repos/${repoName}/releases/latest` + const p = new Promise((resolve, reject) => { + request({ + url: latestReleaseApi, + headers: { + 'User-Agent': 'Awesome-Octocat-App' + } + }, (err, response, body) => { + if (err) { + throw new Error('快应用容器版本请求失败,请重试!') + } + const res = JSON.parse(body) + resolve(res.tag_name) + }) + }) + return p +} + +export async function downloadGithubRepoLatestRelease (repoName, dest) { + const latestTagName = await getGithubRepoLatestReleaseVersion(repoName) + return new Promise((resolve, reject) => { + const downloadUrl = `${GITHUB}${repoName}/archive/${latestTagName}.zip` + const downloadTemp = 'download_temp.zip' + request({ + url: downloadUrl, + headers: { + 'User-Agent': 'Awesome-Octocat-App' + } + }) + .on('error', reject) + .on('complete', () => { + const downloadTempPath = path.join(process.cwd(), downloadTemp) + if (fs.existsSync(downloadTempPath)) { + fs.moveSync(downloadTempPath, path.join(dest, downloadTemp)) + resolve() + } + }) + .pipe(fs.createWriteStream(downloadTemp)) + }) +} diff --git a/packages/taro-cli/src/util/index.ts b/packages/taro-cli/src/util/index.ts index 5e4a430fa149..336fa95494b8 100644 --- a/packages/taro-cli/src/util/index.ts +++ b/packages/taro-cli/src/util/index.ts @@ -7,6 +7,8 @@ import * as chalk from 'chalk' import * as _ from 'lodash' import * as minimatch from 'minimatch' import * as t from 'babel-types' +import * as yauzl from 'yauzl' +import { Transform } from 'stream' import { TS_EXT, @@ -529,3 +531,49 @@ export function generateQuickAppUx ({ } return uxTxt } + + +export function unzip (zipPath) { + return new Promise((resolve, reject) => { + yauzl.open(zipPath, { lazyEntries: true }, (err, zipfile) => { + if (err) throw err + zipfile.on('close', () => { + fs.removeSync(zipPath) + resolve() + }) + zipfile.readEntry() + zipfile.on('error', (err) => { + reject(err) + }) + zipfile.on('entry', entry => { + if (/\/$/.test(entry.fileName)) { + const fileNameArr = entry.fileName.replace(/\\/g, '/').split('/') + fileNameArr.shift() + const fileName = fileNameArr.join('/') + fs.ensureDirSync(path.join(path.dirname(zipPath), fileName)) + zipfile.readEntry() + } else { + zipfile.openReadStream(entry, (err, readStream) => { + if (err) throw err + const filter = new Transform() + filter._transform = function (chunk, encoding, cb) { + cb(undefined, chunk) + } + filter._flush = function (cb) { + cb() + zipfile.readEntry() + } + const fileNameArr = entry.fileName.replace(/\\/g, '/').split('/') + fileNameArr.shift() + const fileName = fileNameArr.join('/') + const writeStream = fs.createWriteStream(path.join(path.dirname(zipPath), fileName)) + writeStream.on('close', () => {}) + readStream + .pipe(filter) + .pipe(writeStream) + }) + } + }) + }) + }) +} diff --git a/packages/taro-cli/src/util/resolve_npm_files.ts b/packages/taro-cli/src/util/resolve_npm_files.ts index e57325a2ef47..170d7efdd653 100644 --- a/packages/taro-cli/src/util/resolve_npm_files.ts +++ b/packages/taro-cli/src/util/resolve_npm_files.ts @@ -194,7 +194,7 @@ async function recursiveRequire ( filePath.slice(0, filePath.search('node_modules')), process.cwd() ) - outputNpmPath = filePath.replace('node_modules', path.join(cwdRelate2Npm, outputDirName, npmConfig.name)) + outputNpmPath = filePath.replace('node_modules', path.join(cwdRelate2Npm, buildAdapter !== BUILD_TYPES.QUICKAPP ? outputDirName : `${outputDirName}/src`, npmConfig.name)) outputNpmPath = outputNpmPath.replace(/node_modules/g, npmConfig.name) } else { const matches = filePath.match(/(?=(node_modules)).*/) diff --git a/packages/taro-cli/yarn.lock b/packages/taro-cli/yarn.lock index 2f9854cbcc81..f8845a4ae46c 100644 --- a/packages/taro-cli/yarn.lock +++ b/packages/taro-cli/yarn.lock @@ -2,6 +2,12 @@ # yarn lockfile v1 +"@babel/code-frame@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9" + dependencies: + "@babel/highlight" "7.0.0-beta.44" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.0.0-beta.35", "@babel/code-frame@^7.0.0-beta.44": version "7.0.0" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" @@ -27,6 +33,16 @@ semver "^5.4.1" source-map "^0.5.0" +"@babel/generator@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42" + dependencies: + "@babel/types" "7.0.0-beta.44" + jsesc "^2.5.1" + lodash "^4.2.0" + source-map "^0.5.0" + trim-right "^1.0.1" + "@babel/generator@^7.0.0-beta", "@babel/generator@^7.2.2": version "7.2.2" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.2.2.tgz#18c816c70962640eab42fe8cae5f3947a5c65ccc" @@ -90,6 +106,14 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" +"@babel/helper-function-name@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd" + dependencies: + "@babel/helper-get-function-arity" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + "@babel/helper-function-name@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" @@ -98,6 +122,12 @@ "@babel/template" "^7.1.0" "@babel/types" "^7.0.0" +"@babel/helper-get-function-arity@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15" + dependencies: + "@babel/types" "7.0.0-beta.44" + "@babel/helper-get-function-arity@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" @@ -169,6 +199,12 @@ "@babel/template" "^7.1.0" "@babel/types" "^7.0.0" +"@babel/helper-split-export-declaration@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc" + dependencies: + "@babel/types" "7.0.0-beta.44" + "@babel/helper-split-export-declaration@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813" @@ -192,6 +228,14 @@ "@babel/traverse" "^7.1.5" "@babel/types" "^7.2.0" +"@babel/highlight@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5" + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + "@babel/highlight@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" @@ -200,7 +244,7 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.2.2", "@babel/parser@^7.2.3": +"@babel/parser@^7.2.2", "@babel/parser@^7.2.3": version "7.2.3" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.2.3.tgz#32f5df65744b70888d17872ec106b02434ba1489" @@ -399,6 +443,15 @@ pirates "^4.0.0" source-map-support "^0.5.9" +"@babel/template@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + lodash "^4.2.0" + "@babel/template@^7.0.0-beta", "@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.2.2": version "7.2.2" resolved "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907" @@ -407,7 +460,22 @@ "@babel/parser" "^7.2.2" "@babel/types" "^7.2.2" -"@babel/traverse@^7.0.0", "@babel/traverse@^7.0.0-beta", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.2.2", "@babel/traverse@^7.2.3": +"@babel/traverse@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/generator" "7.0.0-beta.44" + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/helper-split-export-declaration" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + debug "^3.1.0" + globals "^11.1.0" + invariant "^2.2.0" + lodash "^4.2.0" + +"@babel/traverse@^7.0.0-beta", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.2.2", "@babel/traverse@^7.2.3": version "7.2.3" resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz#7ff50cefa9c7c0bd2d81231fdac122f3957748d8" dependencies: @@ -421,6 +489,14 @@ globals "^11.1.0" lodash "^4.17.10" +"@babel/types@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757" + dependencies: + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^2.0.0" + "@babel/types@^7.0.0", "@babel/types@^7.0.0-beta", "@babel/types@^7.2.0", "@babel/types@^7.2.2": version "7.2.2" resolved "https://registry.npmjs.org/@babel/types/-/types-7.2.2.tgz#44e10fc24e33af524488b716cdaee5360ea8ed1e" @@ -433,9 +509,13 @@ version "0.7.0" resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" -"@tarojs/taroize@1.2.12": - version "1.2.12" - resolved "https://registry.npmjs.org/@tarojs/taroize/-/taroize-1.2.12.tgz#260bc3b7180a440c5449372e7de37926ebbd1042" +"@tarojs/taro@^1.2.2": + version "1.2.21" + resolved "https://registry.npmjs.org/@tarojs/taro/-/taro-1.2.21.tgz#87eda010381802bd71ab690e6e4ce02080b485d7" + +"@tarojs/taroize@1.2.13": + version "1.2.13" + resolved "https://registry.npmjs.org/@tarojs/taroize/-/taroize-1.2.13.tgz#8f63dab0a7e9dc0f8ca5ef687573559a90532a8b" dependencies: "@babel/code-frame" "^7.0.0" babel-core "^6.26.3" @@ -448,13 +528,13 @@ lodash "^4.17.5" typescript "^3.0.1" -"@tarojs/transformer-wx@1.2.12": - version "1.2.12" - resolved "https://registry.npmjs.org/@tarojs/transformer-wx/-/transformer-wx-1.2.12.tgz#b79aff4515dd0158006847e68b12a50c9da6327a" +"@tarojs/transformer-wx@1.2.13": + version "1.2.13" + resolved "https://registry.npmjs.org/@tarojs/transformer-wx/-/transformer-wx-1.2.13.tgz#a0d7f1754acd7d296f182db4c2fbc456bde277da" dependencies: "@babel/code-frame" "^7.0.0-beta.44" babel-core "^6.26.3" - babel-eslint "^10.0.1" + babel-eslint "^8.2.3" babel-helper-evaluate-path "^0.5.0" babel-helper-mark-eval-scopes "^0.4.3" babel-helper-remove-or-void "^0.4.3" @@ -468,13 +548,107 @@ babel-plugin-transform-flow-strip-types "^6.22.0" babel-traverse "^6.26.0" babel-types "^6.26.0" - eslint "^5.10.0" - eslint-plugin-taro "1.2.12" + eslint "^4.15.0" + eslint-plugin-taro "1.2.13" html "^1.0.0" lodash "^4.17.5" prettier "^1.14.2" typescript "^3.2.2" +"@types/autoprefixer@^9.1.1": + version "9.4.0" + resolved "https://registry.npmjs.org/@types/autoprefixer/-/autoprefixer-9.4.0.tgz#b72589130765cf8f7f403b9cec8ea81e507e759b" + dependencies: + postcss "7.x.x" + +"@types/babel-core@^6.25.5": + version "6.25.6" + resolved "https://registry.npmjs.org/@types/babel-core/-/babel-core-6.25.6.tgz#9e4faefcb300fd3abf0d2c2d85c505071462c1e1" + dependencies: + "@types/babel-generator" "*" + "@types/babel-template" "*" + "@types/babel-traverse" "*" + "@types/babel-types" "*" + "@types/babylon" "*" + +"@types/babel-generator@*", "@types/babel-generator@^6.25.2": + version "6.25.3" + resolved "https://registry.npmjs.org/@types/babel-generator/-/babel-generator-6.25.3.tgz#8f06caa12d0595a0538560abe771966d77d29286" + dependencies: + "@types/babel-types" "*" + +"@types/babel-template@*": + version "6.25.2" + resolved "https://registry.npmjs.org/@types/babel-template/-/babel-template-6.25.2.tgz#3c4cde02dbcbbf461a58d095a9f69f35eabd5f06" + dependencies: + "@types/babel-types" "*" + "@types/babylon" "*" + +"@types/babel-traverse@*", "@types/babel-traverse@^6.25.4": + version "6.25.5" + resolved "https://registry.npmjs.org/@types/babel-traverse/-/babel-traverse-6.25.5.tgz#6d293cf7523e48b524faa7b86dc3c488191484e5" + dependencies: + "@types/babel-types" "*" + +"@types/babel-types@*": + version "7.0.6" + resolved "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.6.tgz#a7cfaaeee96e90c4c54da0e580aaff3f4cffacac" + +"@types/babel-types@^6.25.2": + version "6.25.2" + resolved "https://registry.npmjs.org/@types/babel-types/-/babel-types-6.25.2.tgz#5c57f45973e4f13742dbc5273dd84cffe7373a9e" + +"@types/babylon@*": + version "6.16.5" + resolved "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.5.tgz#1c5641db69eb8cdf378edd25b4be7754beeb48b4" + dependencies: + "@types/babel-types" "*" + +"@types/caseless@*": + version "0.12.2" + resolved "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" + +"@types/form-data@*": + version "2.2.1" + resolved "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz#ee2b3b8eaa11c0938289953606b745b738c54b1e" + dependencies: + "@types/node" "*" + +"@types/fs-extra@^5.0.4": + version "5.0.5" + resolved "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.0.5.tgz#080d90a792f3fa2c5559eb44bd8ef840aae9104b" + dependencies: + "@types/node" "*" + +"@types/jest@^23.3.10": + version "23.3.14" + resolved "https://registry.npmjs.org/@types/jest/-/jest-23.3.14.tgz#37daaf78069e7948520474c87b80092ea912520a" + +"@types/lodash@^4.14.119": + version "4.14.123" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.123.tgz#39be5d211478c8dd3bdae98ee75bb7efe4abfe4d" + +"@types/node@*": + version "11.11.6" + resolved "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz#df929d1bb2eee5afdda598a41930fe50b43eaa6a" + +"@types/node@^10.12.18": + version "10.14.3" + resolved "https://registry.npmjs.org/@types/node/-/node-10.14.3.tgz#170a81168620d931cc3b83460be253cadd3028f1" + +"@types/request@^2.48.1": + version "2.48.1" + resolved "https://registry.npmjs.org/@types/request/-/request-2.48.1.tgz#e402d691aa6670fbbff1957b15f1270230ab42fa" + dependencies: + "@types/caseless" "*" + "@types/form-data" "*" + "@types/node" "*" + "@types/tough-cookie" "*" + +"@types/tough-cookie@*": + version "2.3.5" + resolved "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.5.tgz#9da44ed75571999b65c37b60c9b2b88db54c585d" + abab@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz#aba0ab4c5eee2d4c79d3487d85450fb2376ebb0f" @@ -501,23 +675,42 @@ acorn-globals@^4.1.0: acorn "^6.0.1" acorn-walk "^6.0.1" -acorn-jsx@^5.0.0: - version "5.0.1" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" +acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" acorn-walk@^6.0.1: version "6.1.1" resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz#d363b66f5fac5f018ff9c3a1e7b6f8e310cc3913" -acorn@^5.5.3: +acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +acorn@^5.5.0, acorn@^5.5.3: version "5.7.3" resolved "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" -acorn@^6.0.1, acorn@^6.0.2: +acorn@^6.0.1: version "6.0.5" resolved "https://registry.npmjs.org/acorn/-/acorn-6.0.5.tgz#81730c0815f3f3b34d8efa95cb7430965f4d887a" -ajv@^6.5.3, ajv@^6.5.5, ajv@^6.6.1: +ajv-keywords@^2.1.0: + version "2.1.1" + resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" + +ajv@^5.2.3, ajv@^5.3.0: + version "5.5.2" + resolved "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +ajv@^6.5.5: version "6.6.2" resolved "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz#caceccf474bf3fc3ce3b147443711a24063cc30d" dependencies: @@ -526,6 +719,12 @@ ajv@^6.5.3, ajv@^6.5.5, ajv@^6.6.1: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ansi-align@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" + dependencies: + string-width "^2.0.0" + ansi-colors@^1.0.1: version "1.1.0" resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9" @@ -538,6 +737,10 @@ ansi-cyan@^0.1.1: dependencies: ansi-wrap "0.1.0" +ansi-escapes@^1.1.0: + version "1.4.0" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + ansi-escapes@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" @@ -562,10 +765,6 @@ ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" -ansi-regex@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" - ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -611,6 +810,35 @@ arch@^2.1.0: version "2.1.1" resolved "https://registry.npmjs.org/arch/-/arch-2.1.1.tgz#8f5c2731aa35a30929221bb0640eed65175ec84e" +archiver-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.0.0.tgz#5639818a8b5d89d0ffc51b72c39283cf4fea14a1" + dependencies: + glob "^7.0.0" + graceful-fs "^4.1.0" + lazystream "^1.0.0" + lodash.assign "^4.2.0" + lodash.defaults "^4.2.0" + lodash.difference "^4.5.0" + lodash.flatten "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.toarray "^4.4.0" + lodash.union "^4.6.0" + normalize-path "^3.0.0" + readable-stream "^2.0.0" + +archiver@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/archiver/-/archiver-3.0.0.tgz#50b2628cf032adcbf35d35d111b5324db95bfb69" + dependencies: + archiver-utils "^2.0.0" + async "^2.0.0" + buffer-crc32 "^0.2.1" + glob "^7.0.0" + readable-stream "^2.0.0" + tar-stream "^1.5.0" + zip-stream "^2.0.1" + are-we-there-yet@~1.1.2: version "1.1.5" resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" @@ -665,6 +893,17 @@ array-filter@~0.0.0: version "0.0.1" resolved "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + +array-includes@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.7.0" + array-map@~0.0.0: version "0.0.0" resolved "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" @@ -733,6 +972,12 @@ async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" +async@^2.0.0: + version "2.6.2" + resolved "https://registry.npmjs.org/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" + dependencies: + lodash "^4.17.11" + async@^2.1.4, async@^2.4.0, async@^2.5.0: version "2.6.1" resolved "https://registry.npmjs.org/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" @@ -766,7 +1011,7 @@ aws4@^1.8.0: version "1.8.0" resolved "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" -babel-code-frame@^6.26.0, babel-code-frame@^6.8.0: +babel-code-frame@^6.22.0, babel-code-frame@^6.26.0, babel-code-frame@^6.8.0: version "6.26.0" resolved "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: @@ -824,14 +1069,14 @@ babel-core@^6.0.0, babel-core@^6.24.1, babel-core@^6.26.0, babel-core@^6.26.3, b slash "^1.0.0" source-map "^0.5.7" -babel-eslint@^10.0.1: - version "10.0.1" - resolved "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz#919681dc099614cd7d31d45c8908695092a1faed" +babel-eslint@^8.2.3: + version "8.2.6" + resolved "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.6.tgz#6270d0c73205628067c0f7ae1693a9e797acefd9" dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.0.0" - "@babel/traverse" "^7.0.0" - "@babel/types" "^7.0.0" + "@babel/code-frame" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" eslint-scope "3.7.1" eslint-visitor-keys "^1.0.0" @@ -1399,9 +1644,9 @@ babel-plugin-transform-function-bind@^6.22.0: babel-plugin-syntax-function-bind "^6.8.0" babel-runtime "^6.22.0" -babel-plugin-transform-jsx-to-stylesheet@1.2.12: - version "1.2.12" - resolved "https://registry.npmjs.org/babel-plugin-transform-jsx-to-stylesheet/-/babel-plugin-transform-jsx-to-stylesheet-1.2.12.tgz#e6301e470475e71d7e18541a3e616d5f5eabd477" +babel-plugin-transform-jsx-to-stylesheet@1.2.13: + version "1.2.13" + resolved "https://registry.npmjs.org/babel-plugin-transform-jsx-to-stylesheet/-/babel-plugin-transform-jsx-to-stylesheet-1.2.13.tgz#b571271a2290c49e7addbf671866e2ca5377eecb" babel-plugin-transform-object-assign@^6.5.0: version "6.22.0" @@ -1647,7 +1892,7 @@ babel-register@^6.24.1, babel-register@^6.26.0, babel-register@^6.9.0: mkdirp "^0.5.1" source-map-support "^0.4.15" -babel-runtime@^6.0.0, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0, babel-runtime@^6.9.1: +babel-runtime@^6.0.0, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0, babel-runtime@^6.6.1, babel-runtime@^6.9.1: version "6.26.0" resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: @@ -1664,7 +1909,7 @@ babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0, babel-te babylon "^6.18.0" lodash "^4.17.4" -babel-traverse@^6.0.0, babel-traverse@^6.10.4, babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: +babel-traverse@^6.0.0, babel-traverse@^6.10.4, babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0, babel-traverse@^6.7.3: version "6.26.0" resolved "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" dependencies: @@ -1687,7 +1932,11 @@ babel-types@^6.0.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24. lodash "^4.17.4" to-fast-properties "^1.0.3" -babylon@^6.18.0, babylon@^6.7.0: +babylon@7.0.0-beta.44: + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" + +babylon@^6.1.21, babylon@^6.18.0, babylon@^6.7.0: version "6.18.0" resolved "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" @@ -1707,7 +1956,7 @@ base64-js@1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.1.2.tgz#d6400cac1c4c660976d90d07a04351d89395f5e8" -base64-js@^1.1.2: +base64-js@^1.0.2, base64-js@^1.1.2: version "1.3.0" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" @@ -1760,6 +2009,25 @@ binary-extensions@^1.0.0: version "1.12.0" resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14" +bl@^1.0.0: + version "1.2.2" + resolved "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +boxen@^1.2.1: + version "1.3.0" + resolved "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" + dependencies: + ansi-align "^2.0.0" + camelcase "^4.0.0" + chalk "^2.0.1" + cli-boxes "^1.0.0" + string-width "^2.0.0" + term-size "^1.2.0" + widest-line "^2.0.0" + bplist-creator@0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.7.tgz#37df1536092824b87c42f957b01344117372ae45" @@ -1836,6 +2104,10 @@ buffer-alloc@^1.2.0: buffer-alloc-unsafe "^1.1.0" buffer-fill "^1.0.0" +buffer-crc32@^0.2.1: + version "0.2.13" + resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + buffer-equal@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe" @@ -1848,7 +2120,14 @@ buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" -builtin-modules@^1.0.0: +buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz#dd57fa0f109ac59c602479044dca7b8b3d0b71d6" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + +builtin-modules@^1.0.0, builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -1882,15 +2161,47 @@ cacheable-request@^2.1.1: normalize-url "2.0.1" responselike "1.0.2" +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsite-record@^3.0.0: + version "3.2.2" + resolved "https://registry.npmjs.org/callsite-record/-/callsite-record-3.2.2.tgz#9a0390642e43fe8bb823945e51464f69f41643de" + dependencies: + callsite "^1.0.0" + chalk "^1.1.1" + error-stack-parser "^1.3.3" + highlight-es "^1.0.0" + lodash "4.6.1 || ^4.16.1" + pinkie-promise "^2.0.0" + +callsite@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + callsites@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" -callsites@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz#fb7eb569b72ad7a45812f93fd9430a3e410b3dd3" +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" -camelcase@^4.1.0: +camelcase@^4.0.0, camelcase@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" @@ -1904,11 +2215,15 @@ capture-exit@^1.2.0: dependencies: rsvp "^3.3.3" +capture-stack-trace@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d" + caseless@~0.12.0: version "0.12.0" resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" -chalk@^1.1.1, chalk@^1.1.3: +chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -1926,7 +2241,7 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.1, chalk@^2.3.2, chalk@^2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^2.1.0: +chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" dependencies: @@ -1938,10 +2253,6 @@ chardet@^0.4.0: version "0.4.2" resolved "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - chokidar@^2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" @@ -1982,12 +2293,26 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +cli-boxes@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" + +cli-cursor@^1.0.1, cli-cursor@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" dependencies: restore-cursor "^2.0.0" +cli-spinners@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" + cli-spinners@^1.1.0: version "1.3.1" resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" @@ -2088,14 +2413,14 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +commander@^2.12.1, commander@^2.9.0: + version "2.19.0" + resolved "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" + commander@^2.15.0: version "2.18.0" resolved "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970" -commander@^2.9.0: - version "2.19.0" - resolved "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" - commander@~2.13.0: version "2.13.0" resolved "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" @@ -2112,6 +2437,15 @@ component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" +compress-commons@^1.2.0: + version "1.2.2" + resolved "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.2.tgz#524a9f10903f3a813389b0225d27c48bb751890f" + dependencies: + buffer-crc32 "^0.2.1" + crc32-stream "^2.0.0" + normalize-path "^2.0.0" + readable-stream "^2.0.0" + compressible@~2.0.14: version "2.0.15" resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.15.tgz#857a9ab0a7e5a07d8d837ed43fe2defff64fe212" @@ -2143,6 +2477,17 @@ concat-stream@^1.4.7, concat-stream@^1.6.0: readable-stream "^2.2.2" typedarray "^0.0.6" +configstore@^3.0.0: + version "3.1.2" + resolved "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f" + dependencies: + dot-prop "^4.1.0" + graceful-fs "^4.1.2" + make-dir "^1.0.0" + unique-string "^1.0.0" + write-file-atomic "^2.0.0" + xdg-basedir "^3.0.0" + connect@^3.6.5: version "3.6.6" resolved "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" @@ -2156,6 +2501,10 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.5.1: version "1.6.0" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" @@ -2182,6 +2531,25 @@ core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" +crc32-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz#e3cdd3b4df3168dd74e3de3fbbcb7b297fe908f4" + dependencies: + crc "^3.4.4" + readable-stream "^2.0.0" + +crc@^3.4.4: + version "3.8.0" + resolved "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6" + dependencies: + buffer "^5.1.0" + +create-error-class@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" + dependencies: + capture-stack-trace "^1.0.0" + create-react-class@^15.6.3: version "15.6.3" resolved "https://registry.npmjs.org/create-react-class/-/create-react-class-15.6.3.tgz#2d73237fb3f970ae6ebe011a9e66f46dbca80036" @@ -2190,6 +2558,13 @@ create-react-class@^15.6.3: loose-envify "^1.3.1" object-assign "^4.1.1" +cross-spawn-async@^2.1.1: + version "2.2.5" + resolved "https://registry.npmjs.org/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz#845ff0c0834a3ded9d160daca6d390906bb288cc" + dependencies: + lru-cache "^4.0.0" + which "^1.2.8" + cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -2208,6 +2583,10 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" +crypto-random-string@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + css-color-keywords@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" @@ -2267,6 +2646,12 @@ cuint@^0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b" +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + dependencies: + array-find-index "^1.0.1" + dashdash@^1.12.0: version "1.14.1" resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -2293,13 +2678,13 @@ debug@^3.1.0: dependencies: ms "^2.1.1" -debug@^4.0.1, debug@^4.1.0: +debug@^4.1.0: version "4.1.1" resolved "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" dependencies: ms "^2.1.1" -decamelize@^1.1.1: +decamelize@^1.1.1, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -2370,10 +2755,34 @@ denodeify@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz#3a36287f5034e699e7577901052c2e6c94251631" +depcheck@^0.6.11: + version "0.6.11" + resolved "https://registry.npmjs.org/depcheck/-/depcheck-0.6.11.tgz#6b616f2cf8c44ddcfdc5d7c7f7759bc53b479262" + dependencies: + babel-traverse "^6.7.3" + babylon "^6.1.21" + builtin-modules "^1.1.1" + deprecate "^1.0.0" + deps-regex "^0.1.4" + js-yaml "^3.4.2" + lodash "^4.5.1" + minimatch "^3.0.2" + require-package-name "^2.0.1" + walkdir "0.0.11" + yargs "^8.0.2" + depd@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" +deprecate@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/deprecate/-/deprecate-1.1.0.tgz#bbd069d62b232175b4e8459b2650cd2bad51f4b8" + +deps-regex@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/deps-regex/-/deps-regex-0.1.4.tgz#518667b7691460a5e7e0a341be76eb7ce8090184" + destroy@~1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" @@ -2403,6 +2812,20 @@ dir-glob@^2.0.0: arrify "^1.0.1" path-type "^3.0.0" +doctrine@0.7.2: + version "0.7.2" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-0.7.2.tgz#7cb860359ba3be90e040b26b729ce4bfa654c523" + dependencies: + esutils "^1.1.6" + isarray "0.0.1" + +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + doctrine@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -2419,6 +2842,12 @@ domexception@^1.0.1: dependencies: webidl-conversions "^4.0.2" +dot-prop@^4.1.0: + version "4.2.0" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + dependencies: + is-obj "^1.0.0" + duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" @@ -2485,12 +2914,18 @@ envinfo@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/envinfo/-/envinfo-6.0.1.tgz#dec51f2dd38fb4a1fb5bf568488c06ad1e7e08a7" -error-ex@^1.2.0: +error-ex@^1.2.0, error-ex@^1.3.1: version "1.3.2" resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" dependencies: is-arrayish "^0.2.1" +error-stack-parser@^1.3.3: + version "1.3.6" + resolved "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-1.3.6.tgz#e0e73b93e417138d1cd7c0b746b1a4a14854c292" + dependencies: + stackframe "^0.3.1" + errorhandler@^1.5.0: version "1.5.0" resolved "https://registry.npmjs.org/errorhandler/-/errorhandler-1.5.0.tgz#eaba64ca5d542a311ac945f582defc336165d9f4" @@ -2498,7 +2933,7 @@ errorhandler@^1.5.0: accepts "~1.3.3" escape-html "~1.0.3" -es-abstract@^1.5.1: +es-abstract@^1.11.0, es-abstract@^1.4.3, es-abstract@^1.5.1, es-abstract@^1.7.0: version "1.13.0" resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" dependencies: @@ -2536,6 +2971,41 @@ escodegen@^1.9.1: optionalDependencies: source-map "~0.6.1" +eslint-config-taro@^1.1.4: + version "1.2.21" + resolved "https://registry.npmjs.org/eslint-config-taro/-/eslint-config-taro-1.2.21.tgz#cdf5b6a895bd43895def06cb6b89d86b7d7688eb" + dependencies: + eslint-plugin-taro "1.2.21" + +eslint-import-resolver-node@^0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" + dependencies: + debug "^2.6.9" + resolve "^1.5.0" + +eslint-module-utils@^2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.3.0.tgz#546178dab5e046c8b562bbb50705e2456d7bda49" + dependencies: + debug "^2.6.8" + pkg-dir "^2.0.0" + +eslint-plugin-import@^2.8.0: + version "2.16.0" + resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.16.0.tgz#97ac3e75d0791c4fac0e15ef388510217be7f66f" + dependencies: + contains-path "^0.1.0" + debug "^2.6.9" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.2" + eslint-module-utils "^2.3.0" + has "^1.0.3" + lodash "^4.17.11" + minimatch "^3.0.4" + read-pkg-up "^2.0.0" + resolve "^1.9.0" + eslint-plugin-react-native-globals@^0.1.1: version "0.1.2" resolved "https://registry.npmjs.org/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz#ee1348bc2ceb912303ce6bdbd22e2f045ea86ea2" @@ -2546,12 +3016,36 @@ eslint-plugin-react-native@^3.2.1: dependencies: eslint-plugin-react-native-globals "^0.1.1" -eslint-plugin-taro@1.2.12: - version "1.2.12" - resolved "https://registry.npmjs.org/eslint-plugin-taro/-/eslint-plugin-taro-1.2.12.tgz#9107a9e64614eb44b8513015fe4f3e5897108ac8" +eslint-plugin-react@^7.4.0: + version "7.12.4" + resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.12.4.tgz#b1ecf26479d61aee650da612e425c53a99f48c8c" + dependencies: + array-includes "^3.0.3" + doctrine "^2.1.0" + has "^1.0.3" + jsx-ast-utils "^2.0.1" + object.fromentries "^2.0.0" + prop-types "^15.6.2" + resolve "^1.9.0" + +eslint-plugin-taro@1.2.13: + version "1.2.13" + resolved "https://registry.npmjs.org/eslint-plugin-taro/-/eslint-plugin-taro-1.2.13.tgz#e6a90a50fa0f3fef495e36e9135fab6db8bcc785" + dependencies: + has "^1.0.1" + +eslint-plugin-taro@1.2.21, eslint-plugin-taro@^1.1.4: + version "1.2.21" + resolved "https://registry.npmjs.org/eslint-plugin-taro/-/eslint-plugin-taro-1.2.21.tgz#68c7f5b431829c64cd503c6e0680c717c4a94585" dependencies: has "^1.0.1" +eslint-plugin-typescript@^0.12.0: + version "0.12.0" + resolved "https://registry.npmjs.org/eslint-plugin-typescript/-/eslint-plugin-typescript-0.12.0.tgz#e23d58cb27fe28e89fc641a1f20e8d862cb99aef" + dependencies: + requireindex "~1.1.0" + eslint-scope@3.7.1: version "3.7.1" resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" @@ -2559,70 +3053,66 @@ eslint-scope@3.7.1: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-scope@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" +eslint-scope@^3.7.1: + version "3.7.3" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535" dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-utils@^1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" - eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" -eslint@^5.10.0: - version "5.12.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-5.12.0.tgz#fab3b908f60c52671fb14e996a450b96c743c859" +eslint@^4.15.0: + version "4.19.1" + resolved "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.5.3" + ajv "^5.3.0" + babel-code-frame "^6.22.0" chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" + concat-stream "^1.6.0" + cross-spawn "^5.1.0" + debug "^3.1.0" doctrine "^2.1.0" - eslint-scope "^4.0.0" - eslint-utils "^1.3.1" + eslint-scope "^3.7.1" eslint-visitor-keys "^1.0.0" - espree "^5.0.0" - esquery "^1.0.1" + espree "^3.5.4" + esquery "^1.0.0" esutils "^2.0.2" file-entry-cache "^2.0.0" functional-red-black-tree "^1.0.1" glob "^7.1.2" - globals "^11.7.0" - ignore "^4.0.6" - import-fresh "^3.0.0" + globals "^11.0.1" + ignore "^3.3.3" imurmurhash "^0.1.4" - inquirer "^6.1.0" - js-yaml "^3.12.0" + inquirer "^3.0.6" + is-resolvable "^1.0.0" + js-yaml "^3.9.1" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" - lodash "^4.17.5" - minimatch "^3.0.4" + lodash "^4.17.4" + minimatch "^3.0.2" mkdirp "^0.5.1" natural-compare "^1.4.0" optionator "^0.8.2" path-is-inside "^1.0.2" pluralize "^7.0.0" progress "^2.0.0" - regexpp "^2.0.1" - semver "^5.5.1" + regexpp "^1.0.1" + require-uncached "^1.0.3" + semver "^5.3.0" strip-ansi "^4.0.0" - strip-json-comments "^2.0.1" - table "^5.0.2" - text-table "^0.2.0" + strip-json-comments "~2.0.1" + table "4.0.2" + text-table "~0.2.0" -espree@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/espree/-/espree-5.0.0.tgz#fc7f984b62b36a0f543b13fb9cd7b9f4a7f5b65c" +espree@^3.5.4: + version "3.5.4" + resolved "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" dependencies: - acorn "^6.0.2" - acorn-jsx "^5.0.0" - eslint-visitor-keys "^1.0.0" + acorn "^5.5.0" + acorn-jsx "^3.0.0" esprima@^3.1.3: version "3.1.3" @@ -2632,7 +3122,7 @@ esprima@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" -esquery@^1.0.1: +esquery@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" dependencies: @@ -2648,6 +3138,10 @@ estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" +esutils@^1.1.6: + version "1.1.6" + resolved "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz#c01ccaa9ae4b897c6d0c3e210ae52f3c7a844375" + esutils@^2.0.0, esutils@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" @@ -2670,6 +3164,16 @@ exec-sh@^0.2.0: dependencies: merge "^1.2.0" +execa@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/execa/-/execa-0.2.2.tgz#e2ead472c2c31aad6f73f1ac956eef45e12320cb" + dependencies: + cross-spawn-async "^2.1.1" + npm-run-path "^1.0.0" + object-assign "^4.0.1" + path-key "^1.0.0" + strip-eof "^1.0.0" + execa@^0.7.0: version "0.7.0" resolved "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" @@ -2694,6 +3198,10 @@ execa@^0.8.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + exit@^0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -2722,6 +3230,12 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + dependencies: + homedir-polyfill "^1.0.1" + expect@^23.6.0: version "23.6.0" resolved "https://registry.npmjs.org/expect/-/expect-23.6.0.tgz#1e0c8d3ba9a581c87bd71fb9bc8862d443425f98" @@ -2764,14 +3278,6 @@ external-editor@^2.0.4, external-editor@^2.1.0: iconv-lite "^0.4.17" tmp "^0.0.33" -external-editor@^3.0.0: - version "3.0.3" - resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - extglob@^0.3.1: version "0.3.2" resolved "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" @@ -2808,6 +3314,10 @@ fancy-log@^1.3.2: parse-node-version "^1.0.0" time-stamp "^1.0.0" +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" @@ -2857,6 +3367,13 @@ fbjs@^0.8.14, fbjs@^0.8.5, fbjs@^0.8.9: setimmediate "^1.0.5" ua-parser-js "^0.7.18" +figures@^1.3.5: + version "1.7.0" + resolved "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + figures@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -2994,6 +3511,10 @@ from2@^2.1.1: inherits "^2.0.1" readable-stream "^2.0.0" +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + fs-extra@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" @@ -3034,7 +3555,7 @@ fsevents@^1.2.2, fsevents@^1.2.3: nan "^2.9.2" node-pre-gyp "^0.10.0" -function-bind@^1.1.1: +function-bind@^1.0.2, function-bind@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -3075,6 +3596,10 @@ get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -3089,6 +3614,10 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" +giturl@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/giturl/-/giturl-1.0.1.tgz#926c69bda5c48a3d8f74254e99f826835e6a4aa0" + glob-base@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" @@ -3124,6 +3653,16 @@ glob-stream@^6.1.0: to-absolute-glob "^2.0.0" unique-stream "^2.0.2" +glob@^6.0.1: + version "6.0.4" + resolved "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3: version "7.1.3" resolved "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" @@ -3135,6 +3674,30 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +global-dirs@^0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" + dependencies: + ini "^1.3.4" + +global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + global@^4.3.0: version "4.3.2" resolved "https://registry.npmjs.org/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" @@ -3142,7 +3705,11 @@ global@^4.3.0: min-document "^2.19.0" process "~0.5.1" -globals@^11.1.0, globals@^11.7.0: +globals@^11.0.1: + version "11.11.0" + resolved "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz#dcf93757fa2de5486fbeed7118538adf789e9c2e" + +globals@^11.1.0: version "11.10.0" resolved "https://registry.npmjs.org/globals/-/globals-11.10.0.tgz#1e09776dffda5e01816b3bb4077c8b59c24eaa50" @@ -3150,6 +3717,17 @@ globals@^9.18.0: version "9.18.0" resolved "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" +globby@^4.0.0: + version "4.1.0" + resolved "https://registry.npmjs.org/globby/-/globby-4.1.0.tgz#080f54549ec1b82a6c60e631fc82e1211dbe95f8" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^6.0.1" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + globby@^7.1.1: version "7.1.1" resolved "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz#fb2ccff9401f8600945dfada97440cca972b8680" @@ -3161,6 +3739,22 @@ globby@^7.1.1: pify "^3.0.0" slash "^1.0.0" +got@^6.7.1: + version "6.7.1" + resolved "https://registry.npmjs.org/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" + dependencies: + create-error-class "^3.0.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-redirect "^1.0.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + lowercase-keys "^1.0.0" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + unzip-response "^2.0.1" + url-parse-lax "^1.0.0" + got@^8.3.1: version "8.3.2" resolved "https://registry.npmjs.org/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" @@ -3187,7 +3781,7 @@ graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, version "4.1.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" -graceful-fs@^4.1.3: +graceful-fs@^4.1.0, graceful-fs@^4.1.3, graceful-fs@^4.1.5: version "4.1.15" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" @@ -3281,10 +3875,22 @@ has@^1.0.1, has@^1.0.3: dependencies: function-bind "^1.1.1" +highlight-es@^1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/highlight-es/-/highlight-es-1.0.3.tgz#12abc300a27e686f6f18010134e3a5c6d2fe6930" + dependencies: + chalk "^2.4.0" + is-es2016-keyword "^1.0.0" + js-tokens "^3.0.0" + himalaya-wxml@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/himalaya-wxml/-/himalaya-wxml-1.1.0.tgz#85d0341af1c5f53f3b021be8e4be890cc8b4d7af" +hoek@6.x.x: + version "6.1.2" + resolved "https://registry.npmjs.org/hoek/-/hoek-6.1.2.tgz#99e6d070561839de74ee427b61aa476bd6bddfd6" + home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -3296,6 +3902,12 @@ home-or-tmp@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-3.0.0.tgz#57a8fe24cf33cdd524860a15821ddc25c86671fb" +homedir-polyfill@^1.0.1: + version "1.0.3" + resolved "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" + dependencies: + parse-passwd "^1.0.0" + hosted-git-info@^2.1.4: version "2.7.1" resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" @@ -3333,7 +3945,7 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: +iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.4, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" dependencies: @@ -3349,30 +3961,27 @@ icss-utils@^3.0.1: dependencies: postcss "^6.0.2" +ieee754@^1.1.4: + version "1.1.13" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + ignore-walk@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" dependencies: minimatch "^3.0.4" -ignore@^3.3.5: +ignore@^3.3.3, ignore@^3.3.5: version "3.3.10" resolved "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - image-size@^0.6.0: version "0.6.3" resolved "https://registry.npmjs.org/image-size/-/image-size-0.6.3.tgz#e7e5c65bb534bd7cdcedd6cb5166272a85f75fb2" -import-fresh@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz#a3d897f420cab0e671236897f75bc14b4885c390" - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" import-local@^1.0.0: version "1.0.0" @@ -3385,6 +3994,12 @@ imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + dependencies: + repeating "^2.0.0" + inflight@^1.0.4: version "1.0.6" resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -3396,10 +4011,28 @@ inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" -ini@~1.3.0: +ini@^1.3.4, ini@~1.3.0: version "1.3.5" resolved "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" +inquirer@^0.12.0: + version "0.12.0" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + dependencies: + ansi-escapes "^1.1.0" + ansi-regex "^2.0.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + figures "^1.3.5" + lodash "^4.3.0" + readline2 "^1.0.1" + run-async "^0.1.0" + rx-lite "^3.1.2" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + inquirer@^3.0.6: version "3.3.0" resolved "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" @@ -3437,24 +4070,6 @@ inquirer@^5.2.0: strip-ansi "^4.0.0" through "^2.3.6" -inquirer@^6.1.0: - version "6.2.1" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz#9943fc4882161bdb0b0c9276769c75b32dbfcd52" - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^3.0.0" - figures "^2.0.0" - lodash "^4.17.10" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^6.1.0" - string-width "^2.1.0" - strip-ansi "^5.0.0" - through "^2.3.6" - interpret@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" @@ -3466,7 +4081,7 @@ into-stream@^3.1.0: from2 "^2.1.1" p-is-promise "^1.1.0" -invariant@^2.2.2, invariant@^2.2.4: +invariant@^2.2.0, invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" dependencies: @@ -3523,7 +4138,7 @@ is-callable@^1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" -is-ci@^1.0.10: +is-ci@^1.0.10, is-ci@^1.0.8: version "1.2.1" resolved "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" dependencies: @@ -3571,6 +4186,10 @@ is-equal-shallow@^0.1.3: dependencies: is-primitive "^2.0.0" +is-es2016-keyword@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-es2016-keyword/-/is-es2016-keyword-1.0.0.tgz#f6e54e110c5e4f8d265e69d2ed0eaf8cf5f47718" + is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -3627,10 +4246,21 @@ is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" +is-installed-globally@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" + dependencies: + global-dirs "^0.1.0" + is-path-inside "^1.0.0" + is-negated-glob@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2" +is-npm@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" + is-number@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" @@ -3647,10 +4277,20 @@ is-number@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" +is-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + is-object@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + dependencies: + path-is-inside "^1.0.1" + is-plain-obj@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" @@ -3673,6 +4313,10 @@ is-promise@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" +is-redirect@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + is-regex@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" @@ -3685,11 +4329,15 @@ is-relative@^1.0.0: dependencies: is-unc-path "^1.0.0" -is-retry-allowed@^1.1.0: +is-resolvable@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + +is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" -is-stream@^1.0.1, is-stream@^1.1.0: +is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -3721,7 +4369,11 @@ is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" -isarray@1.0.0, isarray@~1.0.0: +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -3731,6 +4383,12 @@ isbinaryfile@^3.0.2: dependencies: buffer-alloc "^1.2.0" +isemail@3.x.x: + version "3.2.0" + resolved "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz#59310a021931a9fb06bbb51e155ce0b3f236832c" + dependencies: + punycode "2.x.x" + isexe@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -4160,19 +4818,34 @@ jest@^23.6.0: import-local "^1.0.0" jest-cli "^23.6.0" +joi@^14.0.6: + version "14.3.1" + resolved "https://registry.npmjs.org/joi/-/joi-14.3.1.tgz#164a262ec0b855466e0c35eea2a885ae8b6c703c" + dependencies: + hoek "6.x.x" + isemail "3.x.x" + topo "3.x.x" + js-base64@^2.1.9: version "2.4.9" resolved "https://registry.npmjs.org/js-base64/-/js-base64-2.4.9.tgz#748911fb04f48a60c4771b375cac45a80df11c03" +js-tokens@^3.0.0, js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" +js-yaml@^3.4.2, js-yaml@^3.6.1, js-yaml@^3.9.1: + version "3.13.0" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz#38ee7178ac0eea2c97ff6d96fff4b18c7d8cf98e" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" -js-yaml@^3.12.0, js-yaml@^3.7.0: +js-yaml@^3.7.0: version "3.12.1" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz#295c8632a18a23e054cf5c9d3cecafe678167600" dependencies: @@ -4230,6 +4903,14 @@ json-buffer@3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -4297,6 +4978,12 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +jsx-ast-utils@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f" + dependencies: + array-includes "^3.0.3" + keyv@3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" @@ -4343,6 +5030,12 @@ kleur@^2.0.1: version "2.0.2" resolved "https://registry.npmjs.org/kleur/-/kleur-2.0.2.tgz#b704f4944d95e255d038f0cb05fb8a602c55a300" +latest-version@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" + dependencies: + package-json "^4.0.0" + latest-version@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/latest-version/-/latest-version-4.0.0.tgz#9542393ac55a585861a4c4ebc02389a0b4a9c332" @@ -4401,6 +5094,24 @@ load-json-file@^2.0.0: pify "^2.0.0" strip-bom "^3.0.0" +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + +load-yaml-file@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.1.0.tgz#f680066e691b3eeb45017672e4a3956af5b83b89" + dependencies: + graceful-fs "^4.1.5" + js-yaml "^3.6.1" + pify "^2.3.0" + strip-bom "^3.0.0" + loader-utils@^1.1.0: version "1.2.3" resolved "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" @@ -4416,10 +5127,30 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" +lodash.assign@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + +lodash.difference@^4.5.0: + version "4.5.0" + resolved "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + lodash.pad@^4.1.0: version "4.5.1" resolved "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz#4330949a833a7c8da22cc20f6a26c4d59debba70" @@ -4444,18 +5175,26 @@ lodash.throttle@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" +lodash.toarray@^4.4.0: + version "4.4.0" + resolved "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561" + +lodash.union@^4.6.0: + version "4.6.0" + resolved "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + lodash@4.17.4: version "4.17.4" resolved "http://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" +"lodash@4.6.1 || ^4.16.1", lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1, lodash@^4.7.0: + version "4.17.11" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + lodash@^3.5.0: version "3.10.1" resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: - version "4.17.11" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" - log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" @@ -4468,6 +5207,13 @@ loose-envify@^1.0.0, loose-envify@^1.3.1: dependencies: js-tokens "^3.0.0 || ^4.0.0" +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + lowercase-keys@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" @@ -4476,7 +5222,7 @@ lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" -lru-cache@^4.0.1: +lru-cache@^4.0.0, lru-cache@^4.0.1: version "4.1.5" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" dependencies: @@ -4503,6 +5249,10 @@ map-cache@^0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + map-visit@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" @@ -4543,6 +5293,25 @@ mem@^1.1.0: dependencies: mimic-fn "^1.0.0" +memorystream@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" + +meow@^3.7.0: + version "3.7.0" + resolved "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + merge-stream@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" @@ -4757,7 +5526,7 @@ min-document@^2.19.0: dependencies: dom-walk "^0.1.0" -minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: @@ -4767,7 +5536,7 @@ minimist@0.0.8: version "0.0.8" resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@^1.1.1, minimist@^1.2.0: +minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" resolved "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" @@ -4828,6 +5597,10 @@ multimatch@^2.0.0: arrify "^1.0.0" minimatch "^3.0.0" +mute-stream@0.0.5: + version "0.0.5" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + mute-stream@0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" @@ -4872,6 +5645,12 @@ nice-try@^1.0.4: version "1.0.5" resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" +node-emoji@^1.0.3: + version "1.10.0" + resolved "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da" + dependencies: + lodash.toarray "^4.4.0" + node-fetch@^1.0.1, node-fetch@^1.3.3: version "1.7.3" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" @@ -4927,12 +5706,25 @@ normalize-package-data@^2.3.2: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.0.1, normalize-path@^2.1.1: +normalize-package-data@^2.3.4: + version "2.5.0" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" dependencies: remove-trailing-separator "^1.0.1" +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + normalize-range@^0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" @@ -4955,6 +5747,37 @@ npm-bundled@^1.0.1: version "1.0.5" resolved "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" +npm-check@^5.9.0: + version "5.9.0" + resolved "https://registry.npmjs.org/npm-check/-/npm-check-5.9.0.tgz#f9666af7d3c02442e16a9c56a32abc62023fa019" + dependencies: + babel-runtime "^6.6.1" + callsite-record "^3.0.0" + chalk "^1.1.3" + co "^4.6.0" + depcheck "^0.6.11" + execa "^0.2.2" + giturl "^1.0.0" + global-modules "^1.0.0" + globby "^4.0.0" + inquirer "^0.12.0" + is-ci "^1.0.8" + lodash "^4.7.0" + meow "^3.7.0" + minimatch "^3.0.2" + node-emoji "^1.0.3" + ora "^0.2.1" + package-json "^4.0.1" + path-exists "^2.1.0" + pkg-dir "^1.0.0" + preferred-pm "^1.0.1" + semver "^5.0.1" + semver-diff "^2.0.0" + text-table "^0.2.0" + throat "^2.0.2" + update-notifier "^2.1.0" + xtend "^4.0.1" + npm-packlist@^1.1.6: version "1.1.11" resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de" @@ -4962,6 +5785,26 @@ npm-packlist@^1.1.6: ignore-walk "^3.0.1" npm-bundled "^1.0.1" +npm-run-all@^4.1.5: + version "4.1.5" + resolved "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" + dependencies: + ansi-styles "^3.2.1" + chalk "^2.4.1" + cross-spawn "^6.0.5" + memorystream "^0.3.1" + minimatch "^3.0.4" + pidtree "^0.3.0" + read-pkg "^3.0.0" + shell-quote "^1.6.1" + string.prototype.padend "^3.0.0" + +npm-run-path@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-1.0.0.tgz#f5c32bf595fe81ae927daec52e82f8b000ac3c8f" + dependencies: + path-key "^1.0.0" + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -5032,6 +5875,15 @@ object.assign@^4.0.4: has-symbols "^1.0.0" object-keys "^1.0.11" +object.fromentries@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.0.tgz#49a543d92151f8277b3ac9600f1e930b189d30ab" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.11.0" + function-bind "^1.1.1" + has "^1.0.1" + object.getownpropertydescriptors@^2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" @@ -5068,6 +5920,10 @@ once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0: dependencies: wrappy "1" +onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + onetime@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" @@ -5102,6 +5958,15 @@ options@>=0.0.5: version "0.0.6" resolved "https://registry.npmjs.org/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" +ora@^0.2.1: + version "0.2.3" + resolved "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" + dependencies: + chalk "^1.1.1" + cli-cursor "^1.0.2" + cli-spinners "^0.1.2" + object-assign "^4.0.1" + ora@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" @@ -5183,6 +6048,15 @@ p-try@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" +package-json@^4.0.0, package-json@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" + dependencies: + got "^6.7.1" + registry-auth-token "^3.0.1" + registry-url "^3.0.3" + semver "^5.1.0" + package-json@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/package-json/-/package-json-5.0.0.tgz#a7dbe2725edcc7dc9bcee627672275e323882433" @@ -5192,12 +6066,6 @@ package-json@^5.0.0: registry-url "^3.1.0" semver "^5.5.0" -parent-module@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.0.tgz#df250bdc5391f4a085fb589dad761f5ad6b865b5" - dependencies: - callsites "^3.0.0" - parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -5213,10 +6081,21 @@ parse-json@^2.2.0: dependencies: error-ex "^1.2.0" +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + parse-node-version@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.0.tgz#33d9aa8920dcc3c0d33658ec18ce237009a56d53" +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + parse5@4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" @@ -5237,7 +6116,7 @@ path-exists@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" -path-exists@^2.0.0: +path-exists@^2.0.0, path-exists@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" dependencies: @@ -5251,10 +6130,14 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" -path-is-inside@^1.0.2: +path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" +path-key@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/path-key/-/path-key-1.0.0.tgz#5d53d578019646c0d68800db4e146e6bdc2ac7af" + path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" @@ -5291,6 +6174,10 @@ performance-now@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" +pidtree@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz#f6fada10fccc9f99bf50e90d0b23d72c9ebc2e6b" + pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -5315,6 +6202,12 @@ pirates@^4.0.0: dependencies: node-modules-regexp "^1.0.0" +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + dependencies: + find-up "^1.0.0" + pkg-dir@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" @@ -5402,16 +6295,16 @@ postcss-pxtorem@^4.0.1: object-assign "^4.1.0" postcss "^5.2.10" -postcss-pxtransform@1.2.12: - version "1.2.12" - resolved "https://registry.npmjs.org/postcss-pxtransform/-/postcss-pxtransform-1.2.12.tgz#4c973e6820d8f584bfa6214afc4aaf60a4fd1ac6" +postcss-pxtransform@1.2.13: + version "1.2.13" + resolved "https://registry.npmjs.org/postcss-pxtransform/-/postcss-pxtransform-1.2.13.tgz#c1f09cfed0007d9748fa733c46f65962cc08400f" dependencies: postcss "^6.0.16" postcss-pxtorem "^4.0.1" -postcss-taro-unit-transform@1.2.12: - version "1.2.12" - resolved "https://registry.npmjs.org/postcss-taro-unit-transform/-/postcss-taro-unit-transform-1.2.12.tgz#e1f78441feead994c4584354e270aa637207ae1d" +postcss-taro-unit-transform@1.2.13: + version "1.2.13" + resolved "https://registry.npmjs.org/postcss-taro-unit-transform/-/postcss-taro-unit-transform-1.2.13.tgz#f81cb826c74bfd12279a901b025599bee6f229ba" dependencies: postcss "^6.0.21" @@ -5429,6 +6322,14 @@ postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" +postcss@7.x.x: + version "7.0.14" + resolved "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz#4527ed6b1ca0d82c53ce5ec1a2041c2346bbd6e5" + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + postcss@^5.2.10: version "5.2.18" resolved "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5" @@ -5446,10 +6347,21 @@ postcss@^6.0.1, postcss@^6.0.16, postcss@^6.0.2, postcss@^6.0.21, postcss@^6.0.2 source-map "^0.6.1" supports-color "^5.4.0" +preferred-pm@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/preferred-pm/-/preferred-pm-1.0.1.tgz#539df37ce944b1b765ae944a8ba34a7e68694e8d" + dependencies: + path-exists "^3.0.0" + which-pm "^1.0.1" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + prepend-http@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" @@ -5462,9 +6374,9 @@ prettier@^1.14.2: version "1.14.3" resolved "https://registry.npmjs.org/prettier/-/prettier-1.14.3.tgz#90238dd4c0684b7edce5f83b0fb7328e48bd0895" -prettier@^1.14.3: - version "1.15.3" - resolved "https://registry.npmjs.org/prettier/-/prettier-1.15.3.tgz#1feaac5bdd181237b54dbe65d874e02a1472786a" +prettier@^1.16.4: + version "1.16.4" + resolved "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz#73e37e73e018ad2db9c76742e2647e21790c9717" pretty-format@^23.6.0: version "23.6.0" @@ -5536,14 +6448,14 @@ pumpify@^1.3.5: inherits "^2.0.3" pump "^2.0.0" +punycode@2.x.x, punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + punycode@^1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - qs@~6.5.2: version "6.5.2" resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -5704,7 +6616,15 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5: +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + +readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5: version "2.3.6" resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -5724,6 +6644,14 @@ readdirp@^2.0.0: micromatch "^3.1.10" readable-stream "^2.0.2" +readline2@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + mute-stream "0.0.5" + realpath-native@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/realpath-native/-/realpath-native-1.0.2.tgz#cd51ce089b513b45cf9b1516c82989b51ccc6560" @@ -5736,6 +6664,13 @@ rechoir@^0.6.2: dependencies: resolve "^1.1.6" +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + regenerate@^1.2.1: version "1.4.0" resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" @@ -5771,9 +6706,9 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" +regexpp@^1.0.1: + version "1.1.0" + resolved "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" regexpu-core@^1.0.0: version "1.0.0" @@ -5791,6 +6726,13 @@ regexpu-core@^2.0.0: regjsgen "^0.2.0" regjsparser "^0.1.4" +registry-auth-token@^3.0.1: + version "3.4.0" + resolved "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e" + dependencies: + rc "^1.1.6" + safe-buffer "^5.0.1" + registry-auth-token@^3.3.2: version "3.3.2" resolved "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" @@ -5798,7 +6740,7 @@ registry-auth-token@^3.3.2: rc "^1.1.6" safe-buffer "^5.0.1" -registry-url@^3.1.0: +registry-url@^3.0.3, registry-url@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" dependencies: @@ -5869,7 +6811,7 @@ request-promise-native@^1.0.5: stealthy-require "^1.1.0" tough-cookie ">=2.3.3" -request@^2.87.0: +request@^2.87.0, request@^2.88.0: version "2.88.0" resolved "https://registry.npmjs.org/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" dependencies: @@ -5902,20 +6844,42 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" +require-package-name@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9" + +require-uncached@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +requireindex@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/requireindex/-/requireindex-1.1.0.tgz#e5404b81557ef75db6e49c5a72004893fe03e162" + resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" dependencies: resolve-from "^3.0.0" +resolve-dir@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - resolve-options@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz#32bb9e39c06d67338dc9378c0d6d6074566ad131" @@ -5936,6 +6900,12 @@ resolve@^1.1.6, resolve@^1.6.0: dependencies: path-parse "^1.0.5" +resolve@^1.10.0, resolve@^1.9.0: + version "1.10.0" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" + dependencies: + path-parse "^1.0.6" + resolve@^1.3.2, resolve@^1.5.0: version "1.9.0" resolved "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz#a14c6fdfa8f92a7df1d996cb7105fa744658ea06" @@ -5948,6 +6918,13 @@ responselike@1.0.2: dependencies: lowercase-keys "^1.0.0" +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -5979,6 +6956,12 @@ rsvp@^3.3.3: version "3.6.2" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" +run-async@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + dependencies: + once "^1.3.0" + run-async@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" @@ -5995,18 +6978,16 @@ rx-lite@*, rx-lite@^4.0.8: version "4.0.8" resolved "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" +rx-lite@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + rxjs@^5.5.2: version "5.5.12" resolved "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz#6fa61b8a77c3d793dbaf270bee2f43f652d741cc" dependencies: symbol-observable "1.0.1" -rxjs@^6.1.0: - version "6.3.3" - resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz#3c6a7fa420e844a81390fb1158a9ec614f4bad55" - dependencies: - tslib "^1.9.0" - safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -6048,7 +7029,13 @@ sax@~1.1.1: version "1.1.6" resolved "https://registry.npmjs.org/sax/-/sax-1.1.6.tgz#5d616be8a5e607d54e114afae55b7eaf2fcc3240" -"semver@2 || 3 || 4 || 5", semver@5.x, semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.4.1, semver@^5.5.1: +semver-diff@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" + dependencies: + semver "^5.0.3" + +"semver@2 || 3 || 4 || 5", semver@5.x, semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.4.1: version "5.6.0" resolved "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" @@ -6168,12 +7155,10 @@ slash@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" -slice-ansi@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.0.0.tgz#5373bdb8559b45676e8541c66916cdd6251612e7" +slice-ansi@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" slide@^1.1.5: @@ -6298,6 +7283,10 @@ stack-utils@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" +stackframe@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/stackframe/-/stackframe-0.3.1.tgz#33aa84f1177a5548c8935533cbfeb3420975f5a4" + stacktrace-parser@^0.1.3: version "0.1.4" resolved "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.4.tgz#01397922e5f62ecf30845522c95c4fe1d25e7d4e" @@ -6359,6 +7348,14 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string.prototype.padend@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz#f3aaef7c1719f170c5eab1c32bf780d96e21f2f0" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.4.3" + function-bind "^1.0.2" + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -6377,12 +7374,6 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" - dependencies: - ansi-regex "^4.0.0" - strip-bom-stream@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz#f87db5ef2613f6968aa545abfe1ec728b6a829ca" @@ -6404,7 +7395,13 @@ strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" -strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + dependencies: + get-stdin "^4.0.1" + +strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -6424,6 +7421,12 @@ supports-color@^5.3.0, supports-color@^5.4.0: dependencies: has-flag "^3.0.0" +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + dependencies: + has-flag "^3.0.0" + symbol-observable@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" @@ -6432,15 +7435,29 @@ symbol-tree@^3.2.2: version "3.2.2" resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" -table@^5.0.2: - version "5.2.0" - resolved "https://registry.npmjs.org/table/-/table-5.2.0.tgz#2e38bd1f16dd3f97085ac80cdc574ad9198af04d" +table@4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" dependencies: - ajv "^6.6.1" - lodash "^4.17.11" - slice-ansi "2.0.0" + ajv "^5.2.3" + ajv-keywords "^2.1.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" string-width "^2.1.1" +tar-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + dependencies: + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" + tar@^4: version "4.4.6" resolved "https://registry.npmjs.org/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b" @@ -6460,6 +7477,12 @@ temp@0.8.3: os-tmpdir "^1.0.0" rimraf "~2.2.6" +term-size@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" + dependencies: + execa "^0.7.0" + test-exclude@^4.2.1: version "4.2.3" resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.3.tgz#a9a5e64474e4398339245a0a769ad7c2f4a97c20" @@ -6470,10 +7493,14 @@ test-exclude@^4.2.1: read-pkg-up "^1.0.1" require-main-filename "^1.0.1" -text-table@^0.2.0: +text-table@^0.2.0, text-table@~0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" +throat@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/throat/-/throat-2.0.2.tgz#a9fce808b69e133a632590780f342c30a6249b02" + throat@^4.0.0, throat@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" @@ -6500,7 +7527,7 @@ time-stamp@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" -timed-out@^4.0.1: +timed-out@^4.0.0, timed-out@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" @@ -6521,6 +7548,10 @@ to-absolute-glob@^2.0.0: is-absolute "^1.0.0" is-negated-glob "^1.0.0" +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" @@ -6557,6 +7588,12 @@ to-through@^2.0.0: dependencies: through2 "^2.0.3" +topo@3.x.x: + version "3.0.3" + resolved "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz#d5a67fb2e69307ebeeb08402ec2a2a6f5f7ad95c" + dependencies: + hoek "6.x.x" + tough-cookie@>=2.3.3: version "3.0.0" resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.0.tgz#d2bceddebde633153ff20a52fa844a0dc71dacef" @@ -6589,14 +7626,70 @@ traverse@0.6.6: version "0.6.6" resolved "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + trim-right@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" -tslib@^1.9.0: +tslib@1.9.0: + version "1.9.0" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" + +tslib@^1.8.0, tslib@^1.8.1: version "1.9.3" resolved "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" +tslint-config-prettier@^1.17.0: + version "1.18.0" + resolved "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz#75f140bde947d35d8f0d238e0ebf809d64592c37" + +tslint-config-standard@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/tslint-config-standard/-/tslint-config-standard-8.0.1.tgz#e4dd3128e84b0e34b51990b68715a641f2b417e4" + dependencies: + tslint-eslint-rules "^5.3.1" + +tslint-eslint-rules@^5.3.1: + version "5.4.0" + resolved "https://registry.npmjs.org/tslint-eslint-rules/-/tslint-eslint-rules-5.4.0.tgz#e488cc9181bf193fe5cd7bfca213a7695f1737b5" + dependencies: + doctrine "0.7.2" + tslib "1.9.0" + tsutils "^3.0.0" + +tslint@^5.12.0: + version "5.14.0" + resolved "https://registry.npmjs.org/tslint/-/tslint-5.14.0.tgz#be62637135ac244fc9b37ed6ea5252c9eba1616e" + dependencies: + babel-code-frame "^6.22.0" + builtin-modules "^1.1.1" + chalk "^2.3.0" + commander "^2.12.1" + diff "^3.2.0" + glob "^7.1.1" + js-yaml "^3.7.0" + minimatch "^3.0.4" + mkdirp "^0.5.1" + resolve "^1.3.2" + semver "^5.3.0" + tslib "^1.8.0" + tsutils "^2.29.0" + +tsutils@^2.29.0: + version "2.29.0" + resolved "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" + dependencies: + tslib "^1.8.1" + +tsutils@^3.0.0: + version "3.9.1" + resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.9.1.tgz#2a40dc742943c71eca6d5c1994fcf999956be387" + dependencies: + tslib "^1.8.1" + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -6671,6 +7764,12 @@ unique-stream@^2.0.2: json-stable-stringify "^1.0.0" through2-filter "^2.0.0" +unique-string@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + dependencies: + crypto-random-string "^1.0.0" + universalify@^0.1.0: version "0.1.2" resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -6686,10 +7785,29 @@ unset-value@^1.0.0: has-value "^0.3.1" isobject "^3.0.0" +unzip-response@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" + upath@^1.0.5: version "1.1.0" resolved "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" +update-notifier@^2.1.0: + version "2.5.0" + resolved "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6" + dependencies: + boxen "^1.2.1" + chalk "^2.0.1" + configstore "^3.0.0" + import-lazy "^2.1.0" + is-ci "^1.0.10" + is-installed-globally "^0.1.0" + is-npm "^1.0.0" + latest-version "^3.0.0" + semver-diff "^2.0.0" + xdg-basedir "^3.0.0" + uri-js@^4.2.2: version "4.2.2" resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" @@ -6700,6 +7818,12 @@ urix@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + dependencies: + prepend-http "^1.0.1" + url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" @@ -6830,6 +7954,10 @@ w3c-hr-time@^1.0.1: dependencies: browser-process-hrtime "^0.1.2" +walkdir@0.0.11: + version "0.0.11" + resolved "https://registry.npmjs.org/walkdir/-/walkdir-0.0.11.tgz#a16d025eb931bd03b52f308caed0f40fcebe9532" + walker@~1.0.5: version "1.0.7" resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" @@ -6891,7 +8019,14 @@ which-module@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" -which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0: +which-pm@^1.0.1: + version "1.1.0" + resolved "https://registry.npmjs.org/which-pm/-/which-pm-1.1.0.tgz#5c0fc3f722f003707dea7b20cd17effd3ad2fc33" + dependencies: + load-yaml-file "^0.1.0" + path-exists "^3.0.0" + +which@^1.2.12, which@^1.2.14, which@^1.2.8, which@^1.2.9, which@^1.3.0: version "1.3.1" resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" dependencies: @@ -6903,6 +8038,12 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.2 || 2" +widest-line@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc" + dependencies: + string-width "^2.1.1" + win-release@^1.0.0: version "1.1.1" resolved "https://registry.npmjs.org/win-release/-/win-release-1.1.1.tgz#5fa55e02be7ca934edfc12665632e849b72e5209" @@ -6936,6 +8077,14 @@ write-file-atomic@^1.2.0: imurmurhash "^0.1.4" slide "^1.1.5" +write-file-atomic@^2.0.0: + version "2.4.2" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz#a7181706dfba17855d221140a9c06e15fcdd87b9" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + write-file-atomic@^2.1.0: version "2.3.0" resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" @@ -6978,6 +8127,10 @@ xcode@^0.9.1: simple-plist "^0.2.1" uuid "3.0.1" +xdg-basedir@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" @@ -7006,7 +8159,7 @@ xpipe@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/xpipe/-/xpipe-1.0.5.tgz#8dd8bf45fc3f7f55f0e054b878f43a62614dafdf" -xtend@~4.0.0, xtend@~4.0.1: +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" @@ -7057,6 +8210,24 @@ yargs@^11.0.0: y18n "^3.2.1" yargs-parser "^9.0.2" +yargs@^8.0.2: + version "8.0.2" + resolved "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" + dependencies: + camelcase "^4.1.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + read-pkg-up "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^7.0.0" + yargs@^9.0.0: version "9.0.1" resolved "https://registry.npmjs.org/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c" @@ -7074,3 +8245,11 @@ yargs@^9.0.0: which-module "^2.0.0" y18n "^3.2.1" yargs-parser "^7.0.0" + +zip-stream@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/zip-stream/-/zip-stream-2.0.1.tgz#48a062488afe91dda42f823700fae589753ccd34" + dependencies: + archiver-utils "^2.0.0" + compress-commons "^1.2.0" + readable-stream "^2.0.0" From 189d60e7d7f1b400de6027768e7a53ff8f17a605 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Wed, 27 Mar 2019 20:45:16 +0800 Subject: [PATCH 051/103] =?UTF-8?q?feat(cli):=20=E5=BF=AB=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E6=A0=B7=E5=BC=8F=E5=B0=BA=E5=AF=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/src/mini/compileStyle.ts | 4 ++-- packages/taro-cli/src/mini/index.ts | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/taro-cli/src/mini/compileStyle.ts b/packages/taro-cli/src/mini/compileStyle.ts index aeac33ee7e65..5e37028aaeb3 100644 --- a/packages/taro-cli/src/mini/compileStyle.ts +++ b/packages/taro-cli/src/mini/compileStyle.ts @@ -24,7 +24,7 @@ import { processStyleImports, promoteRelativePath } from '../util' -import { CSS_EXT, FILE_PROCESSOR_MAP, DEVICE_RATIO_NAME } from '../util/constants' +import { CSS_EXT, FILE_PROCESSOR_MAP, DEVICE_RATIO_NAME, BUILD_TYPES } from '../util/constants' import { IMiniAppConfig } from '../util/types' import { @@ -137,7 +137,7 @@ async function processStyleWithPostCSS (styleObj: IStyleObj): Promise { if (customAutoprefixerConf.enable) { processors.push(autoprefixer(customAutoprefixerConf.config)) } - if (customPxtransformConf.enable) { + if (customPxtransformConf.enable && buildAdapter !== BUILD_TYPES.QUICKAPP) { processors.push(pxtransform(postcssPxtransformConf)) } if (cssUrlConf.enable) { diff --git a/packages/taro-cli/src/mini/index.ts b/packages/taro-cli/src/mini/index.ts index adf4f6f20422..3820c3dee3ec 100644 --- a/packages/taro-cli/src/mini/index.ts +++ b/packages/taro-cli/src/mini/index.ts @@ -88,7 +88,7 @@ async function buildFrameworkInfo () { } function generateQuickAppManifest () { - const { appConfig, pageConfigs, appPath, outputDir } = getBuildData() + const { appConfig, pageConfigs, appPath, outputDir, projectConfig } = getBuildData() // 生成 router const pages = appConfig.pages as string[] const routerPages = {} @@ -125,6 +125,9 @@ function generateQuickAppManifest () { } quickappJSON.router = router quickappJSON.display = display + quickappJSON.config = Object.assign({}, quickappJSON.config, { + designWidth: projectConfig.designWidth || 750 + }) fs.writeFileSync(path.join(outputDir, 'manifest.json'), JSON.stringify(quickappJSON, null, 2)) } @@ -194,8 +197,7 @@ async function prepareQuickAppEnvironment (isWatch, buildData) { async function runQuickApp (isWatch) { if (isWatch) { - shelljs.exec('npm run server -- --port 12306', { silent: false }) - // shelljs.exec('npm run watch', { silent: false }) + shelljs.exec('npm run watch & npm run server -- --port 12310', { silent: false }) } } From 34702fa0e1484dc5143414434263b987223399a5 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Wed, 27 Mar 2019 20:45:16 +0800 Subject: [PATCH 052/103] =?UTF-8?q?feat(cli|quickapp):=20=E5=BF=AB?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E6=A0=B7=E5=BC=8F=E5=B0=BA=E5=AF=B8=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-quickapp/src/native-api.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/taro-quickapp/src/native-api.js b/packages/taro-quickapp/src/native-api.js index 6299f209cd64..a42f35639031 100644 --- a/packages/taro-quickapp/src/native-api.js +++ b/packages/taro-quickapp/src/native-api.js @@ -1,4 +1,9 @@ -import { onAndSyncApis, noPromiseApis, otherApis } from '@tarojs/taro' +import { + onAndSyncApis, + noPromiseApis, + otherApis, + initPxTransform +} from '@tarojs/taro' import request from './api/request' import storage from './api/storage' @@ -15,9 +20,15 @@ function canIUseWebp () { return true } +function pxTransform (size) { + return size + 'px' +} + export default function initNativeApi (taro) { processApis(taro) taro.request = request taro.canIUseWebp = canIUseWebp + taro.initPxTransform = initPxTransform.bind(taro) + taro.pxTransform = pxTransform.bind(taro) Object.assign(taro, storage) } From 0a1a4458b6448c1c50151665425181d5bd90cf01 Mon Sep 17 00:00:00 2001 From: yuche Date: Mon, 18 Mar 2019 21:34:56 +0800 Subject: [PATCH 053/103] =?UTF-8?q?fix(transformer):=20if-else=20=E5=BD=93?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=8F=98=E9=87=8F=E4=B8=8D=E4=BC=9A=E5=8A=A0?= =?UTF-8?q?=E5=85=A5=20usedState?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/render.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts index d4049aa29433..685075e201a8 100644 --- a/packages/taro-transformer-wx/src/render.ts +++ b/packages/taro-transformer-wx/src/render.ts @@ -570,7 +570,7 @@ export class RenderParser { this.handleConditionExpr(options, jsxElementPath) }) }, - JSXExpressionContainer: this.replaceIdWithTemplate() + JSXExpressionContainer: this.replaceIdWithTemplate(true) } } From 1689c3829ec19832cf2138ba0f66ef9c6d2d2e40 Mon Sep 17 00:00:00 2001 From: yuche Date: Wed, 27 Mar 2019 19:59:40 +0800 Subject: [PATCH 054/103] =?UTF-8?q?feat(weapp):=20=E5=AE=9E=E7=8E=B0=20rea?= =?UTF-8?q?ct=20hooks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/src/mini/index.ts | 2 +- packages/taro-weapp/src/component.js | 6 + packages/taro-weapp/src/create-component.js | 13 +- packages/taro-weapp/src/current-owner.js | 4 + packages/taro-weapp/src/hooks.js | 166 ++++++++++++++++++++ packages/taro-weapp/src/index.js | 5 +- packages/taro-weapp/src/lifecycle.js | 31 ++-- packages/taro-weapp/src/util.js | 8 + 8 files changed, 222 insertions(+), 13 deletions(-) create mode 100644 packages/taro-weapp/src/current-owner.js create mode 100644 packages/taro-weapp/src/hooks.js diff --git a/packages/taro-cli/src/mini/index.ts b/packages/taro-cli/src/mini/index.ts index 3820c3dee3ec..4e1a2a7cd24c 100644 --- a/packages/taro-cli/src/mini/index.ts +++ b/packages/taro-cli/src/mini/index.ts @@ -26,7 +26,7 @@ import { } from './helper' import { buildEntry } from './entry' import { buildPages } from './page' -import { watchFiles } from './watch' +// import { watchFiles } from './watch' import { downloadGithubRepoLatestRelease } from '../util/dowload' const appPath = process.cwd() diff --git a/packages/taro-weapp/src/component.js b/packages/taro-weapp/src/component.js index da767bb920e8..bb18d600792d 100644 --- a/packages/taro-weapp/src/component.js +++ b/packages/taro-weapp/src/component.js @@ -33,6 +33,12 @@ class BaseComponent { path: '' } + _afterScheduleEffect = false + _disableEffect = false + hooks = [] + effects = [] + layoutEffects = [] + constructor (props = {}, isPage) { this.state = {} this.props = props diff --git a/packages/taro-weapp/src/create-component.js b/packages/taro-weapp/src/create-component.js index b96c29bf66da..7c9cf965335e 100644 --- a/packages/taro-weapp/src/create-component.js +++ b/packages/taro-weapp/src/create-component.js @@ -1,8 +1,9 @@ import { getCurrentPageUrl } from '@tarojs/utils' -import { isEmptyObject, noop } from './util' +import { isEmptyObject, noop, isFunction } from './util' import { updateComponent } from './lifecycle' import { cacheDataSet, cacheDataGet, cacheDataHas } from './data-cache' +import { Current } from './current-owner'; const privatePropValName = '__triggerObserer' const anonymousFnNamePreffix = 'funPrivate' @@ -299,6 +300,8 @@ function createComponent (ComponentClass, isPage) { const componentInstance = new ComponentClass(componentProps) componentInstance._constructor && componentInstance._constructor(componentProps) try { + Current.current = componentInstance + Current.index = 0 componentInstance.state = componentInstance._createData() || componentInstance.state } catch (err) { if (isPage) { @@ -358,7 +361,13 @@ function createComponent (ComponentClass, isPage) { } }, detached () { - componentTrigger(this.$component, 'componentWillUnmount') + const component = this.$component + componentTrigger(component, 'componentWillUnmount') + component.hooks.forEach((hook) => { + if (isFunction(hook.cleanup)) { + hook.cleanup() + } + }) } } if (isPage) { diff --git a/packages/taro-weapp/src/current-owner.js b/packages/taro-weapp/src/current-owner.js new file mode 100644 index 000000000000..dfaf7aa3d1dc --- /dev/null +++ b/packages/taro-weapp/src/current-owner.js @@ -0,0 +1,4 @@ +export const Current = { + current: null, + index: 0 +} diff --git a/packages/taro-weapp/src/hooks.js b/packages/taro-weapp/src/hooks.js new file mode 100644 index 000000000000..6b1d00e6e2e5 --- /dev/null +++ b/packages/taro-weapp/src/hooks.js @@ -0,0 +1,166 @@ +import { isFunction, isUndefined, isArray, isNullOrUndef } from './util' +import { Current } from './current-owner' +import nextTick from './next-tick' + +function getHooks (index) { + if (Current.current === null) { + throw new Error(`invalid hooks call: hooks can only be called in a stateless component.`) + } + const hooks = Current.current.hooks + if (index >= hooks.length) { + hooks.push({}) + } + return hooks[index] +} + +export function useState (initialState) { + if (isFunction(initialState)) { + initialState = initialState() + } + const hook = getHooks(Current.index++) + if (!hook.state) { + hook.component = Current.current + hook.state = [ + initialState, + (action) => { + hook.state[0] = isFunction(action) ? action(hook.state[0]) : action + hook.component._disable = false + hook.component.setState({}) + } + ] + } + return hook.state +} + +export function useReducer ( + reducer, + initialState, + initializer +) { + if (isFunction(initialState)) { + initialState = initialState() + } + const hook = getHooks(Current.index++) + if (!hook.state) { + hook.component = Current.current + hook.state = [ + isUndefined(initializer) ? initialState : initializer(initialState), + (action) => { + hook.state[0] = reducer(hook.state[0], action) + hook.component._disable = false + hook.component.setState({}) + } + ] + } + return hook.state +} + +function areDepsChanged (prevDeps, deps) { + if (isNullOrUndef(prevDeps) || isNullOrUndef(deps)) { + return true + } + return deps.some((a, i) => a !== prevDeps[i]) +} + +export function invokeEffects (component, delay) { + const effects = delay ? component.effects : component.layoutEffects + effects.forEach((hook) => { + if (isFunction(hook.cleanup)) { + hook.cleanup() + } + const result = hook.effect() + if (isFunction(result)) { + hook.cleanup = result + } + }) + + if (delay) { + component.effects = [] + } else { + component.layoutEffects = [] + } +} + +let scheduleEffectComponents = [] + +function invokeScheduleEffects (component) { + if (!component._afterScheduleEffect) { + component._afterScheduleEffect = true + scheduleEffectComponents.push(component) + if (scheduleEffectComponents.length === 1) { + nextTick(() => { + setTimeout(() => { + scheduleEffectComponents.forEach((c) => { + c._afterScheduleEffect = false + invokeEffects(c, true) + }) + scheduleEffectComponents = [] + }, 0) + }) + } + } +} + +function useEffectImpl (effect, deps, delay) { + const hook = getHooks(Current.index++) + if (Current.current._disableHooks || !Current.current.__isReady) { + return + } + if (areDepsChanged(hook.deps, deps)) { + hook.effect = effect + hook.deps = deps + + if (delay) { + Current.current.effects = Current.current.effects.concat(hook) + invokeScheduleEffects(Current.current) + } else { + Current.current.layoutEffects = Current.current.layoutEffects.concat(hook) + } + } +} + +export function useEffect (effect, deps) { + useEffectImpl(effect, deps, true) +} + +export function useLayoutEffect (effect, deps) { + useEffectImpl(effect, deps) +} + +export function useRef (initialValue) { + const hook = getHooks(Current.index++) + if (!hook.ref) { + hook.ref = { + current: initialValue + } + } + return hook.ref +} + +export function useMemo (factory, deps) { + const hook = getHooks(Current.index++) + if (areDepsChanged(hook.deps, deps)) { + hook.deps = deps + hook.callback = factory + hook.value = factory() + } + return hook.value +} + +export function useCallback (callback, deps) { + return useMemo(() => callback, deps) +} + +export function useImperativeHandle (ref, init, deps) { + useLayoutEffect(() => { + if (isFunction(ref)) { + ref(init()) + return () => ref(null) + } else if (!isUndefined(ref)) { + ref.current = init() + return () => { + delete ref.current + } + } + }, isArray(deps) ? deps.concat([ref]) : undefined) +} diff --git a/packages/taro-weapp/src/index.js b/packages/taro-weapp/src/index.js index 2eca6eb5a823..f15da579beda 100644 --- a/packages/taro-weapp/src/index.js +++ b/packages/taro-weapp/src/index.js @@ -17,6 +17,7 @@ import createApp from './create-app' import createComponent from './create-component' import initNativeApi from './native-api' import { getElementById } from './util' +import { useEffect, useLayoutEffect, useReducer, useState, useRef, useCallback, useMemo, useImperativeHandle } from './hooks' export const Taro = { Component, @@ -33,7 +34,9 @@ export const Taro = { internal_inline_style, createComponent, internal_get_original, - getElementById + getElementById, + // eslint-disable-next-line object-property-newline + useEffect, useLayoutEffect, useReducer, useState, useRef, useCallback, useMemo, useImperativeHandle } export default Taro diff --git a/packages/taro-weapp/src/lifecycle.js b/packages/taro-weapp/src/lifecycle.js index 4fd8f50d96f2..ccb30acdcffd 100644 --- a/packages/taro-weapp/src/lifecycle.js +++ b/packages/taro-weapp/src/lifecycle.js @@ -2,21 +2,23 @@ import { internal_safe_get as safeGet, internal_safe_set as safeSet } from '@tarojs/taro' -import PropTypes from 'prop-types' +// import PropTypes from 'prop-types' import { componentTrigger } from './create-component' import { shakeFnFromObject, isEmptyObject, diffObjToPath } from './util' +import { Current } from './current-owner' +import { invokeEffects } from './hooks' -const isDEV = typeof process === 'undefined' || - !process.env || - process.env.NODE_ENV !== 'production' +// const isDEV = typeof process === 'undefined' || +// !process.env || +// process.env.NODE_ENV !== 'production' const privatePropKeyName = '_triggerObserer' export function updateComponent (component) { - const { props, __propTypes } = component - if (isDEV && __propTypes) { - const componentName = component.constructor.name || component.constructor.toString().match(/^function\s*([^\s(]+)/)[1] - PropTypes.checkPropTypes(__propTypes, props, 'prop', componentName) - } + const { props } = component + // if (isDEV && __propTypes) { + // const componentName = component.constructor.name || component.constructor.toString().match(/^function\s*([^\s(]+)/)[1] + // PropTypes.checkPropTypes(__propTypes, props, 'prop', componentName) + // } const prevProps = component.prevProps || props component.props = prevProps if (component.__mounted && component._unsafeCallUpdate === true && component.componentWillReceiveProps) { @@ -63,7 +65,15 @@ function doUpdate (component, prevProps, prevState) { if (component._createData) { // 返回null或undefined则保持不变 const runLoopRef = !component.__mounted + if (component.__isReady) { + Current.current = component + Current.index = 0 + invokeEffects(component, true) + } data = component._createData(state, props, runLoopRef) || data + if (component.__isReady) { + Current.current = null + } } let privatePropKeyVal = component.$scope.data[privatePropKeyName] || false @@ -101,6 +111,7 @@ function doUpdate (component, prevProps, prevState) { component.$scope.setData(dataDiff, function () { if (__mounted) { + invokeEffects(component) if (component['$$refs'] && component['$$refs'].length > 0) { component['$$refs'].forEach(ref => { // 只有 component 类型能做判断。因为 querySelector 每次调用都一定返回 nodeRefs,无法得知 dom 类型的挂载状态。 @@ -119,7 +130,9 @@ function doUpdate (component, prevProps, prevState) { } if (component['$$hasLoopRef']) { + component._disableEffect = true component._createData(component.state, component.props, true) + component._disableEffect = false } if (typeof component.componentDidUpdate === 'function') { diff --git a/packages/taro-weapp/src/util.js b/packages/taro-weapp/src/util.js index 2355941129c2..e25bf72608d5 100644 --- a/packages/taro-weapp/src/util.js +++ b/packages/taro-weapp/src/util.js @@ -12,6 +12,14 @@ export function isEmptyObject (obj) { return true } +export function isUndefined (o) { + return o === undefined +} + +export function isNullOrUndef (o) { + return isUndefined(o) || o === null +} + /** * JSON 克隆 * @param {Object | Json} jsonObj json对象 From 855e2ebdd3d3a068f7e6f7c075e4b1ab88a1137e Mon Sep 17 00:00:00 2001 From: yuche Date: Thu, 28 Mar 2019 16:50:07 +0800 Subject: [PATCH 055/103] =?UTF-8?q?feat(taro):=20=E5=A2=9E=E5=8A=A0=20hook?= =?UTF-8?q?s=20=E7=9A=84=20typings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro/types/index.d.ts | 216 +++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) diff --git a/packages/taro/types/index.d.ts b/packages/taro/types/index.d.ts index 78ca4c0b3e1c..23e4a30b8f4f 100644 --- a/packages/taro/types/index.d.ts +++ b/packages/taro/types/index.d.ts @@ -11220,4 +11220,220 @@ declare namespace Taro { function getCurrentPages(): Page[] function getApp(): any + + // + // React Hooks + // ---------------------------------------------------------------------- + + interface RefObject { + readonly current: T | null; + } + + // based on the code in https://github.com/facebook/react/pull/13968 + + // Unlike the class component setState, the updates are not allowed to be partial + type SetStateAction = S | ((prevState: S) => S); + // this technically does accept a second argument, but it's already under a deprecation warning + // and it's not even released so probably better to not define it. + type Dispatch = (value: A) => void; + // Unlike redux, the actions _can_ be anything + type Reducer = (prevState: S, action: A) => S; + // types used to try and prevent the compiler from reducing S + // to a supertype common with the second argument to useReducer() + type ReducerState> = R extends Reducer ? S : never; + type ReducerAction> = R extends Reducer ? A : never; + // The identity check is done with the SameValue algorithm (Object.is), which is stricter than === + // TODO (TypeScript 3.0): ReadonlyArray + type DependencyList = ReadonlyArray; + + // NOTE: callbacks are _only_ allowed to return either void, or a destructor. + // The destructor is itself only allowed to return void. + type EffectCallback = () => (void | (() => void | undefined)); + + interface MutableRefObject { + current: T; + } + + /** + * Returns a stateful value, and a function to update it. + * + * @version 16.8.0 + * @see https://reactjs.org/docs/hooks-reference.html#usestate + */ + function useState(initialState: S | (() => S)): [S, Dispatch>]; + // convenience overload when first argument is ommitted + /** + * Returns a stateful value, and a function to update it. + * + * @version 16.8.0 + * @see https://reactjs.org/docs/hooks-reference.html#usestate + */ + function useState(): [S | undefined, Dispatch>]; + /** + * An alternative to `useState`. + * + * `useReducer` is usually preferable to `useState` when you have complex state logic that involves + * multiple sub-values. It also lets you optimize performance for components that trigger deep + * updates because you can pass `dispatch` down instead of callbacks. + * + * @version 16.8.0 + * @see https://reactjs.org/docs/hooks-reference.html#usereducer + */ + // overload where "I" may be a subset of ReducerState; used to provide autocompletion. + // If "I" matches ReducerState exactly then the last overload will allow initializer to be ommitted. + // the last overload effectively behaves as if the identity function (x => x) is the initializer. + function useReducer, I>( + reducer: R, + initializerArg: I & ReducerState, + initializer?: (arg: I & ReducerState) => ReducerState + ): [ReducerState, Dispatch>]; + /** + * An alternative to `useState`. + * + * `useReducer` is usually preferable to `useState` when you have complex state logic that involves + * multiple sub-values. It also lets you optimize performance for components that trigger deep + * updates because you can pass `dispatch` down instead of callbacks. + * + * @version 16.8.0 + * @see https://reactjs.org/docs/hooks-reference.html#usereducer + */ + // overload for free "I"; all goes as long as initializer converts it into "ReducerState". + function useReducer, I>( + reducer: R, + initializerArg: I, + initializer: (arg: I) => ReducerState + ): [ReducerState, Dispatch>]; + /** + * An alternative to `useState`. + * + * `useReducer` is usually preferable to `useState` when you have complex state logic that involves + * multiple sub-values. It also lets you optimize performance for components that trigger deep + * updates because you can pass `dispatch` down instead of callbacks. + * + * @version 16.8.0 + * @see https://reactjs.org/docs/hooks-reference.html#usereducer + */ + + // I'm not sure if I keep this 2-ary or if I make it (2,3)-ary; it's currently (2,3)-ary. + // The Flow types do have an overload for 3-ary invocation with undefined initializer. + + // NOTE: without the ReducerState indirection, TypeScript would reduce S to be the most common + // supertype between the reducer's return type and the initialState (or the initializer's return type), + // which would prevent autocompletion from ever working. + + // TODO: double-check if this weird overload logic is necessary. It is possible it's either a bug + // in older versions, or a regression in newer versions of the typescript completion service. + function useReducer>( + reducer: R, + initialState: ReducerState, + initializer?: undefined + ): [ReducerState, Dispatch>]; + /** + * `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument + * (`initialValue`). The returned object will persist for the full lifetime of the component. + * + * Note that `useRef()` is useful for more than the `ref` attribute. It’s handy for keeping any mutable + * value around similar to how you’d use instance fields in classes. + * + * @version 16.8.0 + * @see https://reactjs.org/docs/hooks-reference.html#useref + */ + // TODO (TypeScript 3.0): + function useRef(initialValue: T): MutableRefObject; + // convenience overload for refs given as a ref prop as they typically start with a null value + /** + * `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument + * (`initialValue`). The returned object will persist for the full lifetime of the component. + * + * Note that `useRef()` is useful for more than the `ref` attribute. It’s handy for keeping any mutable + * value around similar to how you’d use instance fields in classes. + * + * Usage note: if you need the result of useRef to be directly mutable, include `| null` in the type + * of the generic argument. + * + * @version 16.8.0 + * @see https://reactjs.org/docs/hooks-reference.html#useref + */ + // TODO (TypeScript 3.0): + function useRef(initialValue: T|null): RefObject; + // convenience overload for potentially undefined initialValue / call with 0 arguments + // has a default to stop it from defaulting to {} instead + /** + * `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument + * (`initialValue`). The returned object will persist for the full lifetime of the component. + * + * Note that `useRef()` is useful for more than the `ref` attribute. It’s handy for keeping any mutable + * value around similar to how you’d use instance fields in classes. + * + * @version 16.8.0 + * @see https://reactjs.org/docs/hooks-reference.html#useref + */ + // TODO (TypeScript 3.0): + function useRef(): MutableRefObject; + /** + * The signature is identical to `useEffect`, but it fires synchronously after all DOM mutations. + * Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside + * `useLayoutEffect` will be flushed synchronously, before the browser has a chance to paint. + * + * Prefer the standard `useEffect` when possible to avoid blocking visual updates. + * + * If you’re migrating code from a class component, `useLayoutEffect` fires in the same phase as + * `componentDidMount` and `componentDidUpdate`. + * + * @version 16.8.0 + * @see https://reactjs.org/docs/hooks-reference.html#uselayouteffect + */ + function useLayoutEffect(effect: EffectCallback, deps?: DependencyList): void; + /** + * Accepts a function that contains imperative, possibly effectful code. + * + * @param effect Imperative function that can return a cleanup function + * @param deps If present, effect will only activate if the values in the list change. + * + * @version 16.8.0 + * @see https://reactjs.org/docs/hooks-reference.html#useeffect + */ + function useEffect(effect: EffectCallback, deps?: DependencyList): void; + // NOTE: this does not accept strings, but this will have to be fixed by removing strings from type Ref + /** + * `useImperativeHandle` customizes the instance value that is exposed to parent components when using + * `ref`. As always, imperative code using refs should be avoided in most cases. + * + * `useImperativeHandle` should be used with `React.forwardRef`. + * + * @version 16.8.0 + * @see https://reactjs.org/docs/hooks-reference.html#useimperativehandle + */ + function useImperativeHandle(ref: RefObject|undefined, init: () => R, deps?: DependencyList): void; + // I made 'inputs' required here and in useMemo as there's no point to memoizing without the memoization key + // useCallback(X) is identical to just using X, useMemo(() => Y) is identical to just using Y. + /** + * `useCallback` will return a memoized version of the callback that only changes if one of the `inputs` + * has changed. + * + * @version 16.8.0 + * @see https://reactjs.org/docs/hooks-reference.html#usecallback + */ + // TODO (TypeScript 3.0): unknown> + function useCallback any>(callback: T, deps: DependencyList): T; + /** + * `useMemo` will only recompute the memoized value when one of the `deps` has changed. + * + * Usage note: if calling `useMemo` with a referentially stable function, also give it as the input in + * the second argument. + * + * ```ts + * function expensive () { ... } + * + * function Component () { + * const expensiveResult = useMemo(expensive, [expensive]) + * return ... + * } + * ``` + * + * @version 16.8.0 + * @see https://reactjs.org/docs/hooks-reference.html#usememo + */ + // allow undefined, but don't make it optional as that is very likely a mistake + function useMemo(factory: () => T, deps: DependencyList | undefined): T; } From e89d582469616682f6563366c3f9ee4ec979b97c Mon Sep 17 00:00:00 2001 From: yuche Date: Mon, 1 Apr 2019 16:14:34 +0800 Subject: [PATCH 056/103] =?UTF-8?q?fix(transformer):=20=E7=89=B9=E6=AE=8A?= =?UTF-8?q?=E5=BF=AB=E5=BA=94=E7=94=A8=E7=BB=84=E4=BB=B6=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E5=BD=93=E6=88=90=E8=87=AA=E5=AE=9A=E4=B9=89=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/taro-transformer-wx/src/index.ts b/packages/taro-transformer-wx/src/index.ts index c9c42fc236b1..18ce4581ef2e 100644 --- a/packages/taro-transformer-wx/src/index.ts +++ b/packages/taro-transformer-wx/src/index.ts @@ -149,7 +149,10 @@ interface TransformResult extends Result { export default function transform (options: Options): TransformResult { if (options.adapter) { setAdapter(options.adapter) - if (Adapter.type === Adapters.quickapp) DEFAULT_Component_SET.add('div') + if (Adapter.type === Adapters.quickapp) { + DEFAULT_Component_SET.add('div') + quickappComponentName.forEach((n) => DEFAULT_Component_SET.delete(n)) + } } if (Adapter.type === Adapters.swan) { setLoopOriginal('privateOriginal') From 83bb741c39e01a040a8ffc1bf71b8ad97dc39a22 Mon Sep 17 00:00:00 2001 From: yuche Date: Mon, 1 Apr 2019 17:02:31 +0800 Subject: [PATCH 057/103] =?UTF-8?q?fix(transformer):=20=E5=BF=AB=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E7=89=B9=E6=AE=8A=E7=BB=84=E4=BB=B6=E4=B8=8D=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E5=8A=A0=E5=85=A5=E6=9C=80=E7=BB=88=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E7=9A=84=20components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/class.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/taro-transformer-wx/src/class.ts b/packages/taro-transformer-wx/src/class.ts index b825454b10dc..b4dae4ef7260 100644 --- a/packages/taro-transformer-wx/src/class.ts +++ b/packages/taro-transformer-wx/src/class.ts @@ -13,7 +13,7 @@ import { incrementId, isContainStopPropagation } from './utils' -import { DEFAULT_Component_SET, COMPONENTS_PACKAGE_NAME } from './constant' +import { DEFAULT_Component_SET, COMPONENTS_PACKAGE_NAME, quickappComponentName } from './constant' import { kebabCase, uniqueId, get as safeGet, set as safeSet } from 'lodash' import { RenderParser } from './render' import { findJSXAttrByName } from './jsx' @@ -655,6 +655,9 @@ class Transformer { if (name.startsWith('Taro') && component.sourcePath === COMPONENTS_PACKAGE_NAME) { return } + if (Adapter.type === Adapters.quickapp && quickappComponentName.has(name)) { + return + } this.result.components.push({ path: pathResolver(component.sourcePath, this.sourcePath), name: kebabCase(name), From 369758d6d1107f0fad357dd4fc0b8683b04c018c Mon Sep 17 00:00:00 2001 From: luckyadam Date: Mon, 1 Apr 2019 17:23:20 +0800 Subject: [PATCH 058/103] =?UTF-8?q?feat(quickapp):=20=E5=BF=AB=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E4=BA=8B=E4=BB=B6=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-quickapp/src/create-component.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/taro-quickapp/src/create-component.js b/packages/taro-quickapp/src/create-component.js index fe6f5fdc5714..6cde8465cb45 100644 --- a/packages/taro-quickapp/src/create-component.js +++ b/packages/taro-quickapp/src/create-component.js @@ -36,6 +36,14 @@ function filterProps (properties, defaultProps = {}, componentProps = {}, compon return newProps } +function bindEvents (componentConf, componentInstance, events) { + events.forEach(name => { + if (componentInstance[name]) { + componentConf[name] = componentInstance[name] + } + }) +} + function getPageUrlParams (url) { const queryStr = url.replace(/^.*\?&?/, '') const params = queryToJson(queryStr) @@ -148,5 +156,6 @@ export default function createComponent (ComponentClass, isPage) { } }) } + ComponentClass['$$events'] && bindEvents(componentConf, componentInstance, ComponentClass['$$events']) return componentConf } From af279bca7d615975c2ced4d7216875d9d51c8ce5 Mon Sep 17 00:00:00 2001 From: yuche Date: Mon, 1 Apr 2019 17:38:33 +0800 Subject: [PATCH 059/103] =?UTF-8?q?refactor(transformer):=20=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E5=BF=AB=E5=BA=94=E7=94=A8=E7=9A=84=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89/=E5=86=85=E7=BD=AE=E7=BB=84=E4=BB=B6=E6=9C=BA?= =?UTF-8?q?=E5=88=B6=EF=BC=9A=20*=20=E9=99=A4=E4=BA=86div=20=E4=B9=8B?= =?UTF-8?q?=E5=A4=96=E6=89=80=E6=9C=89=E7=BB=84=E4=BB=B6=E9=83=BD=E6=8C=89?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E7=BB=84=E4=BB=B6=E5=A4=84=E7=90=86?= =?UTF-8?q?=20*=20=E4=BB=BB=E4=BD=95=E7=BB=84=E4=BB=B6=E7=9A=84=E6=89=80?= =?UTF-8?q?=E6=9C=89=E4=BA=8B=E4=BB=B6=E5=90=8D=E9=83=BD=E4=BF=9D=E7=95=99?= =?UTF-8?q?=E5=8E=9F=E6=A0=B7=E8=BE=93=E5=87=BA=20*=20=E5=86=85=E7=BD=AE?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E5=94=AF=E4=B8=80=E8=B5=B7=E4=BD=9C=E7=94=A8?= =?UTF-8?q?=E7=9A=84=E5=9C=B0=E6=96=B9=E5=9C=A8=E4=BA=8E=E4=B8=8D=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E5=8A=A0=E5=85=A5=20result.components=20*=20=E5=BF=AB?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E7=89=B9=E6=AE=8A=E7=BB=84=E4=BB=B6(quickapp?= =?UTF-8?q?ComponentName)=E4=BB=85=E4=BD=9C=E4=B8=BA=E6=9B=B4=E5=90=8D?= =?UTF-8?q?=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/class.ts | 4 ++-- packages/taro-transformer-wx/src/constant.ts | 4 ++++ packages/taro-transformer-wx/src/index.ts | 2 +- packages/taro-transformer-wx/src/jsx.ts | 6 +++--- packages/taro-transformer-wx/src/render.ts | 3 +++ 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/taro-transformer-wx/src/class.ts b/packages/taro-transformer-wx/src/class.ts index b4dae4ef7260..4ce2530865dc 100644 --- a/packages/taro-transformer-wx/src/class.ts +++ b/packages/taro-transformer-wx/src/class.ts @@ -13,7 +13,7 @@ import { incrementId, isContainStopPropagation } from './utils' -import { DEFAULT_Component_SET, COMPONENTS_PACKAGE_NAME, quickappComponentName } from './constant' +import { DEFAULT_Component_SET, COMPONENTS_PACKAGE_NAME, DEFAULT_Component_SET_COPY } from './constant' import { kebabCase, uniqueId, get as safeGet, set as safeSet } from 'lodash' import { RenderParser } from './render' import { findJSXAttrByName } from './jsx' @@ -655,7 +655,7 @@ class Transformer { if (name.startsWith('Taro') && component.sourcePath === COMPONENTS_PACKAGE_NAME) { return } - if (Adapter.type === Adapters.quickapp && quickappComponentName.has(name)) { + if (Adapter.type === Adapters.quickapp && DEFAULT_Component_SET_COPY.has(name)) { return } this.result.components.push({ diff --git a/packages/taro-transformer-wx/src/constant.ts b/packages/taro-transformer-wx/src/constant.ts index c986a565f897..7bc2223a3901 100644 --- a/packages/taro-transformer-wx/src/constant.ts +++ b/packages/taro-transformer-wx/src/constant.ts @@ -50,6 +50,10 @@ export const DEFAULT_Component_SET = new Set([ 'Template' ]) +// tslint:disable-next-line:variable-name +export const DEFAULT_Component_SET_COPY = new Set([]) +DEFAULT_Component_SET.forEach((c) => DEFAULT_Component_SET_COPY.add(c)) + export const INTERNAL_SAFE_GET = 'internal_safe_get' export const TARO_PACKAGE_NAME = '@tarojs/taro' diff --git a/packages/taro-transformer-wx/src/index.ts b/packages/taro-transformer-wx/src/index.ts index 18ce4581ef2e..095c1d38bc0b 100644 --- a/packages/taro-transformer-wx/src/index.ts +++ b/packages/taro-transformer-wx/src/index.ts @@ -150,8 +150,8 @@ export default function transform (options: Options): TransformResult { if (options.adapter) { setAdapter(options.adapter) if (Adapter.type === Adapters.quickapp) { + DEFAULT_Component_SET.clear() DEFAULT_Component_SET.add('div') - quickappComponentName.forEach((n) => DEFAULT_Component_SET.delete(n)) } } if (Adapter.type === Adapters.swan) { diff --git a/packages/taro-transformer-wx/src/jsx.ts b/packages/taro-transformer-wx/src/jsx.ts index 88fc4757a1c9..b3c50932a655 100644 --- a/packages/taro-transformer-wx/src/jsx.ts +++ b/packages/taro-transformer-wx/src/jsx.ts @@ -199,7 +199,7 @@ export function parseJSXElement (element: t.JSXElement): string { let value: string | boolean = true let attrValue = attr.value if (typeof name === 'string') { - const isAlipayEvent = Adapter.type === Adapters.alipay && /(^on[A-Z_])|(^catch[A-Z_])/.test(name) + const isAlipayOrQuickappEvent = (Adapter.type === Adapters.alipay || Adapter.type === Adapters.quickapp) && /(^on[A-Z_])|(^catch[A-Z_])/.test(name) if (t.isStringLiteral(attrValue)) { value = attrValue.value } else if (t.isJSXExpressionContainer(attrValue)) { @@ -229,7 +229,7 @@ export function parseJSXElement (element: t.JSXElement): string { value = code } } else { - value = isBindEvent || isAlipayEvent ? code : `{{${isJSXMetHod && name === 'data' ? '...' : ''}${code}}}` + value = isBindEvent || isAlipayOrQuickappEvent ? code : `{{${isJSXMetHod && name === 'data' ? '...' : ''}${code}}}` } } if (Adapter.type === Adapters.swan && name === Adapter.for) { @@ -257,7 +257,7 @@ export function parseJSXElement (element: t.JSXElement): string { } else if ( componentSpecialProps && componentSpecialProps.has(name) || name.startsWith('__fn_') || - isAlipayEvent + isAlipayOrQuickappEvent ) { obj[name] = value } else { diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts index 685075e201a8..cc688b1f5b39 100644 --- a/packages/taro-transformer-wx/src/render.ts +++ b/packages/taro-transformer-wx/src/render.ts @@ -911,6 +911,9 @@ export class RenderParser { } } path.node.name = t.jSXIdentifier(transformName) + } else if (Adapter.type === Adapters.quickapp) { + const transformName = name.name + path.node.name = t.jSXIdentifier(transformName) } else if (DEFAULT_Component_SET.has(componentName)) { let transformName = `${eventShouldBeCatched ? 'catch' : 'bind'}` + name.name.slice(2).toLowerCase() From 8574580512c96c9f57a37677ae2563c7b136e941 Mon Sep 17 00:00:00 2001 From: yuche Date: Mon, 1 Apr 2019 21:06:37 +0800 Subject: [PATCH 060/103] =?UTF-8?q?refactor(transformer):=20=E5=BF=AB?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E4=BA=8B=E4=BB=B6=20observer=20=E6=9B=B4?= =?UTF-8?q?=E5=90=8D=EF=BC=9A=20propName:=20=5F=5FtriggerObserer=20->=20pr?= =?UTF-8?q?ivateTriggerObserer=20propValue:=20=5F=5FtriggerObserer=20->=20?= =?UTF-8?q?privateTriggerObsererKey?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/jsx.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/taro-transformer-wx/src/jsx.ts b/packages/taro-transformer-wx/src/jsx.ts index b3c50932a655..67e1fdde2550 100644 --- a/packages/taro-transformer-wx/src/jsx.ts +++ b/packages/taro-transformer-wx/src/jsx.ts @@ -159,7 +159,8 @@ function parseJSXChildren ( export function parseJSXElement (element: t.JSXElement): string { const children = element.children const { attributes, name } = element.openingElement - const TRIGGER_OBSERER = Adapter.type === Adapters.swan ? 'privateTriggerObserer' : '__triggerObserer' + const TRIGGER_OBSERER = Adapter.type === Adapters.swan || Adapter.type === Adapters.quickapp ? 'privateTriggerObserer' : '__triggerObserer' + const TRIGGER_OBSERER_KEY = Adapter.type === Adapters.quickapp ? 'privateTriggerObsererKey' : '_triggerObserer' if (t.isJSXMemberExpression(name)) { throw codeFrameError(name.loc, '暂不支持 JSX 成员表达式') } @@ -265,12 +266,12 @@ export function parseJSXElement (element: t.JSXElement): string { } } if (!isDefaultComponent && !specialComponentName.includes(componentName)) { - obj[TRIGGER_OBSERER] = '{{ _triggerObserer }}' + obj[TRIGGER_OBSERER] = `{{ ${TRIGGER_OBSERER_KEY} }}` } return obj }, {}) } else if (!isDefaultComponent && !specialComponentName.includes(componentName)) { - attributesTrans[TRIGGER_OBSERER] = '{{ _triggerObserer }}' + attributesTrans[TRIGGER_OBSERER] = `{{ ${TRIGGER_OBSERER_KEY} }}` } return createHTMLElement({ From 20605d3d522bf45df2e2138b18adfcfc95acb346 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Mon, 1 Apr 2019 23:09:55 +0800 Subject: [PATCH 061/103] =?UTF-8?q?fix(cli):=20=E5=BF=AB=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E6=97=B6=E8=87=AA=E5=AE=9A=E4=B9=89=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E6=B2=A1=E6=9C=89=E7=94=9F=E6=88=90=20import=20?= =?UTF-8?q?=E5=BC=95=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/src/mini/component.ts | 6 +++++- packages/taro-cli/src/mini/page.ts | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/taro-cli/src/mini/component.ts b/packages/taro-cli/src/mini/component.ts index b0c8c4244871..f6b9a311d600 100644 --- a/packages/taro-cli/src/mini/component.ts +++ b/packages/taro-cli/src/mini/component.ts @@ -247,11 +247,15 @@ export async function buildSingleComponent ( } else { // 快应用编译,搜集创建组件 ux 文件 const importTaroSelfComponents = getImportTaroSelfComponents(outputComponentJSPath, res.taroSelfComponents) + const importCustomComponents = new Set(componentDepComponents.map(item => { + delete item.type + return item + })) const styleRelativePath = promoteRelativePath(path.relative(outputComponentJSPath, outputComponentWXSSPath)) const uxTxt = generateQuickAppUx({ script: resCode, style: styleRelativePath, - imports: importTaroSelfComponents, + imports: new Set([...importTaroSelfComponents, ...importCustomComponents]), template: componentWXMLContent }) fs.writeFileSync(outputComponentWXMLPath, uxTxt) diff --git a/packages/taro-cli/src/mini/page.ts b/packages/taro-cli/src/mini/page.ts index 4405c7fd23bc..1c263f960574 100644 --- a/packages/taro-cli/src/mini/page.ts +++ b/packages/taro-cli/src/mini/page.ts @@ -129,12 +129,16 @@ export async function buildSinglePage (page: string) { } else { // 快应用编译,搜集创建页面 ux 文件 const importTaroSelfComponents = getImportTaroSelfComponents(outputPageJSPath, res.taroSelfComponents) + const importCustomComponents = new Set(pageDepComponents.map(item => { + delete item.type + return item + })) // 生成页面 ux 文件 const styleRelativePath = promoteRelativePath(path.relative(outputPageJSPath, outputPageWXSSPath)) const uxTxt = generateQuickAppUx({ script: resCode, style: styleRelativePath, - imports: importTaroSelfComponents, + imports: new Set([...importTaroSelfComponents, ...importCustomComponents]), template: pageWXMLContent }) fs.writeFileSync(outputPageWXMLPath, uxTxt) From 5c611b6ca883b705f9ca243bd46faddfd548227e Mon Sep 17 00:00:00 2001 From: luckyadam Date: Mon, 1 Apr 2019 23:11:13 +0800 Subject: [PATCH 062/103] =?UTF-8?q?feat(quickapp):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E6=94=AF=E6=8C=81=20&&=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=20setState=20=E5=AE=9E=E7=8E=B0=E5=8F=8A=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E7=94=9F=E5=91=BD=E5=91=A8=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../taro-quickapp/src/create-component.js | 140 +++++++++++++++++- packages/taro-quickapp/src/lifecycle.js | 26 +++- 2 files changed, 157 insertions(+), 9 deletions(-) diff --git a/packages/taro-quickapp/src/create-component.js b/packages/taro-quickapp/src/create-component.js index 6cde8465cb45..8213f58a8629 100644 --- a/packages/taro-quickapp/src/create-component.js +++ b/packages/taro-quickapp/src/create-component.js @@ -2,7 +2,8 @@ import { isEmptyObject, queryToJson } from './util' import { cacheDataGet, cacheDataHas } from './data-cache' import { updateComponent } from './lifecycle' -const privatePropValName = '__triggerObserer' +const privatePropValName = 'privateTriggerObserer' +const anonymousFnNamePreffix = 'funPrivate' const componentFnReg = /^__fn_/ const PRELOAD_DATA_KEY = 'preload' const pageExtraFns = ['onBackPress', 'onMenuPress'] @@ -15,7 +16,7 @@ function filterProps (properties, defaultProps = {}, componentProps = {}, compon } if (typeof componentProps[propName] === 'function') { newProps[propName] = componentProps[propName] - } else if (propName in componentData) { + } else if (componentData && propName in componentData) { newProps[propName] = componentData[propName] } if (componentFnReg.test(propName)) { @@ -36,12 +37,135 @@ function filterProps (properties, defaultProps = {}, componentProps = {}, compon return newProps } -function bindEvents (componentConf, componentInstance, events) { +function processEvent (eventHandlerName, obj) { + if (obj[eventHandlerName]) return + + obj[eventHandlerName] = function (event) { + if (event) { + event.preventDefault = function () {} + event.stopPropagation = function () {} + event.currentTarget = event.currentTarget || event.target || {} + if (event.target) { + Object.assign(event.target, event.detail) + } + Object.assign(event.currentTarget, event.detail) + } + + const scope = this.$component + let callScope = scope + const isAnonymousFn = eventHandlerName.indexOf(anonymousFnNamePreffix) > -1 + let realArgs = [] + let detailArgs = [] + let datasetArgs = [] + let isScopeBinded = false + // 解析从dataset中传过来的参数 + const dataset = event.currentTarget.dataset || {} + const bindArgs = {} + const eventType = event.type.toLocaleLowerCase() + Object.keys(dataset).forEach(key => { + let keyLower = key.toLocaleLowerCase() + if (/^e/.test(keyLower)) { + // 小程序属性里中划线后跟一个下划线会解析成不同的结果 + keyLower = keyLower.replace(/^e/, '') + if (keyLower.indexOf(eventType) >= 0) { + const argName = keyLower.replace(eventType, '') + if (/^(a[a-z]|so)$/.test(argName)) { + bindArgs[argName] = dataset[key] + } + } + } + }) + // 如果是通过triggerEvent触发,并且带有参数 + if (event.__arguments && event.__arguments.length > 0) { + detailArgs = event.__arguments + } + // 普通的事件(非匿名函数),会直接call + if (!isAnonymousFn) { + if ('so' in bindArgs) { + if (bindArgs['so'] !== 'this') { + callScope = bindArgs['so'] + } + isScopeBinded = true + delete bindArgs['so'] + } + if (detailArgs.length > 0) { + !isScopeBinded && detailArgs[0] && (callScope = detailArgs[0]) + detailArgs.shift() + } + if (!isEmptyObject(bindArgs)) { + datasetArgs = Object.keys(bindArgs) + .sort() + .map(key => bindArgs[key]) + } + realArgs = [...datasetArgs, ...detailArgs, event] + } else { + // 匿名函数,会将scope作为第一个参数 + let _scope = null + if ('so' in bindArgs) { + if (bindArgs['so'] !== 'this') { + _scope = bindArgs['so'] + } + isScopeBinded = true + delete bindArgs['so'] + } + if (detailArgs.length > 0) { + !isScopeBinded && detailArgs[0] && (callScope = detailArgs[0]) + detailArgs.shift() + } + if (!isEmptyObject(bindArgs)) { + datasetArgs = Object.keys(bindArgs) + .sort() + .map(key => bindArgs[key]) + } + realArgs = [_scope, ...datasetArgs, ...detailArgs, event] + } + return scope[eventHandlerName].apply(callScope, realArgs) + } +} + +function bindEvents (componentConf, events) { events.forEach(name => { - if (componentInstance[name]) { - componentConf[name] = componentInstance[name] + processEvent(name, componentConf) + }) +} + +function bindStaticFns (componentConf, ComponentClass) { + for (const key in ComponentClass) { + typeof ComponentClass[key] === 'function' && (componentConf[key] = ComponentClass[key]) + } + // 低版本 IOS 下部分属性不能直接访问 + Object.getOwnPropertyNames(ComponentClass).forEach(key => { + const excludes = ['arguments', 'caller', 'length', 'name', 'prototype'] + if (excludes.indexOf(key) < 0) { + typeof ComponentClass[key] === 'function' && (componentConf[key] = ComponentClass[key]) + } + }) +} + +function bindProperties (componentConf, ComponentClass) { + componentConf.properties = ComponentClass.properties || {} + const defaultProps = ComponentClass.defaultProps || {} + for (const key in defaultProps) { + if (defaultProps.hasOwnProperty(key)) { + componentConf.properties[key] = { + type: null, + value: defaultProps[key] + } } + } + componentConf.props = [] + Object.keys(componentConf.properties).forEach(item => { + componentConf.props.push(item) }) + componentConf.props.push(privatePropValName) + componentConf.onPrivatePropChange = function () { + if (!this.$component || !this.$component.__isReady) return + const nextProps = filterProps(ComponentClass.properties, ComponentClass.defaultProps, this.$component.props, this) + this.$component.props = nextProps + this.$component._unsafeCallUpdate = true + updateComponent(this.$component) + this.$component._unsafeCallUpdate = false + } } function getPageUrlParams (url) { @@ -121,6 +245,8 @@ export default function createComponent (ComponentClass, isPage) { // this.$component.$router.path = getCurrentPageUrl() initComponent.apply(this, [ComponentClass, isPage]) } + // 监听数据变化 + this.$watch(privatePropValName, 'onPrivatePropChange') }, onReady () { @@ -156,6 +282,8 @@ export default function createComponent (ComponentClass, isPage) { } }) } - ComponentClass['$$events'] && bindEvents(componentConf, componentInstance, ComponentClass['$$events']) + bindStaticFns(componentConf, ComponentClass) + bindProperties(componentConf, ComponentClass) + ComponentClass['$$events'] && bindEvents(componentConf, ComponentClass['$$events']) return componentConf } diff --git a/packages/taro-quickapp/src/lifecycle.js b/packages/taro-quickapp/src/lifecycle.js index 0bb63bfebb99..386c454234d1 100644 --- a/packages/taro-quickapp/src/lifecycle.js +++ b/packages/taro-quickapp/src/lifecycle.js @@ -9,7 +9,7 @@ import { shakeFnFromObject, isEmptyObject } from './util' const isDEV = typeof process === 'undefined' || !process.env || process.env.NODE_ENV !== 'production' -const privatePropKeyName = '_triggerObserer' +const privatePropKeyName = 'privateTriggerObsererKey' export function updateComponent (component) { const { props, __propTypes } = component @@ -62,7 +62,7 @@ function doUpdate (component, prevProps, prevState) { // 返回null或undefined则保持不变 data = component._createData(state, props) || data } - let privatePropKeyVal = component.$scope[privatePropKeyName] || false + let privatePropKeyVal = component.$scope[privatePropKeyName] || 0 data = Object.assign({}, props, data) if (component.$usedState && component.$usedState.length) { @@ -85,7 +85,7 @@ function doUpdate (component, prevProps, prevState) { data = _data } // 改变这个私有的props用来触发(observer)子组件的更新 - data[privatePropKeyName] = !privatePropKeyVal + data[privatePropKeyName] = privatePropKeyVal + 1 const __mounted = component.__mounted // 每次 setData 都独立生成一个 callback 数组 @@ -94,4 +94,24 @@ function doUpdate (component, prevProps, prevState) { cbs = component._pendingCallbacks component._pendingCallbacks = [] } + + Object.keys(data).map(item => { + if (!(item in component.$scope)) { + component.$scope.$set(item, data[item]) + } else { + component.$scope[item] = data[item] + } + }) + if (__mounted) { + if (typeof component.componentDidUpdate === 'function') { + component.componentDidUpdate(prevProps, prevState) + } + } + + if (cbs.length) { + let i = cbs.length + while (--i >= 0) { + typeof cbs[i] === 'function' && cbs[i].call(component) + } + } } From a11b2bc54135d11caffdeefb5e036696d56e4dc3 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Tue, 2 Apr 2019 10:31:25 +0800 Subject: [PATCH 063/103] =?UTF-8?q?fix(quickapp):=20=E5=BF=AB=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E5=B1=9E=E6=80=A7=E4=BC=A0=E9=80=92=E6=9C=80=E5=90=8E?= =?UTF-8?q?=E5=B0=8F=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-quickapp/src/create-component.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/taro-quickapp/src/create-component.js b/packages/taro-quickapp/src/create-component.js index 8213f58a8629..3798d79a3f2b 100644 --- a/packages/taro-quickapp/src/create-component.js +++ b/packages/taro-quickapp/src/create-component.js @@ -2,7 +2,7 @@ import { isEmptyObject, queryToJson } from './util' import { cacheDataGet, cacheDataHas } from './data-cache' import { updateComponent } from './lifecycle' -const privatePropValName = 'privateTriggerObserer' +const privatePropValName = 'privatetriggerobserer' const anonymousFnNamePreffix = 'funPrivate' const componentFnReg = /^__fn_/ const PRELOAD_DATA_KEY = 'preload' @@ -155,7 +155,7 @@ function bindProperties (componentConf, ComponentClass) { } componentConf.props = [] Object.keys(componentConf.properties).forEach(item => { - componentConf.props.push(item) + componentConf.props.push(item.toLocaleLowerCase()) }) componentConf.props.push(privatePropValName) componentConf.onPrivatePropChange = function () { From ff216c74ce91f7f70fa7e05fdeeb8b680aeff9d6 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Wed, 3 Apr 2019 16:38:37 +0800 Subject: [PATCH 064/103] =?UTF-8?q?fix(cli):=20=E4=BF=AE=E6=AD=A3=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E6=96=87=E4=BB=B6=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/src/mini/page.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/taro-cli/src/mini/page.ts b/packages/taro-cli/src/mini/page.ts index 1c263f960574..b77b8c27bbb1 100644 --- a/packages/taro-cli/src/mini/page.ts +++ b/packages/taro-cli/src/mini/page.ts @@ -64,7 +64,7 @@ export async function buildSinglePage (page: string) { const isQuickApp = buildAdapter === BUILD_TYPES.QUICKAPP printLog(processTypeEnum.COMPILE, '页面文件', `${sourceDirName}/${page}`) - if (!fs.existsSync(pageJs)) { + if (!fs.existsSync(pageJs) || !fs.statSync(pageJs).isFile()) { printLog(processTypeEnum.ERROR, '页面文件', `${sourceDirName}/${page} 不存在!`) return } From 354884bf48ef772aae2133ca39d77f236fd94d5d Mon Sep 17 00:00:00 2001 From: luckyadam Date: Wed, 3 Apr 2019 16:39:41 +0800 Subject: [PATCH 065/103] =?UTF-8?q?fix(quickapp):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=BF=AB=E5=BA=94=E7=94=A8=E8=B7=AF=E7=94=B1=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=20API=20url=20=E5=A4=84=E7=90=86=E9=94=99=E8=AF=AF=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-quickapp/src/api/router/index.js | 2 +- packages/taro-quickapp/src/native-api.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/taro-quickapp/src/api/router/index.js b/packages/taro-quickapp/src/api/router/index.js index 8e91e2c89139..5882a12523cf 100644 --- a/packages/taro-quickapp/src/api/router/index.js +++ b/packages/taro-quickapp/src/api/router/index.js @@ -41,7 +41,7 @@ function qappNavigate (options = {}, method = 'push') { params = getUrlParams(url) try { router[method]({ - uri: url, + uri: url.substr(0, url.lastIndexOf('/')), params }) success && success(res) diff --git a/packages/taro-quickapp/src/native-api.js b/packages/taro-quickapp/src/native-api.js index a42f35639031..8755df237740 100644 --- a/packages/taro-quickapp/src/native-api.js +++ b/packages/taro-quickapp/src/native-api.js @@ -6,6 +6,7 @@ import { } from '@tarojs/taro' import request from './api/request' import storage from './api/storage' +import router from './api/router' function processApis (taro) { const weApis = Object.assign({}, onAndSyncApis, noPromiseApis, otherApis) @@ -30,5 +31,5 @@ export default function initNativeApi (taro) { taro.canIUseWebp = canIUseWebp taro.initPxTransform = initPxTransform.bind(taro) taro.pxTransform = pxTransform.bind(taro) - Object.assign(taro, storage) + Object.assign(taro, storage, router) } From 036a67e3b9e16a45fd4c75462c11fba1f4c2445b Mon Sep 17 00:00:00 2001 From: luckyadam Date: Wed, 3 Apr 2019 16:40:47 +0800 Subject: [PATCH 066/103] =?UTF-8?q?fix(quickapp):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=BF=AB=E5=BA=94=E7=94=A8=E4=BA=8B=E4=BB=B6=20bind=20?= =?UTF-8?q?=E4=BC=A0=E5=8F=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-quickapp/src/component.js | 18 +++++++++++-- .../taro-quickapp/src/create-component.js | 25 ++++++++++++++----- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/packages/taro-quickapp/src/component.js b/packages/taro-quickapp/src/component.js index 605bc98b096e..320c9f5cc095 100644 --- a/packages/taro-quickapp/src/component.js +++ b/packages/taro-quickapp/src/component.js @@ -89,10 +89,24 @@ export default class BaseComponent { } else { // 普通的 const keyLower = key.toLocaleLowerCase() - this.$scope.triggerEvent(keyLower, { + const payload = { __isCustomEvt: true, __arguments: args - }) + } + const detail = {} + if (this.$scope._externalBinding) { + const tempalateAttr = this.$scope._externalBinding.template.attr + Object.keys(tempalateAttr).forEach(item => { + if (/^data/.test(item)) { + detail[item.replace(/^data/, '')] = tempalateAttr[item] + } + }) + } + + if (Object.keys(detail).length) { + payload.__detail = detail + } + this.$scope.$emit(keyLower.replace(/^on/, ''), payload) } } } diff --git a/packages/taro-quickapp/src/create-component.js b/packages/taro-quickapp/src/create-component.js index 3798d79a3f2b..0865f48e5238 100644 --- a/packages/taro-quickapp/src/create-component.js +++ b/packages/taro-quickapp/src/create-component.js @@ -4,7 +4,7 @@ import { updateComponent } from './lifecycle' const privatePropValName = 'privatetriggerobserer' const anonymousFnNamePreffix = 'funPrivate' -const componentFnReg = /^__fn_/ +const componentFnReg = /^prv-fn-/ const PRELOAD_DATA_KEY = 'preload' const pageExtraFns = ['onBackPress', 'onMenuPress'] @@ -20,7 +20,7 @@ function filterProps (properties, defaultProps = {}, componentProps = {}, compon newProps[propName] = componentData[propName] } if (componentFnReg.test(propName)) { - if (componentData[propName] === true) { + if (componentData && componentData[propName] === true) { const fnName = propName.replace(componentFnReg, '') newProps[fnName] = noop } @@ -59,9 +59,22 @@ function processEvent (eventHandlerName, obj) { let datasetArgs = [] let isScopeBinded = false // 解析从dataset中传过来的参数 - const dataset = event.currentTarget.dataset || {} + const currentTarget = event.currentTarget + const dataset = {} + if (currentTarget._vm) { + const tempalateAttr = currentTarget._vm._externalBinding.template.attr + Object.keys(tempalateAttr).forEach(item => { + if (/^data/.test(item)) { + dataset[item.replace(/^data/, '')] = tempalateAttr[item] + } + }) + } + const bindArgs = {} - const eventType = event.type.toLocaleLowerCase() + const eventType = `on${event.type}`.toLocaleLowerCase() + + if (event.detail && event.detail.__detail) Object.assign(dataset, event.detail.__detail) + Object.keys(dataset).forEach(key => { let keyLower = key.toLocaleLowerCase() if (/^e/.test(keyLower)) { @@ -76,8 +89,8 @@ function processEvent (eventHandlerName, obj) { } }) // 如果是通过triggerEvent触发,并且带有参数 - if (event.__arguments && event.__arguments.length > 0) { - detailArgs = event.__arguments + if (event.detail && event.detail.__arguments && event.detail.__arguments.length > 0) { + detailArgs = event.detail.__arguments } // 普通的事件(非匿名函数),会直接call if (!isAnonymousFn) { From 6e3dc86c3ecfe4e2bc81fa3b8b818509e0e60ff2 Mon Sep 17 00:00:00 2001 From: yuche Date: Tue, 2 Apr 2019 11:33:02 +0800 Subject: [PATCH 067/103] =?UTF-8?q?fix(transformer):=20=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E5=BC=8F=E7=BB=84=E4=BB=B6=E6=8F=92=E5=85=A5=20props=20?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E8=AF=AD=E5=8F=A5=E4=BD=8D=E7=BD=AE=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/functional.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/taro-transformer-wx/src/functional.ts b/packages/taro-transformer-wx/src/functional.ts index 4225ee74347b..4a2e5ca9adcd 100644 --- a/packages/taro-transformer-wx/src/functional.ts +++ b/packages/taro-transformer-wx/src/functional.ts @@ -62,9 +62,9 @@ export const functionalComponent: () => { } if (arg) { if (t.isIdentifier(arg)) { - cloneBody.body.push(buildConstVariableDeclaration(arg.name, t.memberExpression(t.thisExpression(), t.identifier('props')))) + cloneBody.body.unshift(buildConstVariableDeclaration(arg.name, t.memberExpression(t.thisExpression(), t.identifier('props')))) } else if (t.isObjectPattern(arg)) { - cloneBody.body.push( + cloneBody.body.unshift( t.variableDeclaration('const', [ t.variableDeclarator(arg, t.memberExpression(t.thisExpression(), t.identifier('props'))) ]) From c4b5e213917b9d6eef0c9b01072436c39ce2185c Mon Sep 17 00:00:00 2001 From: yuche Date: Wed, 3 Apr 2019 16:50:40 +0800 Subject: [PATCH 068/103] =?UTF-8?q?refactor(transformer):=20=E5=BF=AB?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E4=BA=8B=E4=BB=B6=20`=5F=5Ffn=5F`=20?= =?UTF-8?q?=E6=9B=B4=E5=90=8D=E4=B8=BA=20`prv-fn-`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/class.ts | 10 +++++----- packages/taro-transformer-wx/src/constant.ts | 4 ++++ packages/taro-transformer-wx/src/index.ts | 3 ++- packages/taro-transformer-wx/src/jsx.ts | 5 +++-- packages/taro-transformer-wx/src/render.ts | 7 ++++--- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/packages/taro-transformer-wx/src/class.ts b/packages/taro-transformer-wx/src/class.ts index 4ce2530865dc..1b4a1c5ac1b9 100644 --- a/packages/taro-transformer-wx/src/class.ts +++ b/packages/taro-transformer-wx/src/class.ts @@ -13,7 +13,7 @@ import { incrementId, isContainStopPropagation } from './utils' -import { DEFAULT_Component_SET, COMPONENTS_PACKAGE_NAME, DEFAULT_Component_SET_COPY } from './constant' +import { DEFAULT_Component_SET, COMPONENTS_PACKAGE_NAME, DEFAULT_Component_SET_COPY, FN_PREFIX } from './constant' import { kebabCase, uniqueId, get as safeGet, set as safeSet } from 'lodash' import { RenderParser } from './render' import { findJSXAttrByName } from './jsx' @@ -602,10 +602,10 @@ class Transformer { const property = callee.property if (t.isIdentifier(property)) { if (property.name.startsWith('on')) { - self.componentProperies.add(`__fn_${property.name}`) + self.componentProperies.add(`${FN_PREFIX}${property.name}`) processThisPropsFnMemberProperties(callee, path, node.arguments, false) } else if (property.name === 'call' || property.name === 'apply') { - self.componentProperies.add(`__fn_${property.name}`) + self.componentProperies.add(`${FN_PREFIX}${property.name}`) processThisPropsFnMemberProperties(callee.object, path, node.arguments, true) } } @@ -635,10 +635,10 @@ class Transformer { } const attrName = attr.node.name if (t.isJSXIdentifier(attrName) && attrName.name.startsWith('on')) { - this.componentProperies.add(`__fn_${attrName.name}`) + this.componentProperies.add(`${FN_PREFIX}${attrName.name}`) } if (methodName.startsWith('on')) { - this.componentProperies.add(`__fn_${methodName}`) + this.componentProperies.add(`${FN_PREFIX}${methodName}`) } const method = t.classMethod('method', t.identifier(funcName), [], t.blockStatement([ t.expressionStatement(t.callExpression( diff --git a/packages/taro-transformer-wx/src/constant.ts b/packages/taro-transformer-wx/src/constant.ts index 7bc2223a3901..164141ec9b4e 100644 --- a/packages/taro-transformer-wx/src/constant.ts +++ b/packages/taro-transformer-wx/src/constant.ts @@ -122,6 +122,10 @@ TRANSFORM_COMPONENT_PROPS.set(Adapters.alipay, { export const lessThanSignPlacehold = '__LESS_THAN_SIGN_PLACEHOLDER__' +export let FN_PREFIX = '__fn_' + +export const setFnPrefix = (s: string) => FN_PREFIX = s + export const quickappComponentName = new Set([ 'Swiper', 'Image', diff --git a/packages/taro-transformer-wx/src/index.ts b/packages/taro-transformer-wx/src/index.ts index 095c1d38bc0b..fdf1636a0b94 100644 --- a/packages/taro-transformer-wx/src/index.ts +++ b/packages/taro-transformer-wx/src/index.ts @@ -14,7 +14,7 @@ import { getSuperClassCode } from './utils' import * as t from 'babel-types' -import { DEFAULT_Component_SET, INTERNAL_SAFE_GET, TARO_PACKAGE_NAME, REDUX_PACKAGE_NAME, MOBX_PACKAGE_NAME, IMAGE_COMPONENTS, INTERNAL_INLINE_STYLE, THIRD_PARTY_COMPONENTS, INTERNAL_GET_ORIGNAL, setLoopOriginal, GEL_ELEMENT_BY_ID, lessThanSignPlacehold, COMPONENTS_PACKAGE_NAME, quickappComponentName } from './constant' +import { DEFAULT_Component_SET, INTERNAL_SAFE_GET, TARO_PACKAGE_NAME, REDUX_PACKAGE_NAME, MOBX_PACKAGE_NAME, IMAGE_COMPONENTS, INTERNAL_INLINE_STYLE, THIRD_PARTY_COMPONENTS, INTERNAL_GET_ORIGNAL, setLoopOriginal, GEL_ELEMENT_BY_ID, lessThanSignPlacehold, COMPONENTS_PACKAGE_NAME, quickappComponentName, setFnPrefix } from './constant' import { Adapters, setAdapter, Adapter } from './adapter' import { Options, setTransformOptions, buildBabelTransformOptions } from './options' import { get as safeGet } from 'lodash' @@ -152,6 +152,7 @@ export default function transform (options: Options): TransformResult { if (Adapter.type === Adapters.quickapp) { DEFAULT_Component_SET.clear() DEFAULT_Component_SET.add('div') + setFnPrefix('prv-fn-') } } if (Adapter.type === Adapters.swan) { diff --git a/packages/taro-transformer-wx/src/jsx.ts b/packages/taro-transformer-wx/src/jsx.ts index 67e1fdde2550..c7fa93a20df7 100644 --- a/packages/taro-transformer-wx/src/jsx.ts +++ b/packages/taro-transformer-wx/src/jsx.ts @@ -8,7 +8,8 @@ import { swanSpecialAttrs, THIRD_PARTY_COMPONENTS, TRANSFORM_COMPONENT_PROPS, - lessThanSignPlacehold + lessThanSignPlacehold, + FN_PREFIX } from './constant' import { createHTMLElement } from './create-html-element' import { codeFrameError, decodeUnicode } from './utils' @@ -257,7 +258,7 @@ export function parseJSXElement (element: t.JSXElement): string { obj['maxlength'] = value } else if ( componentSpecialProps && componentSpecialProps.has(name) || - name.startsWith('__fn_') || + name.startsWith(FN_PREFIX) || isAlipayOrQuickappEvent ) { obj[name] = value diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts index cc688b1f5b39..381ffac0bd6a 100644 --- a/packages/taro-transformer-wx/src/render.ts +++ b/packages/taro-transformer-wx/src/render.ts @@ -42,7 +42,8 @@ import { LOOP_ORIGINAL, INTERNAL_GET_ORIGNAL, GEL_ELEMENT_BY_ID, - ALIPAY_BUBBLE_EVENTS + ALIPAY_BUBBLE_EVENTS, + FN_PREFIX } from './constant' import { Adapter, Adapters } from './adapter' import { transformOptions, buildBabelTransformOptions } from './options' @@ -892,7 +893,7 @@ export class RenderParser { if (t.isJSXIdentifier(componentName) && !DEFAULT_Component_SET.has(componentName.name)) { const element = path.parent as t.JSXOpeningElement if (process.env.NODE_ENV !== 'test' && Adapter.type !== Adapters.alipay) { - const fnName = `__fn_${name.name}` + const fnName = `${FN_PREFIX}${name.name}` element.attributes = element.attributes.concat([t.jSXAttribute(t.jSXIdentifier(fnName))]) } } @@ -1592,7 +1593,7 @@ export class RenderParser { const componentProperies = cloneDeep(this.componentProperies) componentProperies.forEach(s => { - if (s.startsWith('__fn_')) { + if (s.startsWith(FN_PREFIX)) { const eventName = s.slice(5) if (componentProperies.has(eventName)) { componentProperies.delete(s) From 18e2ed6f6c6389cd4aceb72a091d3ad71a8590df Mon Sep 17 00:00:00 2001 From: luckyadam Date: Tue, 9 Apr 2019 16:35:01 +0800 Subject: [PATCH 069/103] =?UTF-8?q?feat(taro-quickapp):=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E9=A1=B6=E9=83=A8=E5=AF=BC=E8=88=AA=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../taro-quickapp/src/api/navigation/index.js | 23 +++++++++++++++++++ packages/taro-quickapp/src/native-api.js | 3 ++- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 packages/taro-quickapp/src/api/navigation/index.js diff --git a/packages/taro-quickapp/src/api/navigation/index.js b/packages/taro-quickapp/src/api/navigation/index.js new file mode 100644 index 000000000000..7b1ad7f77296 --- /dev/null +++ b/packages/taro-quickapp/src/api/navigation/index.js @@ -0,0 +1,23 @@ +import { + eventCenter +} from '@tarojs/taro' + +function setNavigationBar (params) { + eventCenter.trigger('TaroEvent:setNavigationBar', params) + if (params.success) { + params.success() + } +} + +export function setNavigationBarTitle (params) { + setNavigationBar(params) +} + +export function setNavigationBarColor (params) { + setNavigationBar(params) +} + +export default { + setNavigationBarTitle, + setNavigationBarColor +} diff --git a/packages/taro-quickapp/src/native-api.js b/packages/taro-quickapp/src/native-api.js index 8755df237740..f8be87fee404 100644 --- a/packages/taro-quickapp/src/native-api.js +++ b/packages/taro-quickapp/src/native-api.js @@ -7,6 +7,7 @@ import { import request from './api/request' import storage from './api/storage' import router from './api/router' +import navigation from './api/navigation' function processApis (taro) { const weApis = Object.assign({}, onAndSyncApis, noPromiseApis, otherApis) @@ -31,5 +32,5 @@ export default function initNativeApi (taro) { taro.canIUseWebp = canIUseWebp taro.initPxTransform = initPxTransform.bind(taro) taro.pxTransform = pxTransform.bind(taro) - Object.assign(taro, storage, router) + Object.assign(taro, storage, router, navigation) } From 89879b6c79d52f2c8708085f0d1d9390c5caca5e Mon Sep 17 00:00:00 2001 From: luckyadam Date: Tue, 9 Apr 2019 16:36:44 +0800 Subject: [PATCH 070/103] =?UTF-8?q?feat(cli):=20=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E6=97=B6=E6=B3=A8=E5=85=A5=E5=BF=AB=E5=BA=94=E7=94=A8=E9=A1=B6?= =?UTF-8?q?=E9=83=A8=E5=AF=BC=E8=88=AA=E7=9B=B8=E5=85=B3=E8=B0=83=E7=94=A8?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BB=A5=E9=85=8D=E5=90=88=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E6=97=B6=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/src/mini/astProcess.ts | 115 +++++++++++++++++++---- packages/taro-cli/src/util/astConvert.ts | 6 -- 2 files changed, 97 insertions(+), 24 deletions(-) diff --git a/packages/taro-cli/src/mini/astProcess.ts b/packages/taro-cli/src/mini/astProcess.ts index d3637d62de1a..7d9de2de4935 100644 --- a/packages/taro-cli/src/mini/astProcess.ts +++ b/packages/taro-cli/src/mini/astProcess.ts @@ -38,7 +38,11 @@ import { traverseObjectNode, isQuickAppPkg } from '../util' -import { convertObjectToAstExpression, convertArrayToAstExpression } from '../util/astConvert' +import { + convertObjectToAstExpression, + convertArrayToAstExpression, + convertSourceStringToAstExpression +} from '../util/astConvert' import babylonConfig from '../config/babylon' import { getExactedNpmFilePath, getNotExistNpmList } from '../util/npmExact' @@ -231,6 +235,9 @@ export function parseAst ( let exportTaroReduxConnected: string | null = null const isQuickApp = buildAdapter === BUILD_TYPES.QUICKAPP const cannotRemoves = [taroJsFramework, 'react', 'nervjs'] + let hasComponentDidHide + let hasComponentDidShow + let hasComponentWillMount if (isQuickApp) { cannotRemoves.push(taroJsComponents) } @@ -350,10 +357,31 @@ export function parseAst ( } }, + ClassMethod (astPath) { + const keyName = (astPath.get('key').node as t.Identifier).name + if (keyName === 'componentWillMount') { + hasComponentWillMount = true + } else if (keyName === 'componentDidShow') { + hasComponentDidShow = true + } else if (keyName === 'componentDidHide') { + hasComponentDidHide = true + } + }, + ClassProperty (astPath) { const node = astPath.node - if (node.key.name === 'config') { + const keyName = node.key.name + const valuePath = astPath.get('value') + if (keyName === 'config') { configObj = traverseObjectNode(node, buildAdapter) + } else if (valuePath.isFunctionExpression() || valuePath.isArrowFunctionExpression()) { + if (keyName === 'componentWillMount') { + hasComponentWillMount = true + } else if (keyName === 'componentDidShow') { + hasComponentDidShow = true + } else if (keyName === 'componentDidHide') { + hasComponentDidHide = true + } } }, @@ -482,18 +510,16 @@ export function parseAst ( } if (isNpmPkg(value) && !isQuickAppPkg(value) && !notExistNpmList.has(value)) { if (value === taroJsComponents) { - if (buildAdapter === BUILD_TYPES.QUICKAPP) { - if (isQuickApp) { - if (parentNode.declarations.length === 1 && parentNode.declarations[0].init) { - const id = parentNode.declarations[0].id - if (id.type === 'ObjectPattern') { - const properties = id.properties as any - properties.forEach(p => { - if (p.type === 'ObjectProperty' && p.value.type === 'Identifier') { - taroSelfComponents.add(_.kebabCase(p.value.name)) - } - }) - } + if (isQuickApp) { + if (parentNode.declarations.length === 1 && parentNode.declarations[0].init) { + const id = parentNode.declarations[0].id + if (id.type === 'ObjectPattern') { + const properties = id.properties as any + properties.forEach(p => { + if (p.type === 'ObjectProperty' && p.value.type === 'Identifier') { + taroSelfComponents.add(_.kebabCase(p.value.name)) + } + }) } } } @@ -643,6 +669,59 @@ export function parseAst ( Program: { exit (astPath) { astPath.traverse({ + ClassBody (astPath) { + if (isQuickApp) { + const node = astPath.node + if (!hasComponentWillMount) { + node.body.push(t.classMethod( + 'method', t.identifier('hasComponentWillMount'), [], + t.blockStatement([]), false, false)) + } + if (!hasComponentDidShow) { + node.body.push(t.classMethod( + 'method', t.identifier('componentDidShow'), [], + t.blockStatement([]), false, false)) + } + if (!hasComponentDidHide) { + node.body.push(t.classMethod( + 'method', t.identifier('componentDidHide'), [], + t.blockStatement([]), false, false)) + } + node.body.push(t.classMethod( + 'method', t.identifier('__listenToSetNavigationBarEvent'), [], + t.blockStatement([convertSourceStringToAstExpression( + `if (!Taro.eventCenter.callbacks['TaroEvent:setNavigationBar']) { + Taro.eventCenter.on('TaroEvent:setNavigationBar', params => { + if (params.title) { + this.$scope.$page.setTitleBar({ text: params.title }) + } + if (params.frontColor) { + this.$scope.$page.setTitleBar({ textColor: params.frontColor }) + } + if (params.backgroundColor) { + this.$scope.$page.setTitleBar({ backgroundColor: params.backgroundColor }) + } + }) + }` + )]), false, false)) + node.body.push(t.classMethod( + 'method', t.identifier('__offListenToSetNavigationBarEvent'), [], + t.blockStatement([convertSourceStringToAstExpression( + `Taro.eventCenter.off('TaroEvent:setNavigationBar')` + )]), false, false)) + } + }, + ClassMethod (astPath) { + if (isQuickApp) { + const node = astPath.node + const keyName = (node.key as t.Identifier).name + if (keyName === 'componentDidShow' || keyName === 'componentWillMount') { + node.body.body.unshift(convertSourceStringToAstExpression(`this.__listenToSetNavigationBarEvent()`)) + } else if (keyName === 'componentDidHide') { + node.body.body.unshift(convertSourceStringToAstExpression(`this.__offListenToSetNavigationBarEvent()`)) + } + } + }, ImportDeclaration (astPath) { const node = astPath.node const source = node.source @@ -752,7 +831,7 @@ export function parseAst ( }) const node = astPath.node as t.Program const exportVariableName = exportTaroReduxConnected || componentClassName - if (needExportDefault && buildAdapter !== BUILD_TYPES.QUICKAPP) { + if (needExportDefault && !isQuickApp) { const exportDefault = template(`export default ${exportVariableName}`, babylonConfig as any)() node.body.push(exportDefault as any) } @@ -773,7 +852,7 @@ export function parseAst ( if (projectConfig.hasOwnProperty(DEVICE_RATIO_NAME)) { pxTransformConfig[DEVICE_RATIO_NAME] = projectConfig.deviceRatio } - if (buildAdapter === BUILD_TYPES.QUICKAPP) { + if (isQuickApp) { node.body.push(template(`export default require('${taroMiniAppFrameworkPath}').default.createApp(${exportVariableName})`, babylonConfig as any)() as any) } else { node.body.push(template(`App(require('${taroMiniAppFrameworkPath}').default.createApp(${exportVariableName}))`, babylonConfig as any)() as any) @@ -783,14 +862,14 @@ export function parseAst ( case PARSE_AST_TYPE.PAGE: if (buildAdapter === BUILD_TYPES.WEAPP) { node.body.push(template(`Component(require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}, true))`, babylonConfig as any)() as any) - } else if (buildAdapter === BUILD_TYPES.QUICKAPP) { + } else if (isQuickApp) { node.body.push(template(`export default require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}, true)`, babylonConfig as any)() as any) } else { node.body.push(template(`Page(require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}, true))`, babylonConfig as any)() as any) } break case PARSE_AST_TYPE.COMPONENT: - if (buildAdapter === BUILD_TYPES.QUICKAPP) { + if (isQuickApp) { node.body.push(template(`export default require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName})`, babylonConfig as any)() as any) } else { node.body.push(template(`Component(require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}))`, babylonConfig as any)() as any) diff --git a/packages/taro-cli/src/util/astConvert.ts b/packages/taro-cli/src/util/astConvert.ts index 554ec26e5f9f..5c9f253f680c 100644 --- a/packages/taro-cli/src/util/astConvert.ts +++ b/packages/taro-cli/src/util/astConvert.ts @@ -69,9 +69,3 @@ export const getObjKey = (node) => { return node.value } } - -// exports.obj = convertObjectToAstExpression -// exports.array = convertArrayToAstExpression -// exports.source = convertSourceStringToAstExpression -// exports.getObjKey = getObjKey -// exports.generateMinimalEscapeCode = generateMinimalEscapeCode From c31163793803df32cdec3bc5e83b78c872b413e5 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Tue, 9 Apr 2019 16:39:20 +0800 Subject: [PATCH 071/103] =?UTF-8?q?feat(components-qa):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=BF=AB=E5=BA=94=E7=94=A8=20text=20=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E6=96=87=E5=AD=97=E4=B8=8D=E6=98=BE=E7=A4=BA=E7=9A=84?= =?UTF-8?q?=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-components-qa/src/components/taro-text/index.ux | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/taro-components-qa/src/components/taro-text/index.ux b/packages/taro-components-qa/src/components/taro-text/index.ux index d0eba4ddf688..a97118c4e766 100644 --- a/packages/taro-components-qa/src/components/taro-text/index.ux +++ b/packages/taro-components-qa/src/components/taro-text/index.ux @@ -1,12 +1,12 @@ From ff5ed9929fdb43319f0deaa3ff1491d451570e99 Mon Sep 17 00:00:00 2001 From: yuche Date: Tue, 16 Apr 2019 14:21:27 +0800 Subject: [PATCH 086/103] =?UTF-8?q?fix(transformer):=20=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E8=B0=83=E7=94=A8=20transformer=20=E5=87=BD=E6=95=B0=E5=87=BA?= =?UTF-8?q?=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/taro-transformer-wx/src/index.ts b/packages/taro-transformer-wx/src/index.ts index 311a8baf47b5..3f354563123c 100644 --- a/packages/taro-transformer-wx/src/index.ts +++ b/packages/taro-transformer-wx/src/index.ts @@ -158,8 +158,8 @@ export default function transform (options: Options): TransformResult { } if (Adapter.type === Adapters.swan || Adapter.type === Adapters.quickapp) { setLoopOriginal('privateOriginal') - setLoopCallee(LOOP_CALLEE.slice(1)) - setLoopState(LOOP_STATE.slice(1)) + setLoopCallee('anonymousCallee_') + setLoopState('loopState') } THIRD_PARTY_COMPONENTS.clear() const code = options.isTyped From 55670c9def4a9e5154c8dd49b127ac26358e7f2a Mon Sep 17 00:00:00 2001 From: yuche Date: Tue, 16 Apr 2019 15:07:54 +0800 Subject: [PATCH 087/103] =?UTF-8?q?chore(transformer):=20=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E6=9C=AA=E4=BD=BF=E7=94=A8=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/taro-transformer-wx/src/index.ts b/packages/taro-transformer-wx/src/index.ts index 3f354563123c..9c5b9583fa33 100644 --- a/packages/taro-transformer-wx/src/index.ts +++ b/packages/taro-transformer-wx/src/index.ts @@ -14,7 +14,7 @@ import { getSuperClassCode } from './utils' import * as t from 'babel-types' -import { DEFAULT_Component_SET, INTERNAL_SAFE_GET, TARO_PACKAGE_NAME, REDUX_PACKAGE_NAME, MOBX_PACKAGE_NAME, IMAGE_COMPONENTS, INTERNAL_INLINE_STYLE, THIRD_PARTY_COMPONENTS, INTERNAL_GET_ORIGNAL, setLoopOriginal, GEL_ELEMENT_BY_ID, lessThanSignPlacehold, COMPONENTS_PACKAGE_NAME, quickappComponentName, setFnPrefix, setLoopCallee, LOOP_CALLEE, setLoopState, LOOP_STATE } from './constant' +import { DEFAULT_Component_SET, INTERNAL_SAFE_GET, TARO_PACKAGE_NAME, REDUX_PACKAGE_NAME, MOBX_PACKAGE_NAME, IMAGE_COMPONENTS, INTERNAL_INLINE_STYLE, THIRD_PARTY_COMPONENTS, INTERNAL_GET_ORIGNAL, setLoopOriginal, GEL_ELEMENT_BY_ID, lessThanSignPlacehold, COMPONENTS_PACKAGE_NAME, quickappComponentName, setFnPrefix, setLoopCallee, setLoopState } from './constant' import { Adapters, setAdapter, Adapter } from './adapter' import { Options, setTransformOptions, buildBabelTransformOptions } from './options' import { get as safeGet } from 'lodash' From 5f63f6516e2e4421bd1be13366a8b1f59f631498 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Tue, 16 Apr 2019 16:45:47 +0800 Subject: [PATCH 088/103] =?UTF-8?q?fix(cli):=20=E7=BC=96=E8=AF=91=E6=97=B6?= =?UTF-8?q?=E6=8F=90=E5=89=8D=E5=8A=A0=E5=85=A5=E7=8E=AF=E5=A2=83=E5=8F=98?= =?UTF-8?q?=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/bin/taro-build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/taro-cli/bin/taro-build b/packages/taro-cli/bin/taro-build index 536eeb13d184..ac6dfc92fbc5 100755 --- a/packages/taro-cli/bin/taro-build +++ b/packages/taro-cli/bin/taro-build @@ -47,6 +47,8 @@ if (env) { } } +process.env.TARO_ENV = type + const projectConf = require(projectConfPath)(_.merge) console.log(chalk.green(`开始编译项目 ${chalk.bold(projectConf.projectName)}`)) From b2c6d0c9204864bc03d9b58187d25338968686f1 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Tue, 16 Apr 2019 16:46:18 +0800 Subject: [PATCH 089/103] =?UTF-8?q?fix(taro-qucikapp):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E4=BA=8B=E4=BB=B6=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../taro-quickapp/src/create-component.js | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/taro-quickapp/src/create-component.js b/packages/taro-quickapp/src/create-component.js index 0865f48e5238..9cccbe240f91 100644 --- a/packages/taro-quickapp/src/create-component.js +++ b/packages/taro-quickapp/src/create-component.js @@ -42,13 +42,28 @@ function processEvent (eventHandlerName, obj) { obj[eventHandlerName] = function (event) { if (event) { - event.preventDefault = function () {} - event.stopPropagation = function () {} - event.currentTarget = event.currentTarget || event.target || {} - if (event.target) { - Object.assign(event.target, event.detail) - } - Object.assign(event.currentTarget, event.detail) + const currentTarget = event.currentTarget + const target = event.target + Object.defineProperties(event, { + target: { + configurable: true, + get () { + return Object.assign(target || {}, event.detail) + } + }, + currentTarget: { + configurable: true, + get () { + return Object.assign(currentTarget || target || {}, event.detail) + } + }, + stopPropagation: { + value: () => {} + }, + preventDefault: { + value: () => {} + } + }) } const scope = this.$component From 928e6dbcb6da1f3a3cf13670e319833b355d17ac Mon Sep 17 00:00:00 2001 From: luckyadam Date: Tue, 16 Apr 2019 16:46:53 +0800 Subject: [PATCH 090/103] =?UTF-8?q?fix(components-qa):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E9=A1=B5=E9=9D=A2=E5=AE=B9=E5=99=A8=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-components-qa/src/components/taro-page/index.ux | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/taro-components-qa/src/components/taro-page/index.ux b/packages/taro-components-qa/src/components/taro-page/index.ux index 8c331494f087..30ab0aacb008 100644 --- a/packages/taro-components-qa/src/components/taro-page/index.ux +++ b/packages/taro-components-qa/src/components/taro-page/index.ux @@ -59,7 +59,7 @@ tabBar: { type: Object, required: false, - default: {} + default: null }, pagePath: { type: String, From a1bbb00d20ea719f7173d00fb26c508d0b27cc51 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Tue, 16 Apr 2019 22:55:08 +0800 Subject: [PATCH 091/103] =?UTF-8?q?fix(taro-quickapp):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E4=BA=8B=E4=BB=B6=E4=BC=A0=E5=8F=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-quickapp/src/create-component.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/taro-quickapp/src/create-component.js b/packages/taro-quickapp/src/create-component.js index 9cccbe240f91..80bb8c9d4b05 100644 --- a/packages/taro-quickapp/src/create-component.js +++ b/packages/taro-quickapp/src/create-component.js @@ -74,13 +74,15 @@ function processEvent (eventHandlerName, obj) { let datasetArgs = [] let isScopeBinded = false // 解析从dataset中传过来的参数 - const currentTarget = event.currentTarget const dataset = {} - if (currentTarget._vm) { - const tempalateAttr = currentTarget._vm._externalBinding.template.attr - Object.keys(tempalateAttr).forEach(item => { - if (/^data/.test(item)) { - dataset[item.replace(/^data/, '')] = tempalateAttr[item] + const currentTarget = event.currentTarget + const vm = currentTarget._vm || (currentTarget._target ? currentTarget._target._vm : null) + if (vm) { + const tempalateAttr = vm._externalBinding.template.attr + Object.keys(tempalateAttr).forEach(key => { + if (/^data/.test(key)) { + const item = tempalateAttr[key] + dataset[key.replace(/^data/, '')] = typeof item === 'function' ? item() : item } }) } From b37a025467f3d2b69819632f330b32a878289984 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Tue, 16 Apr 2019 22:55:41 +0800 Subject: [PATCH 092/103] =?UTF-8?q?fix(cli):=20=E5=BF=AB=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E9=9D=99=E6=80=81=E8=B5=84=E6=BA=90=20copy=20=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/src/mini/helper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/taro-cli/src/mini/helper.ts b/packages/taro-cli/src/mini/helper.ts index 8f09d64d6afa..264f6b5c4c08 100644 --- a/packages/taro-cli/src/mini/helper.ts +++ b/packages/taro-cli/src/mini/helper.ts @@ -308,7 +308,7 @@ export function initCopyFiles () { } export function copyFilesFromSrcToOutput (files: string[]) { - const { nodeModulesPath, npmOutputDir } = BuildData + const { nodeModulesPath, npmOutputDir, outputDir } = BuildData files.forEach(file => { let outputFilePath if (NODE_MODULES_REG.test(file)) { From 97c457559e8852ce52857f6ab67c2a7466634129 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Wed, 17 Apr 2019 15:11:07 +0800 Subject: [PATCH 093/103] =?UTF-8?q?fix(components-qa):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20button=20=E7=BB=84=E4=BB=B6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/{button => taro-button}/img.js | 0 .../components/{button => taro-button}/index.ux | 15 +++++---------- 2 files changed, 5 insertions(+), 10 deletions(-) rename packages/taro-components-qa/src/components/{button => taro-button}/img.js (100%) rename packages/taro-components-qa/src/components/{button => taro-button}/index.ux (90%) diff --git a/packages/taro-components-qa/src/components/button/img.js b/packages/taro-components-qa/src/components/taro-button/img.js similarity index 100% rename from packages/taro-components-qa/src/components/button/img.js rename to packages/taro-components-qa/src/components/taro-button/img.js diff --git a/packages/taro-components-qa/src/components/button/index.ux b/packages/taro-components-qa/src/components/taro-button/index.ux similarity index 90% rename from packages/taro-components-qa/src/components/button/index.ux rename to packages/taro-components-qa/src/components/taro-button/index.ux index 0cf11a7b4ad8..8b8602d36340 100644 --- a/packages/taro-components-qa/src/components/button/index.ux +++ b/packages/taro-components-qa/src/components/taro-button/index.ux @@ -3,17 +3,16 @@ class="{{btnClass}}" style="{{btnStyle}}" id="{{id}}" - onclick="handleClick" disabled="{{disabled}}" > - + From 16726b5f8f5eee5eda30900aaf6281966e968c59 Mon Sep 17 00:00:00 2001 From: yuche Date: Wed, 17 Apr 2019 17:36:11 +0800 Subject: [PATCH 094/103] =?UTF-8?q?feat(transformer):=20=E5=BF=AB=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E6=96=B0=E5=A2=9E=E5=8F=82=E6=95=B0:=20rootProps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/options.ts | 3 ++- packages/taro-transformer-wx/src/render.ts | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/taro-transformer-wx/src/options.ts b/packages/taro-transformer-wx/src/options.ts index 729b812c0484..6ead7941108e 100644 --- a/packages/taro-transformer-wx/src/options.ts +++ b/packages/taro-transformer-wx/src/options.ts @@ -12,7 +12,8 @@ export interface Options { isTyped: boolean, isNormal?: boolean, env?: object, - adapter?: Adapters + adapter?: Adapters, + rootProps?: object } export const transformOptions: Options = {} as any diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts index 54dc598dc33c..6f151b2a73e4 100644 --- a/packages/taro-transformer-wx/src/render.ts +++ b/packages/taro-transformer-wx/src/render.ts @@ -1501,6 +1501,20 @@ export class RenderParser { } setOutputTemplate () { + if (Adapter.type === Adapters.quickapp && transformOptions.rootProps && transformOptions.isRoot) { + const attrs: t.JSXAttribute[] = [] + for (const key in transformOptions.rootProps) { + if (transformOptions.rootProps.hasOwnProperty(key)) { + const value = transformOptions.rootProps[key] + const keyName = key + '__temp' + const decl = buildConstVariableDeclaration(keyName, t.identifier(JSON.stringify(value))) + this.referencedIdentifiers.add(t.identifier(keyName)) + this.renderPath.node.body.body.push(decl) + attrs.push(t.jSXAttribute(t.jSXIdentifier(key), t.jSXExpressionContainer(t.identifier(keyName)))) + } + } + this.finalReturnElement.openingElement.attributes.push(...attrs) + } this.outputTemplate = parseJSXElement(this.finalReturnElement, true) if (!this.isDefaultRender) { this.outputTemplate = `` From 8a096cd7c1974744d2d0d68215c5791b48eeaf96 Mon Sep 17 00:00:00 2001 From: yuche Date: Wed, 17 Apr 2019 17:51:01 +0800 Subject: [PATCH 095/103] =?UTF-8?q?fix(transformer):=20=E5=BF=AB=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E7=94=9F=E6=88=90=E5=87=BD=E6=95=B0=E5=8C=BF=E5=90=8D?= =?UTF-8?q?=20state=20=E4=B9=9F=E4=B8=8D=E8=83=BD=E4=BB=A5=20=5F$=20?= =?UTF-8?q?=E5=BC=80=E5=A4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-transformer-wx/src/utils.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/taro-transformer-wx/src/utils.ts b/packages/taro-transformer-wx/src/utils.ts index 0546de99168d..1a864f727168 100644 --- a/packages/taro-transformer-wx/src/utils.ts +++ b/packages/taro-transformer-wx/src/utils.ts @@ -7,7 +7,7 @@ import { cloneDeep } from 'lodash' import * as fs from 'fs' import * as path from 'path' import { buildBlockElement } from './jsx' -import { Adapter } from './adapter' +import { Adapter, Adapters } from './adapter' import { transformOptions } from './options' const template = require('babel-template') @@ -224,6 +224,11 @@ export function generateAnonymousState ( } }) variableName = newId.name + if (Adapter.type === Adapters.quickapp && variableName.startsWith('_$')) { + const newVarName = variableName.slice(2) + scope.rename(variableName, newVarName) + variableName = newVarName + } refIds.add(t.identifier(variableName)) blockStatement.scope.rename(id.name, newId.name) p.parentPath.replaceWith( From 3464096bc212b3e950929c6137b31620ec6b12dd Mon Sep 17 00:00:00 2001 From: chenjiajian <798095202@qq.com> Date: Wed, 17 Apr 2019 17:56:32 +0800 Subject: [PATCH 096/103] =?UTF-8?q?feat(taro-qq):=20=E5=A2=9E=E5=8A=A0=20Q?= =?UTF-8?q?Q=20=E8=BD=BB=E5=BA=94=E7=94=A8=E7=AB=AF=E9=80=82=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/bin/taro-build | 2 +- packages/taro-cli/src/build.ts | 10 + packages/taro-cli/src/mini/astProcess.ts | 2 +- packages/taro-cli/src/mini/index.ts | 2 +- packages/taro-cli/src/util/constants.ts | 30 +- packages/taro-qq/README.md | 2 + packages/taro-qq/index.js | 2 + packages/taro-qq/package.json | 32 ++ packages/taro-qq/rollup.config.js | 74 ++++ packages/taro-qq/src/component.js | 134 ++++++ packages/taro-qq/src/create-app.js | 45 ++ packages/taro-qq/src/create-component.js | 428 ++++++++++++++++++++ packages/taro-qq/src/current-owner.js | 4 + packages/taro-qq/src/data-cache.js | 15 + packages/taro-qq/src/hooks.js | 166 ++++++++ packages/taro-qq/src/index.js | 44 ++ packages/taro-qq/src/lifecycle.js | 150 +++++++ packages/taro-qq/src/native-api.js | 205 ++++++++++ packages/taro-qq/src/next-tick.js | 7 + packages/taro-qq/src/pure-component.js | 13 + packages/taro-qq/src/render-queue.js | 23 ++ packages/taro-qq/src/util.js | 260 ++++++++++++ packages/taro-transformer-wx/src/adapter.ts | 17 +- packages/taro/src/env.js | 6 +- 24 files changed, 1663 insertions(+), 10 deletions(-) create mode 100644 packages/taro-qq/README.md create mode 100644 packages/taro-qq/index.js create mode 100644 packages/taro-qq/package.json create mode 100644 packages/taro-qq/rollup.config.js create mode 100644 packages/taro-qq/src/component.js create mode 100644 packages/taro-qq/src/create-app.js create mode 100644 packages/taro-qq/src/create-component.js create mode 100644 packages/taro-qq/src/current-owner.js create mode 100644 packages/taro-qq/src/data-cache.js create mode 100644 packages/taro-qq/src/hooks.js create mode 100644 packages/taro-qq/src/index.js create mode 100644 packages/taro-qq/src/lifecycle.js create mode 100644 packages/taro-qq/src/native-api.js create mode 100644 packages/taro-qq/src/next-tick.js create mode 100644 packages/taro-qq/src/pure-component.js create mode 100644 packages/taro-qq/src/render-queue.js create mode 100644 packages/taro-qq/src/util.js diff --git a/packages/taro-cli/bin/taro-build b/packages/taro-cli/bin/taro-build index ac6dfc92fbc5..4c32b70545b4 100755 --- a/packages/taro-cli/bin/taro-build +++ b/packages/taro-cli/bin/taro-build @@ -10,7 +10,7 @@ const { PROJECT_CONFIG } = require('../dist/util/constants') const projectConfPath = path.join(process.cwd(), PROJECT_CONFIG) program - .option('--type [typeName]', 'Build type, weapp/swan/alipay/tt/h5/quickapp/rn') + .option('--type [typeName]', 'Build type, weapp/swan/alipay/tt/h5/quickapp/rn/qq') .option('--watch', 'Watch mode') .option('--env [env]', 'Env type') .option('--ui', 'Build Taro UI library') diff --git a/packages/taro-cli/src/build.ts b/packages/taro-cli/src/build.ts index 3bf560399215..d691eed34e16 100644 --- a/packages/taro-cli/src/build.ts +++ b/packages/taro-cli/src/build.ts @@ -41,6 +41,9 @@ export default function build (args, buildConfig: IBuildConfig) { case BUILD_TYPES.QUICKAPP: buildForQuickApp({ watch, port }) break + case BUILD_TYPES.QQ: + buildForQQ({ watch }) + break case BUILD_TYPES.UI: buildForUILibrary({ watch }) break @@ -93,6 +96,13 @@ function buildForQuickApp ({ watch, port }: IBuildConfig) { }) } +function buildForQQ ({ watch }: IBuildConfig) { + require('./mini').build({ + watch, + adapter: BUILD_TYPES.QQ + }) +} + function buildForUILibrary ({ watch }: IBuildConfig) { require('./ui').build({ watch }) } diff --git a/packages/taro-cli/src/mini/astProcess.ts b/packages/taro-cli/src/mini/astProcess.ts index e44327833564..3fa65cae8902 100644 --- a/packages/taro-cli/src/mini/astProcess.ts +++ b/packages/taro-cli/src/mini/astProcess.ts @@ -871,7 +871,7 @@ export function parseAst ( node.body.push(template(`Taro.initPxTransform(${JSON.stringify(pxTransformConfig)})`, babylonConfig as any)() as any) break case PARSE_AST_TYPE.PAGE: - if (buildAdapter === BUILD_TYPES.WEAPP) { + if (buildAdapter === BUILD_TYPES.WEAPP || buildAdapter === BUILD_TYPES.QQ) { node.body.push(template(`Component(require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}, true))`, babylonConfig as any)() as any) } else if (isQuickApp) { node.body.push(template(`export default require('${taroMiniAppFrameworkPath}').default.createComponent(${exportVariableName}, true)`, babylonConfig as any)() as any) diff --git a/packages/taro-cli/src/mini/index.ts b/packages/taro-cli/src/mini/index.ts index bdf35ec1d926..a51932f4c833 100644 --- a/packages/taro-cli/src/mini/index.ts +++ b/packages/taro-cli/src/mini/index.ts @@ -36,7 +36,7 @@ const appPath = process.cwd() function buildProjectConfig () { const { buildAdapter, sourceDir, outputDir, outputDirName } = getBuildData() let projectConfigFileName = `project.${buildAdapter}.json` - if (buildAdapter === BUILD_TYPES.WEAPP) { + if (buildAdapter === BUILD_TYPES.WEAPP || buildAdapter === BUILD_TYPES.QQ) { projectConfigFileName = 'project.config.json' } let projectConfigPath = path.join(appPath, projectConfigFileName) diff --git a/packages/taro-cli/src/util/constants.ts b/packages/taro-cli/src/util/constants.ts index 67f727d5c632..59a38af14f71 100644 --- a/packages/taro-cli/src/util/constants.ts +++ b/packages/taro-cli/src/util/constants.ts @@ -98,7 +98,8 @@ export const enum BUILD_TYPES { ALIPAY ='alipay', TT ='tt', UI ='ui', - QUICKAPP = 'quickapp' + QUICKAPP = 'quickapp', + QQ = 'qq' } export const enum TEMPLATE_TYPES { @@ -106,7 +107,8 @@ export const enum TEMPLATE_TYPES { SWAN = '.swan', ALIPAY = '.axml', TT = '.ttml', - QUICKAPP = '.ux' + QUICKAPP = '.ux', + QQ = '.qml' } export const enum STYLE_TYPES { @@ -114,7 +116,8 @@ export const enum STYLE_TYPES { SWAN = '.css', ALIPAY = '.acss', TT = '.ttss', - QUICKAPP = '.css' + QUICKAPP = '.css', + QQ = '.qss' } export const enum SCRIPT_TYPES { @@ -122,7 +125,8 @@ export const enum SCRIPT_TYPES { SWAN = '.js', ALIPAY = '.js', TT = '.js', - QUICKAPP = '.js' + QUICKAPP = '.js', + QQ = '.js' } export const enum CONFIG_TYPES { @@ -130,7 +134,8 @@ export const enum CONFIG_TYPES { SWAN = '.json', ALIPAY = '.json', TT = '.json', - QUICKAPP = '.json' + QUICKAPP = '.json', + QQ = '.json' } export type IMINI_APP_FILE_TYPE = { @@ -173,6 +178,12 @@ export const MINI_APP_FILES: IMINI_APP_FILES = { STYLE: STYLE_TYPES.QUICKAPP, SCRIPT: SCRIPT_TYPES.QUICKAPP, CONFIG: CONFIG_TYPES.QUICKAPP + }, + [BUILD_TYPES.QQ]: { + TEMPL: TEMPLATE_TYPES.QQ, + STYLE: STYLE_TYPES.QQ, + SCRIPT: SCRIPT_TYPES.QQ, + CONFIG: CONFIG_TYPES.QQ } } @@ -228,6 +239,15 @@ export const CONFIG_MAP = { backgroundColorBottom: false, backgroundColorTop: false, navigationStyle: false + }, + [BUILD_TYPES.QQ]: { + navigationBarTitleText: 'navigationBarTitleText', + navigationBarBackgroundColor: 'navigationBarBackgroundColor', + enablePullDownRefresh: 'enablePullDownRefresh', + list: 'list', + text: 'text', + iconPath: 'iconPath', + selectedIconPath: 'selectedIconPath' } } diff --git a/packages/taro-qq/README.md b/packages/taro-qq/README.md new file mode 100644 index 000000000000..952b4e516eea --- /dev/null +++ b/packages/taro-qq/README.md @@ -0,0 +1,2 @@ +# @tarojs/taro-qq +多端解决方案QQ轻应用端基础框架 diff --git a/packages/taro-qq/index.js b/packages/taro-qq/index.js new file mode 100644 index 000000000000..437a6d4788f4 --- /dev/null +++ b/packages/taro-qq/index.js @@ -0,0 +1,2 @@ +module.exports = require('./dist/index.js').default +module.exports.default = module.exports diff --git a/packages/taro-qq/package.json b/packages/taro-qq/package.json new file mode 100644 index 000000000000..094d4dd96917 --- /dev/null +++ b/packages/taro-qq/package.json @@ -0,0 +1,32 @@ +{ + "name": "@tarojs/taro-qq", + "version": "1.2.13", + "description": "Taro qq framework", + "main": "index.js", + "files": [ + "dist", + "src", + "index.js", + "package.json" + ], + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "rollup -c rollup.config.js", + "watch": "rollup -c rollup.config.js -w" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/NervJS/taro.git" + }, + "keywords": [ + "taro" + ], + "author": "O2Team", + "license": "MIT", + "dependencies": { + "@tarojs/taro": "1.2.13", + "@tarojs/utils": "1.2.13", + "lodash": "^4.17.10", + "prop-types": "^15.6.1" + } +} diff --git a/packages/taro-qq/rollup.config.js b/packages/taro-qq/rollup.config.js new file mode 100644 index 000000000000..4af44972956b --- /dev/null +++ b/packages/taro-qq/rollup.config.js @@ -0,0 +1,74 @@ +const { join } = require('path') +const resolve = require('rollup-plugin-node-resolve') +const babel = require('rollup-plugin-babel') +const common = require('rollup-plugin-commonjs') +const alias = require('rollup-plugin-alias') +const cwd = __dirname + +const baseConfig = { + input: join(cwd, 'src/index.js'), + external: ['nervjs'], + output: [ + { + file: join(cwd, 'dist/index.js'), + format: 'cjs', + sourcemap: true, + exports: 'named' + }, + { + file: join(cwd, 'dist/taro-weapp.js'), + format: 'umd', + name: 'TaroWeapp', + sourcemap: true, + exports: 'named' + } + ], + plugins: [ + alias({ + '@tarojs/taro': join(cwd, '../taro/src/index'), + '@tarojs/utils': join(cwd, '../taro-utils/dist/index') + }), + resolve({ + preferBuiltins: false + }), + + common({ + include: 'node_modules/**' + }), + babel({ + babelrc: false, + presets: [ + ['@babel/preset-env', { + modules: false + }] + ], + plugins: [ + '@babel/plugin-proposal-class-properties', + '@babel/plugin-proposal-object-rest-spread', + ['@babel/plugin-transform-react-jsx', { + 'pragma': 'Nerv.createElement' + }] + ] + }) + ] +} +const esmConfig = Object.assign({}, baseConfig, { + output: Object.assign({}, baseConfig.output, { + sourcemap: true, + format: 'es', + file: join(cwd, 'dist/index.esm.js') + }) +}) + +function rollup () { + const target = process.env.TARGET + + if (target === 'umd') { + return baseConfig + } else if (target === 'esm') { + return esmConfig + } else { + return [baseConfig, esmConfig] + } +} +module.exports = rollup() diff --git a/packages/taro-qq/src/component.js b/packages/taro-qq/src/component.js new file mode 100644 index 000000000000..bb18d600792d --- /dev/null +++ b/packages/taro-qq/src/component.js @@ -0,0 +1,134 @@ +import { enqueueRender } from './render-queue' +import { updateComponent } from './lifecycle' +import { isFunction } from './util' +import { + internal_safe_get as safeGet +} from '@tarojs/taro' +import { cacheDataSet, cacheDataGet } from './data-cache' +// #组件state对应小程序组件data +// #私有的__componentProps更新用于触发子组件中对应obsever,生命周期componentWillReceiveProps,componentShouldUpdate在这里处理 +// #父组件传过来的props放到data.__props中供模板使用,这么做的目的是模拟receiveProps生命周期 +// 执行顺序:组件setState -> 组件_createData() -> 对应的小程序组件setData(组件更新)-> 子组件的__componentProps.observer执行 +// -> 触发子组件componentWillReceiveProps,更新子组件props,componentShouldUpdate -> 子组件_createData -> 子组件setData + +const PRELOAD_DATA_KEY = 'preload' + +class BaseComponent { + // _createData的时候生成,小程序中通过data.__createData访问 + __computed = {} + // this.props,小程序中通过data.__props访问 + __props = {} + __isReady = false + // 会在componentDidMount后置为true + __mounted = false + nextProps = {} + _dirty = true + _disable = true + _isForceUpdate = false + _pendingStates = [] + _pendingCallbacks = [] + $componentType = '' + $router = { + params: {}, + path: '' + } + + _afterScheduleEffect = false + _disableEffect = false + hooks = [] + effects = [] + layoutEffects = [] + + constructor (props = {}, isPage) { + this.state = {} + this.props = props + this.$componentType = isPage ? 'PAGE' : 'COMPONENT' + this.isTaroComponent = this.$componentType && this.$router && this._pendingStates + } + _constructor (props) { + this.props = props || {} + } + _init (scope) { + this.$scope = scope + } + setState (state, callback) { + if (state) { + (this._pendingStates = this._pendingStates || []).push(state) + } + if (isFunction(callback)) { + (this._pendingCallbacks = this._pendingCallbacks || []).push(callback) + } + if (!this._disable) { + enqueueRender(this) + } + } + + getState () { + const { _pendingStates, state, props } = this + const stateClone = Object.assign({}, state) + delete stateClone.__data + if (!_pendingStates.length) { + return stateClone + } + const queue = _pendingStates.concat() + this._pendingStates.length = 0 + queue.forEach((nextState) => { + if (isFunction(nextState)) { + nextState = nextState.call(this, stateClone, props) + } + Object.assign(stateClone, nextState) + }) + return stateClone + } + + forceUpdate (callback) { + if (isFunction(callback)) { + (this._pendingCallbacks = this._pendingCallbacks || []).push(callback) + } + this._isForceUpdate = true + updateComponent(this) + } + + $preload (key, value) { + const preloadData = cacheDataGet(PRELOAD_DATA_KEY) || {} + if (typeof key === 'object') { + for (const k in key) { + preloadData[k] = key[k] + } + } else { + preloadData[key] = value + } + cacheDataSet(PRELOAD_DATA_KEY, preloadData) + } + + // 会被匿名函数调用 + __triggerPropsFn (key, args) { + const keyChain = key.split('.') + const reduxFnPrefix = '__event_' + const reduxFnName = reduxFnPrefix + keyChain.shift() + // redux标识过的方法,直接调用 + if (reduxFnName in this) { + const scope = args.shift() + let fn + if (keyChain.length > 0) { + fn = safeGet(this[reduxFnName], keyChain.join('.')) + } else { + fn = this[reduxFnName] + } + fn.apply(scope, args) + } else { + // 普通的 + const keyLower = key.toLocaleLowerCase() + const detail = { + __isCustomEvt: true, + __arguments: args + } + if (args.length > 0) { + detail.value = args.slice(1) + } + this.$scope.triggerEvent(keyLower, detail) + } + } +} + +export default BaseComponent diff --git a/packages/taro-qq/src/create-app.js b/packages/taro-qq/src/create-app.js new file mode 100644 index 000000000000..0d640702c892 --- /dev/null +++ b/packages/taro-qq/src/create-app.js @@ -0,0 +1,45 @@ +function createApp (AppClass) { + const app = new AppClass() + const weappAppConf = { + onLaunch (options) { + app.$app = this + app.$app.$router = app.$router = { + params: options + } + if (app.componentWillMount) { + app.componentWillMount() + } + if (app.componentDidMount) { + app.componentDidMount() + } + }, + + onShow (options) { + Object.assign(app.$router.params, options) + if (app.componentDidShow) { + app.componentDidShow() + } + }, + + onHide () { + if (app.componentDidHide) { + app.componentDidHide() + } + }, + + onError (err) { + if (app.componentDidCatchError) { + app.componentDidCatchError(err) + } + }, + + onPageNotFound (obj) { + if (app.componentDidNotFound) { + app.componentDidNotFound(obj) + } + } + } + return Object.assign(weappAppConf, app) +} + +export default createApp diff --git a/packages/taro-qq/src/create-component.js b/packages/taro-qq/src/create-component.js new file mode 100644 index 000000000000..c6b4b2dd674b --- /dev/null +++ b/packages/taro-qq/src/create-component.js @@ -0,0 +1,428 @@ +import { getCurrentPageUrl } from '@tarojs/utils' + +import { isEmptyObject, noop, isFunction } from './util' +import { updateComponent } from './lifecycle' +import { cacheDataSet, cacheDataGet, cacheDataHas } from './data-cache' +import { Current } from './current-owner'; + +const privatePropValName = '__triggerObserer' +const anonymousFnNamePreffix = 'funPrivate' +const componentFnReg = /^__fn_/ +const routerParamsPrivateKey = '__key_' +const preloadPrivateKey = '__preload_' +const PRELOAD_DATA_KEY = 'preload' +const preloadInitedComponent = '$preloadComponent' +const pageExtraFns = ['onPullDownRefresh', 'onReachBottom', 'onShareAppMessage', 'onPageScroll', 'onTabItemTap', 'onResize'] + +function bindProperties (weappComponentConf, ComponentClass, isPage) { + weappComponentConf.properties = ComponentClass.properties || {} + const defaultProps = ComponentClass.defaultProps || {} + for (const key in defaultProps) { + if (defaultProps.hasOwnProperty(key)) { + weappComponentConf.properties[key] = { + type: null, + value: null + } + } + } + if (isPage) { + weappComponentConf.properties[routerParamsPrivateKey] = { + type: null, + value: null + } + weappComponentConf.properties[preloadPrivateKey] = { + type: null, + value: null + } + const defaultParams = ComponentClass.defaultParams || {} + for (const key in defaultParams) { + if (defaultParams.hasOwnProperty(key)) { + weappComponentConf.properties[key] = { + type: null, + value: null + } + } + } + } + // 拦截props的更新,插入生命周期 + // 调用小程序setData或会造成性能消耗 + weappComponentConf.properties[privatePropValName] = { + type: null, + observer: function () { + if (!this.$component || !this.$component.__isReady) return + const nextProps = filterProps(ComponentClass.properties, ComponentClass.defaultProps, this.$component.props, this.data) + this.$component.props = nextProps + this.$component._unsafeCallUpdate = true + updateComponent(this.$component) + this.$component._unsafeCallUpdate = false + } + } +} + +function bindBehaviors (weappComponentConf, ComponentClass) { + if (ComponentClass.behaviors) { + weappComponentConf.behaviors = ComponentClass.behaviors + } +} + +function bindStaticOptions (weappComponentConf, ComponentClass) { + if (ComponentClass.options) { + weappComponentConf.options = ComponentClass.options + } +} + +function bindMultipleSlots (weappComponentConf, ComponentClass) { + const multipleSlots = ComponentClass.multipleSlots + if (!multipleSlots) { + return + } + weappComponentConf.options = { + ...weappComponentConf.options, + ...{ multipleSlots } + } +} + +function bindStaticFns (weappComponentConf, ComponentClass) { + for (const key in ComponentClass) { + typeof ComponentClass[key] === 'function' && (weappComponentConf[key] = ComponentClass[key]) + } + // 低版本 IOS 下部分属性不能直接访问 + Object.getOwnPropertyNames(ComponentClass).forEach(key => { + const excludes = ['arguments', 'caller', 'length', 'name', 'prototype'] + if (excludes.indexOf(key) < 0) { + typeof ComponentClass[key] === 'function' && (weappComponentConf[key] = ComponentClass[key]) + } + }) +} + +function processEvent (eventHandlerName, obj) { + if (obj[eventHandlerName]) return + + obj[eventHandlerName] = function (event) { + if (event) { + event.preventDefault = function () {} + event.stopPropagation = function () {} + event.currentTarget = event.currentTarget || event.target || {} + if (event.target) { + Object.assign(event.target, event.detail) + } + Object.assign(event.currentTarget, event.detail) + } + + const scope = this.$component + let callScope = scope + const isAnonymousFn = eventHandlerName.indexOf(anonymousFnNamePreffix) > -1 + let realArgs = [] + let detailArgs = [] + let datasetArgs = [] + let isScopeBinded = false + // 解析从dataset中传过来的参数 + const dataset = event.currentTarget.dataset || {} + const bindArgs = {} + const eventType = event.type.toLocaleLowerCase() + Object.keys(dataset).forEach(key => { + let keyLower = key.toLocaleLowerCase() + if (/^e/.test(keyLower)) { + // 小程序属性里中划线后跟一个下划线会解析成不同的结果 + keyLower = keyLower.replace(/^e/, '') + if (keyLower.indexOf(eventType) >= 0) { + const argName = keyLower.replace(eventType, '') + if (/^(a[a-z]|so)$/.test(argName)) { + bindArgs[argName] = dataset[key] + } + } + } + }) + // 如果是通过triggerEvent触发,并且带有参数 + if (event.detail && event.detail.__arguments && event.detail.__arguments.length > 0) { + detailArgs = event.detail.__arguments + } + // 普通的事件(非匿名函数),会直接call + if (!isAnonymousFn) { + if ('so' in bindArgs) { + if (bindArgs['so'] !== 'this') { + callScope = bindArgs['so'] + } + isScopeBinded = true + delete bindArgs['so'] + } + if (detailArgs.length > 0) { + !isScopeBinded && detailArgs[0] && (callScope = detailArgs[0]) + detailArgs.shift() + } + if (!isEmptyObject(bindArgs)) { + datasetArgs = Object.keys(bindArgs) + .sort() + .map(key => bindArgs[key]) + } + realArgs = [...datasetArgs, ...detailArgs, event] + } else { + // 匿名函数,会将scope作为第一个参数 + let _scope = null + if ('so' in bindArgs) { + if (bindArgs['so'] !== 'this') { + _scope = bindArgs['so'] + } + isScopeBinded = true + delete bindArgs['so'] + } + if (detailArgs.length > 0) { + !isScopeBinded && detailArgs[0] && (callScope = detailArgs[0]) + detailArgs.shift() + } + if (!isEmptyObject(bindArgs)) { + datasetArgs = Object.keys(bindArgs) + .sort() + .map(key => bindArgs[key]) + } + realArgs = [_scope, ...datasetArgs, ...detailArgs, event] + } + return scope[eventHandlerName].apply(callScope, realArgs) + } +} + +function bindEvents (weappComponentConf, events, isPage) { + weappComponentConf.methods = weappComponentConf.methods || {} + const target = weappComponentConf.methods + events.forEach(name => { + processEvent(name, target) + }) +} + +function filterProps (properties, defaultProps = {}, componentProps = {}, weappComponentData) { + let newProps = Object.assign({}, componentProps) + for (const propName in properties) { + if (propName === privatePropValName) { + continue + } + if (typeof componentProps[propName] === 'function') { + newProps[propName] = componentProps[propName] + } else if (propName in weappComponentData) { + newProps[propName] = weappComponentData[propName] + } + if (componentFnReg.test(propName)) { + if (weappComponentData[propName] === true) { + const fnName = propName.replace(componentFnReg, '') + newProps[fnName] = noop + } + delete newProps[propName] + } + } + if (!isEmptyObject(defaultProps)) { + for (const propName in defaultProps) { + if (newProps[propName] === undefined || newProps[propName] === null) { + newProps[propName] = defaultProps[propName] + } + } + } + return newProps +} + +function filterParams (data, defaultParams = {}) { + let res = {} + for (const paramName in defaultParams) { + res[paramName] = paramName in data ? data[paramName] : defaultParams[paramName] + } + return res +} + +export function componentTrigger (component, key, args) { + args = args || [] + + if (key === 'componentDidMount') { + if (component['$$refs'] && component['$$refs'].length > 0) { + let refs = {} + component['$$refs'].forEach(ref => { + let target + if (ref.type === 'component') { + target = component.$scope.selectComponent(`#${ref.id}`) + target = target ? (target.$component || target) : null + } else { + const query = qq.createSelectorQuery().in(component.$scope) + target = query.select(`#${ref.id}`) + } + if ('refName' in ref && ref['refName']) { + refs[ref.refName] = target + } else if ('fn' in ref && typeof ref['fn'] === 'function') { + ref['fn'].call(component, target) + } + ref.target = target + }) + component.refs = Object.assign({}, component.refs || {}, refs) + } + } + + component[key] && typeof component[key] === 'function' && component[key].call(component, ...args) + if (key === 'componentWillMount') { + component._dirty = false + component._disable = false + component.state = component.getState() + } + if (key === 'componentWillUnmount') { + component._dirty = true + component._disable = true + component.$router = { + params: {}, + path: '' + } + component._pendingStates = [] + component._pendingCallbacks = [] + // refs + if (component['$$refs'] && component['$$refs'].length > 0) { + component['$$refs'].forEach(ref => typeof ref['fn'] === 'function' && ref['fn'].call(component, null)) + component.refs = {} + } + } +} + +function initComponent (ComponentClass, isPage) { + if (this.$component.__isReady) return + // ready之后才可以setData, + // ready之前,小程序组件初始化时仍然会触发observer,__isReady为否的时候放弃处理observer + this.$component.__isReady = true + // 页面Ready的时候setData更新,此时并未didMount,触发observer但不会触发子组件更新 + // 小程序组件ready,但是数据并没有ready,需要通过updateComponent来初始化数据,setData完成之后才是真正意义上的组件ready + // 动态组件执行改造函数副本的时,在初始化数据前计算好props + if (!isPage) { + const nextProps = filterProps(ComponentClass.properties, ComponentClass.defaultProps, this.$component.props, this.data) + this.$component.props = nextProps + } else { + this.$component.$router.path = getCurrentPageUrl() + } + updateComponent(this.$component) +} + +function createComponent (ComponentClass, isPage) { + let initData = { + _componentProps: 1 + } + const componentProps = filterProps({}, ComponentClass.defaultProps) + const componentInstance = new ComponentClass(componentProps) + componentInstance._constructor && componentInstance._constructor(componentProps) + try { + Current.current = componentInstance + Current.index = 0 + componentInstance.state = componentInstance._createData() || componentInstance.state + } catch (err) { + if (isPage) { + console.warn(`[Taro warn] 请给页面提供初始 \`state\` 以提高初次渲染性能!`) + } else { + console.warn(`[Taro warn] 请给组件提供一个 \`defaultProps\` 以提高初次渲染性能!`) + } + console.warn(err) + } + initData = Object.assign({}, initData, componentInstance.props, componentInstance.state) + + const weappComponentConf = { + data: initData, + created (options = {}) { + if (isPage && cacheDataHas(preloadInitedComponent)) { + this.$component = cacheDataGet(preloadInitedComponent, true) + } else { + this.$component = new ComponentClass({}, isPage) + } + this.$component._init(this) + this.$component.render = this.$component._createData + this.$component.__propTypes = ComponentClass.propTypes + Object.assign(this.$component.$router.params, options) + }, + attached () { + let hasParamsCache + if (isPage) { + // params + let params = {} + hasParamsCache = cacheDataHas(this.data[routerParamsPrivateKey]) + if (hasParamsCache) { + params = Object.assign({}, ComponentClass.defaultParams, cacheDataGet(this.data[routerParamsPrivateKey], true)) + } else { + // 直接启动,非内部跳转 + params = filterParams(this.data, ComponentClass.defaultParams) + } + if (cacheDataHas(PRELOAD_DATA_KEY)) { + const data = cacheDataGet(PRELOAD_DATA_KEY, true) + this.$component.$router.preload = data + } + Object.assign(this.$component.$router.params, params) + // preload + if (cacheDataHas(this.data[preloadPrivateKey])) { + this.$component.$preloadData = cacheDataGet(this.data[preloadPrivateKey], true) + } else { + this.$component.$preloadData = null + } + } + if (!isPage || hasParamsCache || ComponentClass.defaultParams) { + initComponent.apply(this, [ComponentClass, isPage]) + } + }, + ready () { + if (!isPage && !this.$component.__mounted) { + this.$component.__mounted = true + componentTrigger(this.$component, 'componentDidMount') + } + }, + detached () { + const component = this.$component + componentTrigger(component, 'componentWillUnmount') + component.hooks.forEach((hook) => { + if (isFunction(hook.cleanup)) { + hook.cleanup() + } + }) + } + } + if (isPage) { + weappComponentConf.methods = weappComponentConf.methods || {} + weappComponentConf.methods['onLoad'] = function (options = {}) { + if (this.$component.__isReady) return + Object.assign(this.$component.$router.params, options) + initComponent.apply(this, [ComponentClass, isPage]) + } + weappComponentConf.methods['onReady'] = function () { + this.$component.__mounted = true + componentTrigger(this.$component, 'componentDidMount') + } + weappComponentConf.methods['onShow'] = function () { + componentTrigger(this.$component, 'componentDidShow') + } + weappComponentConf.methods['onHide'] = function () { + componentTrigger(this.$component, 'componentDidHide') + } + pageExtraFns.forEach(fn => { + if (componentInstance[fn] && typeof componentInstance[fn] === 'function') { + weappComponentConf.methods[fn] = function () { + const component = this.$component + if (component[fn] && typeof component[fn] === 'function') { + return component[fn].call(component, ...arguments) + } + } + } + }) + __wxRoute && cacheDataSet(__wxRoute, ComponentClass) + } else { + weappComponentConf.pageLifetimes = weappComponentConf.pageLifetimes || {} + + weappComponentConf.pageLifetimes['show'] = function () { + componentTrigger(this.$component, 'componentDidShow') + } + + weappComponentConf.pageLifetimes['hide'] = function () { + componentTrigger(this.$component, 'componentDidHide') + } + + weappComponentConf.pageLifetimes['resize'] = function () { + componentTrigger(this.$component, 'onResize') + } + } + bindProperties(weappComponentConf, ComponentClass, isPage) + bindBehaviors(weappComponentConf, ComponentClass) + bindStaticFns(weappComponentConf, ComponentClass) + bindStaticOptions(weappComponentConf, ComponentClass) + bindMultipleSlots(weappComponentConf, ComponentClass) + ComponentClass['$$events'] && bindEvents(weappComponentConf, ComponentClass['$$events'], isPage) + if (ComponentClass['externalClasses'] && ComponentClass['externalClasses'].length) { + weappComponentConf['externalClasses'] = ComponentClass['externalClasses'] + } + return weappComponentConf +} + +export default createComponent diff --git a/packages/taro-qq/src/current-owner.js b/packages/taro-qq/src/current-owner.js new file mode 100644 index 000000000000..dfaf7aa3d1dc --- /dev/null +++ b/packages/taro-qq/src/current-owner.js @@ -0,0 +1,4 @@ +export const Current = { + current: null, + index: 0 +} diff --git a/packages/taro-qq/src/data-cache.js b/packages/taro-qq/src/data-cache.js new file mode 100644 index 000000000000..f11a760035da --- /dev/null +++ b/packages/taro-qq/src/data-cache.js @@ -0,0 +1,15 @@ +const data = {} + +export function cacheDataSet (key, val) { + data[key] = val +} + +export function cacheDataGet (key, delelteAfterGet) { + const temp = data[key] + delelteAfterGet && delete data[key] + return temp +} + +export function cacheDataHas (key) { + return key in data +} diff --git a/packages/taro-qq/src/hooks.js b/packages/taro-qq/src/hooks.js new file mode 100644 index 000000000000..6b1d00e6e2e5 --- /dev/null +++ b/packages/taro-qq/src/hooks.js @@ -0,0 +1,166 @@ +import { isFunction, isUndefined, isArray, isNullOrUndef } from './util' +import { Current } from './current-owner' +import nextTick from './next-tick' + +function getHooks (index) { + if (Current.current === null) { + throw new Error(`invalid hooks call: hooks can only be called in a stateless component.`) + } + const hooks = Current.current.hooks + if (index >= hooks.length) { + hooks.push({}) + } + return hooks[index] +} + +export function useState (initialState) { + if (isFunction(initialState)) { + initialState = initialState() + } + const hook = getHooks(Current.index++) + if (!hook.state) { + hook.component = Current.current + hook.state = [ + initialState, + (action) => { + hook.state[0] = isFunction(action) ? action(hook.state[0]) : action + hook.component._disable = false + hook.component.setState({}) + } + ] + } + return hook.state +} + +export function useReducer ( + reducer, + initialState, + initializer +) { + if (isFunction(initialState)) { + initialState = initialState() + } + const hook = getHooks(Current.index++) + if (!hook.state) { + hook.component = Current.current + hook.state = [ + isUndefined(initializer) ? initialState : initializer(initialState), + (action) => { + hook.state[0] = reducer(hook.state[0], action) + hook.component._disable = false + hook.component.setState({}) + } + ] + } + return hook.state +} + +function areDepsChanged (prevDeps, deps) { + if (isNullOrUndef(prevDeps) || isNullOrUndef(deps)) { + return true + } + return deps.some((a, i) => a !== prevDeps[i]) +} + +export function invokeEffects (component, delay) { + const effects = delay ? component.effects : component.layoutEffects + effects.forEach((hook) => { + if (isFunction(hook.cleanup)) { + hook.cleanup() + } + const result = hook.effect() + if (isFunction(result)) { + hook.cleanup = result + } + }) + + if (delay) { + component.effects = [] + } else { + component.layoutEffects = [] + } +} + +let scheduleEffectComponents = [] + +function invokeScheduleEffects (component) { + if (!component._afterScheduleEffect) { + component._afterScheduleEffect = true + scheduleEffectComponents.push(component) + if (scheduleEffectComponents.length === 1) { + nextTick(() => { + setTimeout(() => { + scheduleEffectComponents.forEach((c) => { + c._afterScheduleEffect = false + invokeEffects(c, true) + }) + scheduleEffectComponents = [] + }, 0) + }) + } + } +} + +function useEffectImpl (effect, deps, delay) { + const hook = getHooks(Current.index++) + if (Current.current._disableHooks || !Current.current.__isReady) { + return + } + if (areDepsChanged(hook.deps, deps)) { + hook.effect = effect + hook.deps = deps + + if (delay) { + Current.current.effects = Current.current.effects.concat(hook) + invokeScheduleEffects(Current.current) + } else { + Current.current.layoutEffects = Current.current.layoutEffects.concat(hook) + } + } +} + +export function useEffect (effect, deps) { + useEffectImpl(effect, deps, true) +} + +export function useLayoutEffect (effect, deps) { + useEffectImpl(effect, deps) +} + +export function useRef (initialValue) { + const hook = getHooks(Current.index++) + if (!hook.ref) { + hook.ref = { + current: initialValue + } + } + return hook.ref +} + +export function useMemo (factory, deps) { + const hook = getHooks(Current.index++) + if (areDepsChanged(hook.deps, deps)) { + hook.deps = deps + hook.callback = factory + hook.value = factory() + } + return hook.value +} + +export function useCallback (callback, deps) { + return useMemo(() => callback, deps) +} + +export function useImperativeHandle (ref, init, deps) { + useLayoutEffect(() => { + if (isFunction(ref)) { + ref(init()) + return () => ref(null) + } else if (!isUndefined(ref)) { + ref.current = init() + return () => { + delete ref.current + } + } + }, isArray(deps) ? deps.concat([ref]) : undefined) +} diff --git a/packages/taro-qq/src/index.js b/packages/taro-qq/src/index.js new file mode 100644 index 000000000000..f15da579beda --- /dev/null +++ b/packages/taro-qq/src/index.js @@ -0,0 +1,44 @@ +/* eslint-disable camelcase */ +import { + getEnv, + Events, + eventCenter, + ENV_TYPE, + render, + internal_safe_get, + internal_safe_set, + internal_inline_style, + internal_get_original +} from '@tarojs/taro' + +import Component from './component' +import PureComponent from './pure-component' +import createApp from './create-app' +import createComponent from './create-component' +import initNativeApi from './native-api' +import { getElementById } from './util' +import { useEffect, useLayoutEffect, useReducer, useState, useRef, useCallback, useMemo, useImperativeHandle } from './hooks' + +export const Taro = { + Component, + PureComponent, + createApp, + initNativeApi, + Events, + eventCenter, + getEnv, + render, + ENV_TYPE, + internal_safe_get, + internal_safe_set, + internal_inline_style, + createComponent, + internal_get_original, + getElementById, + // eslint-disable-next-line object-property-newline + useEffect, useLayoutEffect, useReducer, useState, useRef, useCallback, useMemo, useImperativeHandle +} + +export default Taro + +initNativeApi(Taro) diff --git a/packages/taro-qq/src/lifecycle.js b/packages/taro-qq/src/lifecycle.js new file mode 100644 index 000000000000..ccb30acdcffd --- /dev/null +++ b/packages/taro-qq/src/lifecycle.js @@ -0,0 +1,150 @@ +import { + internal_safe_get as safeGet, + internal_safe_set as safeSet +} from '@tarojs/taro' +// import PropTypes from 'prop-types' +import { componentTrigger } from './create-component' +import { shakeFnFromObject, isEmptyObject, diffObjToPath } from './util' +import { Current } from './current-owner' +import { invokeEffects } from './hooks' + +// const isDEV = typeof process === 'undefined' || +// !process.env || +// process.env.NODE_ENV !== 'production' + +const privatePropKeyName = '_triggerObserer' +export function updateComponent (component) { + const { props } = component + // if (isDEV && __propTypes) { + // const componentName = component.constructor.name || component.constructor.toString().match(/^function\s*([^\s(]+)/)[1] + // PropTypes.checkPropTypes(__propTypes, props, 'prop', componentName) + // } + const prevProps = component.prevProps || props + component.props = prevProps + if (component.__mounted && component._unsafeCallUpdate === true && component.componentWillReceiveProps) { + component._disable = true + component.componentWillReceiveProps(props) + component._disable = false + } + // 在willMount前执行构造函数的副本 + if (!component.__componentWillMountTriggered) { + component._constructor && component._constructor(props) + } + let state = component.getState() + + const prevState = component.prevState || state + + let skip = false + if (component.__mounted) { + if (typeof component.shouldComponentUpdate === 'function' && + !component._isForceUpdate && + component.shouldComponentUpdate(props, state) === false) { + skip = true + } else if (typeof component.componentWillUpdate === 'function') { + component.componentWillUpdate(props, state) + } + } + component.props = props + component.state = state + component._dirty = false + component._isForceUpdate = false + if (!component.__componentWillMountTriggered) { + component.__componentWillMountTriggered = true + componentTrigger(component, 'componentWillMount') + } + if (!skip) { + doUpdate(component, prevProps, prevState) + } + component.prevProps = component.props + component.prevState = component.state +} + +function doUpdate (component, prevProps, prevState) { + const { state, props = {} } = component + let data = state || {} + if (component._createData) { + // 返回null或undefined则保持不变 + const runLoopRef = !component.__mounted + if (component.__isReady) { + Current.current = component + Current.index = 0 + invokeEffects(component, true) + } + data = component._createData(state, props, runLoopRef) || data + if (component.__isReady) { + Current.current = null + } + } + let privatePropKeyVal = component.$scope.data[privatePropKeyName] || false + + data = Object.assign({}, props, data) + if (component.$usedState && component.$usedState.length) { + const _data = {} + component.$usedState.forEach(key => { + let val = safeGet(data, key) + if (typeof val === 'undefined') { + return + } + if (typeof val === 'object') { + if (isEmptyObject(val)) return safeSet(_data, key, val) + + val = shakeFnFromObject(val) + // 避免筛选完 Fn 后产生了空对象还去渲染 + if (!isEmptyObject(val)) safeSet(_data, key, val) + } else { + safeSet(_data, key, val) + } + }) + data = _data + } + // 改变这个私有的props用来触发(observer)子组件的更新 + data[privatePropKeyName] = !privatePropKeyVal + const dataDiff = diffObjToPath(data, component.$scope.data) + const __mounted = component.__mounted + + // 每次 setData 都独立生成一个 callback 数组 + let cbs = [] + if (component._pendingCallbacks && component._pendingCallbacks.length) { + cbs = component._pendingCallbacks + component._pendingCallbacks = [] + } + + component.$scope.setData(dataDiff, function () { + if (__mounted) { + invokeEffects(component) + if (component['$$refs'] && component['$$refs'].length > 0) { + component['$$refs'].forEach(ref => { + // 只有 component 类型能做判断。因为 querySelector 每次调用都一定返回 nodeRefs,无法得知 dom 类型的挂载状态。 + if (ref.type !== 'component') return + + let target = component.$scope.selectComponent(`#${ref.id}`) + target = target ? (target.$component || target) : null + + const prevRef = ref.target + if (target !== prevRef) { + if (ref.refName) component.refs[ref.refName] = target + typeof ref.fn === 'function' && ref.fn.call(component, target) + ref.target = target + } + }) + } + + if (component['$$hasLoopRef']) { + component._disableEffect = true + component._createData(component.state, component.props, true) + component._disableEffect = false + } + + if (typeof component.componentDidUpdate === 'function') { + component.componentDidUpdate(prevProps, prevState) + } + } + + if (cbs.length) { + let i = cbs.length + while (--i >= 0) { + typeof cbs[i] === 'function' && cbs[i].call(component) + } + } + }) +} diff --git a/packages/taro-qq/src/native-api.js b/packages/taro-qq/src/native-api.js new file mode 100644 index 000000000000..7130e695ed80 --- /dev/null +++ b/packages/taro-qq/src/native-api.js @@ -0,0 +1,205 @@ +import { + onAndSyncApis, + noPromiseApis, + otherApis, + initPxTransform +} from '@tarojs/taro' +import { cacheDataSet, cacheDataGet } from './data-cache' +import { queryToJson, getUniqueKey } from './util' +const RequestQueue = { + MAX_REQUEST: 5, + queue: [], + request (options) { + this.push(options) + // 返回request task + return this.run() + }, + + push (options) { + this.queue.push(options) + }, + + run () { + if (!this.queue.length) { + return + } + if (this.queue.length <= this.MAX_REQUEST) { + let options = this.queue.shift() + let completeFn = options.complete + options.complete = (...args) => { + completeFn && completeFn.apply(options, args) + this.run() + } + return qq.request(options) + } + } +} + +function request (options) { + options = options || {} + if (typeof options === 'string') { + options = { + url: options + } + } + const originSuccess = options['success'] + const originFail = options['fail'] + const originComplete = options['complete'] + let requestTask + const p = new Promise((resolve, reject) => { + options['success'] = res => { + originSuccess && originSuccess(res) + resolve(res) + } + options['fail'] = res => { + originFail && originFail(res) + reject(res) + } + + options['complete'] = res => { + originComplete && originComplete(res) + } + + requestTask = RequestQueue.request(options) + }) + p.abort = (cb) => { + cb && cb() + if (requestTask) { + requestTask.abort() + } + return p + } + return p +} + +function processApis (taro) { + const weApis = Object.assign({ }, onAndSyncApis, noPromiseApis, otherApis) + const useDataCacheApis = { + 'navigateTo': true, + 'redirectTo': true, + 'reLaunch': true + } + const routerParamsPrivateKey = '__key_' + const preloadPrivateKey = '__preload_' + const preloadInitedComponent = '$preloadComponent' + Object.keys(weApis).forEach(key => { + if (!onAndSyncApis[key] && !noPromiseApis[key]) { + taro[key] = (options, ...args) => { + options = options || {} + let task = null + let obj = Object.assign({}, options) + if (typeof options === 'string') { + if (args.length) { + return qq[key](options, ...args) + } + return qq[key](options) + } + + if (key === 'navigateTo' || key === 'redirectTo' || key === 'switchTab') { + let url = obj['url'] ? obj['url'].replace(/^\//, '') : '' + if (url.indexOf('?') > -1) url = url.split('?')[0] + + const Component = cacheDataGet(url) + if (Component) { + const component = new Component() + if (component.componentWillPreload) { + const cacheKey = getUniqueKey() + const MarkIndex = obj.url.indexOf('?') + const params = queryToJson(obj.url.substring(MarkIndex + 1, obj.url.length)) + obj.url += (MarkIndex > -1 ? '&' : '?') + `${preloadPrivateKey}=${cacheKey}` + cacheDataSet(cacheKey, component.componentWillPreload(params)) + cacheDataSet(preloadInitedComponent, component) + } + } + } + + if (useDataCacheApis[key]) { + const url = obj['url'] = obj['url'] || '' + const MarkIndex = url.indexOf('?') + const params = queryToJson(url.substring(MarkIndex + 1, url.length)) + const cacheKey = getUniqueKey() + obj.url += (MarkIndex > -1 ? '&' : '?') + `${routerParamsPrivateKey}=${cacheKey}` + cacheDataSet(cacheKey, params) + } + + const p = new Promise((resolve, reject) => { + ['fail', 'success', 'complete'].forEach((k) => { + obj[k] = (res) => { + options[k] && options[k](res) + if (k === 'success') { + if (key === 'connectSocket') { + resolve( + Promise.resolve().then(() => Object.assign(task, res)) + ) + } else { + resolve(res) + } + } else if (k === 'fail') { + reject(res) + } + } + }) + if (args.length) { + task = qq[key](obj, ...args) + } else { + task = qq[key](obj) + } + }) + if (key === 'uploadFile' || key === 'downloadFile') { + p.progress = cb => { + if (task) { + task.onProgressUpdate(cb) + } + return p + } + p.abort = cb => { + cb && cb() + if (task) { + task.abort() + } + return p + } + } + return p + } + } else { + taro[key] = (...args) => { + const argsLen = args.length + const newArgs = args.concat() + const lastArg = newArgs[argsLen - 1] + if (lastArg && lastArg.isTaroComponent && lastArg.$scope) { + newArgs.splice(argsLen - 1, 1, lastArg.$scope) + } + return qq[key].apply(qq, newArgs) + } + } + }) +} + +function pxTransform (size) { + const { designWidth, deviceRatio } = this.config + if (!(designWidth in deviceRatio)) { + throw new Error(`deviceRatio 配置中不存在 ${designWidth} 的设置!`) + } + return parseInt(size, 10) / deviceRatio[designWidth] + 'rpx' +} + +function canIUseWebp () { + const { platform } = qq.getSystemInfoSync() + const platformLower = platform.toLowerCase() + if (platformLower === 'android' || platformLower === 'devtools') { + return true + } + return false +} + +export default function initNativeApi (taro) { + processApis(taro) + taro.request = request + taro.getCurrentPages = getCurrentPages + taro.getApp = getApp + taro.requirePlugin = requirePlugin + taro.initPxTransform = initPxTransform.bind(taro) + taro.pxTransform = pxTransform.bind(taro) + taro.canIUseWebp = canIUseWebp +} diff --git a/packages/taro-qq/src/next-tick.js b/packages/taro-qq/src/next-tick.js new file mode 100644 index 000000000000..10188216068e --- /dev/null +++ b/packages/taro-qq/src/next-tick.js @@ -0,0 +1,7 @@ +const nextTick = (fn, ...args) => { + fn = typeof fn === 'function' ? fn.bind(null, ...args) : fn + const timerFunc = qq.nextTick ? qq.nextTick : setTimeout + timerFunc(fn) +} + +export default nextTick diff --git a/packages/taro-qq/src/pure-component.js b/packages/taro-qq/src/pure-component.js new file mode 100644 index 000000000000..5aea70022c69 --- /dev/null +++ b/packages/taro-qq/src/pure-component.js @@ -0,0 +1,13 @@ +import { shallowEqual } from '@tarojs/utils' + +import Component from './component' + +class PureComponent extends Component { + isPureComponent = true + + shouldComponentUpdate (nextProps, nextState) { + return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState) + } +} + +export default PureComponent diff --git a/packages/taro-qq/src/render-queue.js b/packages/taro-qq/src/render-queue.js new file mode 100644 index 000000000000..9f2c40f7767e --- /dev/null +++ b/packages/taro-qq/src/render-queue.js @@ -0,0 +1,23 @@ +import nextTick from './next-tick' +import { updateComponent } from './lifecycle' + +let items = [] + +export function enqueueRender (component) { + // tslint:disable-next-line:no-conditional-assignment + if (!component._dirty && (component._dirty = true) && items.push(component) === 1) { + nextTick(rerender) + } +} + +export function rerender () { + let p + const list = items + items = [] + // tslint:disable-next-line:no-conditional-assignment + while ((p = list.pop())) { + if (p._dirty) { + updateComponent(p, true) + } + } +} diff --git a/packages/taro-qq/src/util.js b/packages/taro-qq/src/util.js new file mode 100644 index 000000000000..d9424bdb7cb2 --- /dev/null +++ b/packages/taro-qq/src/util.js @@ -0,0 +1,260 @@ +import isPlainObject from 'lodash/isPlainObject' + +export function isEmptyObject (obj) { + if (!obj || !isPlainObject(obj)) { + return false + } + for (const n in obj) { + if (obj.hasOwnProperty(n)) { + return false + } + } + return true +} + +export function isUndefined (o) { + return o === undefined +} + +export function isNullOrUndef (o) { + return isUndefined(o) || o === null +} + +/** + * JSON 克隆 + * @param {Object | Json} jsonObj json对象 + * @return {Object | Json} 新的json对象 + */ +export function objClone (jsonObj) { + let buf + if (Array.isArray(jsonObj)) { + buf = [] + let i = jsonObj.length + while (i--) { + buf[i] = objClone(jsonObj[i]) + } + return buf + } else if (isPlainObject(jsonObj)) { + buf = {} + for (const k in jsonObj) { + buf[k] = objClone(jsonObj[k]) + } + return buf + } else { + return jsonObj + } +} + +export function getPrototype (obj) { + /* eslint-disable */ + if (Object.getPrototypeOf) { + return Object.getPrototypeOf(obj) + } else if (obj.__proto__) { + return obj.__proto__ + } + /* eslint-enable */ + return obj.constructor.prototype +} + +export function getPrototypeChain (obj) { + const protoChain = [] + while ((obj = getPrototype(obj))) { + protoChain.push(obj) + } + return protoChain +} + +export function noop () {} + +export function isFunction (arg) { + return typeof arg === 'function' +} + +export function isArray (arg) { + return Array.isArray(arg) +} + +export function shakeFnFromObject (obj) { + let newObj + if (isArray(obj)) { + newObj = [] + const len = obj.length + for (let i = 0; i < len; i++) { + newObj.push(shakeFnFromObject(obj[i])) + } + } else if (isPlainObject(obj)) { + newObj = {} + for (const key in obj) { + if (isFunction(obj[key])) { + continue + } + const ret = shakeFnFromObject(obj[key]) + newObj[key] = ret + } + } else { + return obj + } + return newObj +} + +const keyList = Object.keys +const hasProp = Object.prototype.hasOwnProperty + +function diffArrToPath (to, from, res = {}, keyPrev = '') { + const len = to.length + for (let i = 0; i < len; i++) { + const toItem = to[i] + const fromItem = from[i] + const targetKey = `${keyPrev}[${i}]` + if (toItem === fromItem) { + continue + } else if (typeof toItem !== typeof fromItem) { + res[targetKey] = toItem + } else { + if (typeof toItem !== 'object') { + res[targetKey] = toItem + } else { + const arrTo = isArray(toItem) + const arrFrom = isArray(fromItem) + if (arrTo !== arrFrom) { + res[targetKey] = toItem + } else if (arrTo && arrFrom) { + if (toItem.length === fromItem.length) { + diffArrToPath(toItem, fromItem, res, `${targetKey}`) + } else { + res[targetKey] = toItem + } + } else { + if (!toItem || !fromItem || keyList(toItem).length < keyList(fromItem).length) { + res[targetKey] = toItem + } else { + // 对象 + let shouldDiffObject = true + Object.keys(fromItem).some(key => { + if (typeof toItem[key] === 'undefined') { + shouldDiffObject = false + return true + } + }) + if (shouldDiffObject) { + diffObjToPath(toItem, fromItem, res, `${targetKey}.`) + } else { + res[targetKey] = toItem + } + } + } + } + } + } + return res +} + +// 比较的对象均为plainObject,且函数已被过滤 +export function diffObjToPath (to, from, res = {}, keyPrev = '') { + const keys = keyList(to) + const len = keys.length + + for (let i = 0; i < len; i++) { + const key = keys[i] + const toItem = to[key] + const fromItem = from[key] + const targetKey = `${keyPrev}${key}` + if (toItem === fromItem) { + continue + } else if (!hasProp.call(from, key)) { + res[targetKey] = toItem + } else if (typeof toItem !== typeof fromItem) { + res[targetKey] = toItem + } else { + if (typeof toItem !== 'object') { + res[targetKey] = toItem + } else { + const arrTo = isArray(toItem) + const arrFrom = isArray(fromItem) + if (arrTo !== arrFrom) { + res[targetKey] = toItem + } else if (arrTo && arrFrom) { + if (toItem.length === fromItem.length) { + diffArrToPath(toItem, fromItem, res, `${targetKey}`) + } else { + res[targetKey] = toItem + } + } else { + // null + if (!toItem || !fromItem) { + res[targetKey] = toItem + } else { + // 对象 + let shouldDiffObject = true + Object.keys(fromItem).some(key => { + if (typeof toItem[key] === 'undefined') { + shouldDiffObject = false + return true + } + }) + if (shouldDiffObject) { + diffObjToPath(toItem, fromItem, res, `${targetKey}.`) + } else { + res[targetKey] = toItem + } + } + } + } + } + } + return res +} + +export function queryToJson (str) { + const dec = decodeURIComponent + const qp = str.split('&') + let ret = {} + let name + let val + for (let i = 0, l = qp.length, item; i < l; ++i) { + item = qp[i] + if (item.length) { + const s = item.indexOf('=') + if (s < 0) { + name = dec(item) + val = '' + } else { + name = dec(item.slice(0, s)) + val = dec(item.slice(s + 1)) + } + if (typeof ret[name] === 'string') { // inline'd type check + ret[name] = [ret[name]] + } + + if (isArray(ret[name])) { + ret[name].push(val) + } else { + ret[name] = val + } + } + } + return ret // Object +} + +const _loadTime = (new Date()).getTime().toString() +let _i = 1 +export function getUniqueKey () { + return _loadTime + (_i++) +} + +export function getElementById (component, id, type) { + if (!component) return null + + let res + if (type === 'component') { + res = component.selectComponent(id) + res = res ? (res.$component || res) : null + } else { + const query = qq.createSelectorQuery().in(component) + res = query.select(id) + } + + if (res) return res + + return null +} diff --git a/packages/taro-transformer-wx/src/adapter.ts b/packages/taro-transformer-wx/src/adapter.ts index f7e3f8349e44..507645cc96af 100644 --- a/packages/taro-transformer-wx/src/adapter.ts +++ b/packages/taro-transformer-wx/src/adapter.ts @@ -3,7 +3,8 @@ export const enum Adapters { swan = 'swan', alipay = 'alipay', quickapp = 'quickapp', - tt = 'tt' + tt = 'tt', + qq = 'qq' } interface Adapter { @@ -72,6 +73,17 @@ const quickappAdapter: Adapter = { type: Adapters.quickapp } +const qqAdapter: Adapter = { + if: 'qq:if', + else: 'qq:else', + elseif: 'qq:elif', + for: 'qq:for', + forItem: 'qq:for-item', + forIndex: 'qq:for-index', + key: 'qq:key', + type: Adapters.qq +} + export let Adapter: Adapter = weixinAdapter export function setAdapter (adapter: Adapters) { @@ -88,6 +100,9 @@ export function setAdapter (adapter: Adapters) { case Adapters.quickapp: Adapter = quickappAdapter break + case Adapters.qq: + Adapter = qqAdapter + break default: Adapter = weixinAdapter break diff --git a/packages/taro/src/env.js b/packages/taro/src/env.js index f455f035dd91..c87aa6d4646e 100644 --- a/packages/taro/src/env.js +++ b/packages/taro/src/env.js @@ -4,10 +4,14 @@ export const ENV_TYPE = { RN: 'RN', SWAN: 'SWAN', ALIPAY: 'ALIPAY', - TT: 'TT' + TT: 'TT', + QQ: 'QQ' } export function getEnv () { + if (typeof qq !== 'undefined' && qq.getSystemInfo) { + return ENV_TYPE.QQ + } if (typeof tt !== 'undefined' && tt.getSystemInfo) { return ENV_TYPE.TT } From 94d262ee609d3ad314b85c7c0a90d4b0adb57f57 Mon Sep 17 00:00:00 2001 From: yuche Date: Thu, 18 Apr 2019 15:36:21 +0800 Subject: [PATCH 097/103] =?UTF-8?q?refactor(transformer):=20=E5=BF=AB?= =?UTF-8?q?=E5=BA=94=E7=94=A8=20taro-page=20=E7=9A=84=E7=9A=84=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E5=BA=94=E8=AF=A5=E4=BF=9D=E6=8C=81=E5=8E=9F=E6=A0=B7?= =?UTF-8?q?=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../taro-transformer-wx/src/create-html-element.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/taro-transformer-wx/src/create-html-element.ts b/packages/taro-transformer-wx/src/create-html-element.ts index 0fc2196cf5d9..f5aac71e63ab 100644 --- a/packages/taro-transformer-wx/src/create-html-element.ts +++ b/packages/taro-transformer-wx/src/create-html-element.ts @@ -1,6 +1,7 @@ import { Adapters, Adapter } from './adapter' import { quickappComponentName } from './constant' -import { transformOptions } from './options'; +import { transformOptions } from './options' +import { camelCase } from 'lodash' const voidHtmlTags = new Set([ // 'image', @@ -64,6 +65,13 @@ export const createHTMLElement = (options: Options, isFirstEmit = false) => { } if (isFirstEmit && name === 'div' && transformOptions.isRoot) { options.name = 'taro-page' + for (const key in options.attributes) { + if (options.attributes.hasOwnProperty(key)) { + const attr = options.attributes[key] + options.attributes[camelCase(key)] = attr + delete options.attributes[key] + } + } } } From 9252fd14ad975cf58f527a3d0917011a1ca52135 Mon Sep 17 00:00:00 2001 From: jinjinjin0731 <709899428@qq.com> Date: Fri, 19 Apr 2019 15:19:10 +0800 Subject: [PATCH 098/103] =?UTF-8?q?feat(component):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=BF=AB=E5=BA=94=E7=94=A8=20button,=20checkbox?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/checkbox/index.ux | 33 +++++ .../src/components/taro-button/img.js | 1 + .../src/components/taro-button/index.ux | 115 ++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 packages/taro-components-qa/src/components/checkbox/index.ux create mode 100644 packages/taro-components-qa/src/components/taro-button/img.js create mode 100644 packages/taro-components-qa/src/components/taro-button/index.ux diff --git a/packages/taro-components-qa/src/components/checkbox/index.ux b/packages/taro-components-qa/src/components/checkbox/index.ux new file mode 100644 index 000000000000..3658415a513c --- /dev/null +++ b/packages/taro-components-qa/src/components/checkbox/index.ux @@ -0,0 +1,33 @@ + + + + + diff --git a/packages/taro-components-qa/src/components/taro-button/img.js b/packages/taro-components-qa/src/components/taro-button/img.js new file mode 100644 index 000000000000..619081d152a4 --- /dev/null +++ b/packages/taro-components-qa/src/components/taro-button/img.js @@ -0,0 +1 @@ +export default 'data:image/gif;base64,R0lGODlhgACAAKIAAP///93d3bu7u5mZmQAA/wAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFBQAEACwCAAIAfAB8AAAD/0i63P4wygYqmDjrzbtflvWNZGliYXiubKuloivPLlzReD7al+7/Eh5wSFQIi8hHYBkwHUmD6CD5YTJLz49USuVYraRsZ7vtar7XnQ1Kjpoz6LRHvGlz35O4nEPP2O94EnpNc2sef1OBGIOFMId/inB6jSmPdpGScR19EoiYmZobnBCIiZ95k6KGGp6ni4wvqxilrqBfqo6skLW2YBmjDa28r6Eosp27w8Rov8ekycqoqUHODrTRvXsQwArC2NLF29UM19/LtxO5yJd4Au4CK7DUNxPebG4e7+8n8iv2WmQ66BtoYpo/dvfacBjIkITBE9DGlMvAsOIIZjIUAixliv9ixYZVtLUos5GjwI8gzc3iCGghypQqrbFsme8lwZgLZtIcYfNmTJ34WPTUZw5oRxdD9w0z6iOpO15MgTh1BTTJUKos39jE+o/KS64IFVmsFfYT0aU7capdy7at27dw48qdS7eu3bt480I02vUbX2F/JxYNDImw4GiGE/P9qbhxVpWOI/eFKtlNZbWXuzlmG1mv58+gQ4seTbq06dOoU6vGQZJy0FNlMcV+czhQ7SQmYd8eMhPs5BxVdfcGEtV3buDBXQ+fURxx8oM6MT9P+Fh6dOrH2zavc13u9JXVJb520Vp8dvC76wXMuN5Sepm/1WtkEZHDefnzR9Qvsd9+/wi8+en3X0ntYVcSdAE+UN4zs7ln24CaLagghIxBaGF8kFGoIYV+Ybghh841GIyI5ICIFoklJsigihmimJOLEbLYIYwxSgigiZ+8l2KB+Ml4oo/w8dijjcrouCORKwIpnJIjMnkkksalNeR4fuBIm5UEYImhIlsGCeWNNJphpJdSTlkml1jWeOY6TnaRpppUctcmFW9mGSaZceYopH9zkjnjUe59iR5pdapWaGqHopboaYua1qije67GJ6CuJAAAIfkEBQUABAAsCgACAFcAMAAAA/9Iutz+ML5Ag7w46z0r5WAoSp43nihXVmnrdusrv+s332dt4Tyo9yOBUJD6oQBIQGs4RBlHySSKyczVTtHoidocPUNZaZAr9F5FYbGI3PWdQWn1mi36buLKFJvojsHjLnshdhl4L4IqbxqGh4gahBJ4eY1kiX6LgDN7fBmQEJI4jhieD4yhdJ2KkZk8oiSqEaatqBekDLKztBG2CqBACq4wJRi4PZu1sA2+v8C6EJexrBAD1AOBzsLE0g/V1UvYR9sN3eR6lTLi4+TlY1wz6Qzr8u1t6FkY8vNzZTxaGfn6mAkEGFDgL4LrDDJDyE4hEIbdHB6ESE1iD4oVLfLAqPETIsOODwmCDJlv5MSGJklaS6khAQAh+QQFBQAEACwfAAIAVwAwAAAD/0i63P5LSAGrvTjrNuf+YKh1nWieIumhbFupkivPBEzR+GnnfLj3ooFwwPqdAshAazhEGUXJJIrJ1MGOUamJ2jQ9QVltkCv0XqFh5IncBX01afGYnDqD40u2z76JK/N0bnxweC5sRB9vF34zh4gjg4uMjXobihWTlJUZlw9+fzSHlpGYhTminKSepqebF50NmTyor6qxrLO0L7YLn0ALuhCwCrJAjrUqkrjGrsIkGMW/BMEPJcphLgDaABjUKNEh29vdgTLLIOLpF80s5xrp8ORVONgi8PcZ8zlRJvf40tL8/QPYQ+BAgjgMxkPIQ6E6hgkdjoNIQ+JEijMsasNY0RQix4gKP+YIKXKkwJIFF6JMudFEAgAh+QQFBQAEACw8AAIAQgBCAAAD/kg0PPowykmrna3dzXvNmSeOFqiRaGoyaTuujitv8Gx/661HtSv8gt2jlwIChYtc0XjcEUnMpu4pikpv1I71astytkGh9wJGJk3QrXlcKa+VWjeSPZHP4Rtw+I2OW81DeBZ2fCB+UYCBfWRqiQp0CnqOj4J1jZOQkpOUIYx/m4oxg5cuAaYBO4Qop6c6pKusrDevIrG2rkwptrupXB67vKAbwMHCFcTFxhLIt8oUzLHOE9Cy0hHUrdbX2KjaENzey9Dh08jkz8Tnx83q66bt8PHy8/T19vf4+fr6AP3+/wADAjQmsKDBf6AOKjS4aaHDgZMeSgTQcKLDhBYPEswoA1BBAgAh+QQFBQAEACxOAAoAMABXAAAD7Ei6vPOjyUkrhdDqfXHm4OZ9YSmNpKmiqVqykbuysgvX5o2HcLxzup8oKLQQix0UcqhcVo5ORi+aHFEn02sDeuWqBGCBkbYLh5/NmnldxajX7LbPBK+PH7K6narfO/t+SIBwfINmUYaHf4lghYyOhlqJWgqDlAuAlwyBmpVnnaChoqOkpaanqKmqKgGtrq+wsbA1srW2ry63urasu764Jr/CAb3Du7nGt7TJsqvOz9DR0tPU1TIA2ACl2dyi3N/aneDf4uPklObj6OngWuzt7u/d8fLY9PXr9eFX+vv8+PnYlUsXiqC3c6PmUUgAACH5BAUFAAQALE4AHwAwAFcAAAPpSLrc/m7IAau9bU7MO9GgJ0ZgOI5leoqpumKt+1axPJO1dtO5vuM9yi8TlAyBvSMxqES2mo8cFFKb8kzWqzDL7Xq/4LB4TC6bz1yBes1uu9uzt3zOXtHv8xN+Dx/x/wJ6gHt2g3Rxhm9oi4yNjo+QkZKTCgGWAWaXmmOanZhgnp2goaJdpKGmp55cqqusrZuvsJays6mzn1m4uRAAvgAvuBW/v8GwvcTFxqfIycA3zA/OytCl0tPPO7HD2GLYvt7dYd/ZX99j5+Pi6tPh6+bvXuTuzujxXens9fr7YPn+7egRI9PPHrgpCQAAIfkEBQUABAAsPAA8AEIAQgAAA/lIutz+UI1Jq7026h2x/xUncmD5jehjrlnqSmz8vrE8u7V5z/m5/8CgcEgsGo/IpHLJbDqf0Kh0ShBYBdTXdZsdbb/Yrgb8FUfIYLMDTVYz2G13FV6Wz+lX+x0fdvPzdn9WeoJGAYcBN39EiIiKeEONjTt0kZKHQGyWl4mZdREAoQAcnJhBXBqioqSlT6qqG6WmTK+rsa1NtaGsuEu6o7yXubojsrTEIsa+yMm9SL8osp3PzM2cStDRykfZ2tfUtS/bRd3ewtzV5pLo4eLjQuUp70Hx8t9E9eqO5Oku5/ztdkxi90qPg3x2EMpR6IahGocPCxp8AGtigwQAIfkEBQUABAAsHwBOAFcAMAAAA/9Iutz+MMo36pg4682J/V0ojs1nXmSqSqe5vrDXunEdzq2ta3i+/5DeCUh0CGnF5BGULC4tTeUTFQVONYAs4CfoCkZPjFar83rBx8l4XDObSUL1Ott2d1U4yZwcs5/xSBB7dBMBhgEYfncrTBGDW4WHhomKUY+QEZKSE4qLRY8YmoeUfkmXoaKInJ2fgxmpqqulQKCvqRqsP7WooriVO7u8mhu5NacasMTFMMHCm8qzzM2RvdDRK9PUwxzLKdnaz9y/Kt8SyR3dIuXmtyHpHMcd5+jvWK4i8/TXHff47SLjQvQLkU+fG29rUhQ06IkEG4X/Rryp4mwUxSgLL/7IqFETB8eONT6ChCFy5ItqJomES6kgAQAh+QQFBQAEACwKAE4AVwAwAAAD/0i63A4QuEmrvTi3yLX/4MeNUmieITmibEuppCu3sDrfYG3jPKbHveDktxIaF8TOcZmMLI9NyBPanFKJp4A2IBx4B5lkdqvtfb8+HYpMxp3Pl1qLvXW/vWkli16/3dFxTi58ZRcChwIYf3hWBIRchoiHiotWj5AVkpIXi4xLjxiaiJR/T5ehoomcnZ+EGamqq6VGoK+pGqxCtaiiuJVBu7yaHrk4pxqwxMUzwcKbyrPMzZG90NGDrh/JH8t72dq3IN1jfCHb3L/e5ebh4ukmxyDn6O8g08jt7tf26ybz+m/W9GNXzUQ9fm1Q/APoSWAhhfkMAmpEbRhFKwsvCsmosRIHx444PoKcIXKkjIImjTzjkQAAIfkEBQUABAAsAgA8AEIAQgAAA/VIBNz+8KlJq72Yxs1d/uDVjVxogmQqnaylvkArT7A63/V47/m2/8CgcEgsGo/IpHLJbDqf0Kh0Sj0FroGqDMvVmrjgrDcTBo8v5fCZki6vCW33Oq4+0832O/at3+f7fICBdzsChgJGeoWHhkV0P4yMRG1BkYeOeECWl5hXQ5uNIAOjA1KgiKKko1CnqBmqqk+nIbCkTq20taVNs7m1vKAnurtLvb6wTMbHsUq4wrrFwSzDzcrLtknW16tI2tvERt6pv0fi48jh5h/U6Zs77EXSN/BE8jP09ZFA+PmhP/xvJgAMSGBgQINvEK5ReIZhQ3QEMTBLAAAh+QQFBQAEACwCAB8AMABXAAAD50i6DA4syklre87qTbHn4OaNYSmNqKmiqVqyrcvBsazRpH3jmC7yD98OCBF2iEXjBKmsAJsWHDQKmw571l8my+16v+CweEwum8+hgHrNbrvbtrd8znbR73MVfg838f8BeoB7doN0cYZvaIuMjY6PkJGSk2gClgJml5pjmp2YYJ6dX6GeXaShWaeoVqqlU62ir7CXqbOWrLafsrNctjIDwAMWvC7BwRWtNsbGFKc+y8fNsTrQ0dK3QtXAYtrCYd3eYN3c49/a5NVj5eLn5u3s6e7x8NDo9fbL+Mzy9/T5+tvUzdN3Zp+GBAAh+QQJBQAEACwCAAIAfAB8AAAD/0i63P4wykmrvTjrzbv/YCiOZGmeaKqubOu+cCzPdArcQK2TOL7/nl4PSMwIfcUk5YhUOh3M5nNKiOaoWCuWqt1Ou16l9RpOgsvEMdocXbOZ7nQ7DjzTaeq7zq6P5fszfIASAYUBIYKDDoaGIImKC4ySH3OQEJKYHZWWi5iZG0ecEZ6eHEOio6SfqCaqpaytrpOwJLKztCO2jLi1uoW8Ir6/wCHCxMG2x7muysukzb230M6H09bX2Nna29zd3t/g4cAC5OXm5+jn3Ons7eba7vHt2fL16tj2+QL0+vXw/e7WAUwnrqDBgwgTKlzIsKHDh2gGSBwAccHEixAvaqTYcFCjRoYeNyoM6REhyZIHT4o0qPIjy5YTTcKUmHImx5cwE85cmJPnSYckK66sSAAj0aNIkypdyrSp06dQo0qdSrWq1atYs2rdyrWr169gwxZJAAA7' diff --git a/packages/taro-components-qa/src/components/taro-button/index.ux b/packages/taro-components-qa/src/components/taro-button/index.ux new file mode 100644 index 000000000000..a9a09a574493 --- /dev/null +++ b/packages/taro-components-qa/src/components/taro-button/index.ux @@ -0,0 +1,115 @@ + + + + + From 71d4bfae0cd344121b4ce5de579c329a326c4994 Mon Sep 17 00:00:00 2001 From: jinjinjin0731 <709899428@qq.com> Date: Fri, 19 Apr 2019 15:38:56 +0800 Subject: [PATCH 099/103] =?UTF-8?q?fix(compontens-qa):=20husky=20=E8=AF=AF?= =?UTF-8?q?=E5=88=A0=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 0279702f6128..e24781af94da 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,12 @@ "git add" ] }, - + "husky": { + "hooks": { + "commit-msg": "commitlint -E HUSKY_GIT_PARAMS", + "pre-commit": "lint-staged" + } + }, "keywords": [ "nerv", "taro" From 9bf4266d809131a545353474102b76be545f48b9 Mon Sep 17 00:00:00 2001 From: luckyadam Date: Wed, 17 Apr 2019 17:38:03 +0800 Subject: [PATCH 100/103] =?UTF-8?q?feat(cli):=20=E5=BF=AB=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E7=BC=96=E8=AF=91=E6=97=B6=E9=9C=80=E8=A6=81=E4=BC=A0?= =?UTF-8?q?=E5=85=A5=E6=A0=B9=E8=8A=82=E7=82=B9=E9=9C=80=E8=A6=81=E7=9A=84?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro-cli/src/mini/page.ts | 26 +++++++++++++++++-- packages/taro-cli/src/util/constants.ts | 1 - .../src/components/taro-page/index.ux | 8 ++++-- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/taro-cli/src/mini/page.ts b/packages/taro-cli/src/mini/page.ts index a93291ab3dfd..fd045e5e304f 100644 --- a/packages/taro-cli/src/mini/page.ts +++ b/packages/taro-cli/src/mini/page.ts @@ -55,7 +55,8 @@ export async function buildSinglePage (page: string) { outputFilesTypes, nodeModulesPath, npmOutputDir, - pageConfigs + pageConfigs, + appConfig } = getBuildData() const pagePath = path.join(sourceDir, `${page}`) const pageJs = resolveScriptPath(pagePath) @@ -92,6 +93,26 @@ export async function buildSinglePage (page: string) { return } try { + const rootProps: { [key: string]: any } = {} + if (isQuickApp) { + // 如果是快应用,需要提前解析一次 ast,获取 config + const aheadTransformResult: IWxTransformResult = wxTransformer({ + code: pageJsContent, + sourcePath: pageJs, + outputPath: outputPageJSPath, + isRoot: true, + isTyped: REG_TYPESCRIPT.test(pageJs), + adapter: buildAdapter, + env: constantsReplaceList + }) + const res = parseAst(PARSE_AST_TYPE.PAGE, aheadTransformResult.ast, [], pageJs, outputPageJSPath) + if (res.configObj.enablePullDownRefresh || (appConfig.window && appConfig.window.enablePullDownRefresh)) { + rootProps.enablePullDownRefresh = true + } + if (appConfig.tabBar) { + rootProps.tabBar = appConfig.tabBar + } + } const transformResult: IWxTransformResult = wxTransformer({ code: pageJsContent, sourcePath: pageJs, @@ -99,7 +120,8 @@ export async function buildSinglePage (page: string) { isRoot: true, isTyped: REG_TYPESCRIPT.test(pageJs), adapter: buildAdapter, - env: constantsReplaceList + env: constantsReplaceList, + rootProps }) const pageDepComponents = transformResult.components const pageWXMLContent = isProduction ? transformResult.compressedTemplate : transformResult.template diff --git a/packages/taro-cli/src/util/constants.ts b/packages/taro-cli/src/util/constants.ts index 59a38af14f71..20473346f422 100644 --- a/packages/taro-cli/src/util/constants.ts +++ b/packages/taro-cli/src/util/constants.ts @@ -230,7 +230,6 @@ export const CONFIG_MAP = { navigationBarTextStyle: 'titleBarTextColor', pageOrientation: 'orientation', backgroundTextStyle: false, - enablePullDownRefresh: false, list: false, text: false, iconPath: false, diff --git a/packages/taro-components-qa/src/components/taro-page/index.ux b/packages/taro-components-qa/src/components/taro-page/index.ux index 30ab0aacb008..818fbfd1d8e2 100644 --- a/packages/taro-components-qa/src/components/taro-page/index.ux +++ b/packages/taro-components-qa/src/components/taro-page/index.ux @@ -1,6 +1,6 @@