diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bd4f5c52..a2696e41 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,3 @@ # MorJS 贡献指南 -参见文档 [website/docs/guides/contributing.md](website/docs/guides/contributing.md)。 +参见文档 [参与贡献](https://mor.ele.me/guides/contributing)。 diff --git a/README.md b/README.md index dcc3ef11..6cddb7ab 100644 --- a/README.md +++ b/README.md @@ -60,13 +60,13 @@ Mor 是一套基于小程序 DSL (支付宝或微信) 的框架。他的易用 ## 贡献 -参见 [贡献指南](https://github.com/eleme/morjs/blob/master/CONTRIBUTING.md) +参见 [参与贡献](https://mor.ele.me/guides/contributing) ## 社区 参见 [社区指南](https://mor.ele.me/about/community-guide) - + ### 核心成员 @@ -77,6 +77,7 @@ Mor 是一套基于小程序 DSL (支付宝或微信) 的框架。他的易用 - [hwaphon](https://github.com/hwaphon) - [shujian-cao](https://github.com/shujian-cao) - [robin-shine](https://github.com/robin-shine) +- [aboyforwind](https://github.com/aboyforwind) ## 许可证 diff --git a/website/README.md b/website/README.md deleted file mode 100644 index 2de5ed7a..00000000 --- a/website/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# MorJS 站点 - -## 框架 - -站点采用 [Docusaurus 2](https://docusaurus.io/) 框架,要求 node 版本 >=16.14 - -- Installation: `$ npm install` -- Development: `$ npm run start` -- Build: `$ npm run build` -- Version: `npx docusaurus docs:version 1.1.0` - -> 发完版本号 Version 后需要修改一下 `docusaurus.config.js` 配置文件的 `onlyIncludeVersions` 相关配置项 - -## 配置 - -- 主要配置文件 `docusaurus.config.js` -- 头部导航配置 `config/navbar.js` -- 底部超链配置 `config/footer.js` -- 文档分组配置 `config/sidebars.js` - -## 发布 - -使用 gh-pages 分支为文档专用分支,使用 Github Actions 自动部署 diff --git a/website/algolia.json b/website/algolia.json deleted file mode 100644 index b75f197c..00000000 --- a/website/algolia.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "index_name": "morjs", - "start_urls": ["https://mor.eleme.io"], - "sitemap_urls": ["https://mor.eleme.io/sitemap.xml"], - "selectors": { - "lvl0": { - "selector": "(//ul[contains(@class,'menu__list')]//a[contains(@class, 'menu__link menu__link--sublist menu__link--active')]/text() | //nav[contains(@class, 'navbar')]//a[contains(@class, 'navbar__link--active')]/text())[last()]", - "type": "xpath", - "global": true, - "default_value": "Documentation" - }, - "lvl1": "header h1, article h1", - "lvl2": "article h2", - "lvl3": "article h3", - "lvl4": "article h4", - "lvl5": "article h5, article td:first-child", - "lvl6": "article h6", - "text": "article p, article li, article td:last-child" - }, - "custom_settings": { - "attributesForFaceting": [ - "type", - "lang", - "language", - "version", - "docusaurus_tag" - ], - "attributesToRetrieve": [ - "hierarchy", - "content", - "anchor", - "url", - "url_without_anchor", - "type" - ], - "attributesToHighlight": ["hierarchy", "content"], - "attributesToSnippet": ["content:10"], - "camelCaseAttributes": ["hierarchy", "content"], - "searchableAttributes": [ - "unordered(hierarchy.lvl0)", - "unordered(hierarchy.lvl1)", - "unordered(hierarchy.lvl2)", - "unordered(hierarchy.lvl3)", - "unordered(hierarchy.lvl4)", - "unordered(hierarchy.lvl5)", - "unordered(hierarchy.lvl6)", - "content" - ], - "distinct": true, - "attributeForDistinct": "url", - "customRanking": [ - "desc(weight.pageRank)", - "desc(weight.level)", - "asc(weight.position)" - ], - "ranking": [ - "words", - "filters", - "typo", - "attribute", - "proximity", - "exact", - "custom" - ], - "highlightPreTag": "", - "highlightPostTag": "", - "minWordSizefor1Typo": 3, - "minWordSizefor2Typos": 7, - "allowTyposOnNumericTokens": false, - "minProximity": 1, - "ignorePlurals": true, - "advancedSyntax": true, - "attributeCriteriaComputedByMinProximity": true, - "removeWordsIfNoResults": "allOptional", - "separatorsToIndex": "_", - "synonyms": [ - ["js", "javascript"], - ["ts", "typescript"] - ] - } -} \ No newline at end of file diff --git a/website/babel.config.js b/website/babel.config.js deleted file mode 100644 index 14e5baf0..00000000 --- a/website/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: [require.resolve('@docusaurus/core/lib/babel/preset')] -} diff --git a/website/config/footer.js b/website/config/footer.js deleted file mode 100644 index fd9a4917..00000000 --- a/website/config/footer.js +++ /dev/null @@ -1,38 +0,0 @@ -module.exports = { - style: 'dark', - links: [ - { - title: '文档', - items: [ - { label: 'MorJS 配置', href: '/guides/basic/config' }, - { label: '命令行', href: '/guides/basic/cli' }, - { label: '工程 Hooks', href: '/api/engineering-hooks' } - ], - }, - { - title: '帮助', - items: [ - { label: '常见问题', href: '/guides/faq' }, - { - label: '社区钉钉群', - href: 'https://qr.dingtalk.com/action/joingroup?code=v1,k1,zPirp4W1FDF7tKteTDgOjgk7cMzCTt31ztWoGVMVJ7U=&_dt_no_comment=1&origin=11' - }, - { label: 'GitHub Issue', href: 'https://github.com/eleme/morjs/issues' } - ], - }, - { - title: '更多', - items: [ - { - label: '行为规范', - to: 'https://github.com/eleme/morjs/blob/master/CODE_OF_CONDUCT.md' - }, - { - label: '参与贡献', - href: 'https://github.com/eleme/morjs/blob/master/CONTRIBUTING.md' - } - ] - } - ], - copyright: `Copyright © ${new Date().getFullYear()} - Present MorJS.` -} diff --git a/website/config/navbar.js b/website/config/navbar.js deleted file mode 100644 index 4fd5737b..00000000 --- a/website/config/navbar.js +++ /dev/null @@ -1,31 +0,0 @@ -module.exports = { - title: 'MorJS', - logo: { - alt: 'MorJS', - src: 'https://img.alicdn.com/imgextra/i1/O1CN017EoZuR20PghATY7Fw_!!6000000006842-55-tps-485-350.svg' - }, - items: [ - { label: '文档', position: 'left', to: 'guides' }, - { label: 'API', position: 'left', to: 'api' }, - { label: '博客', position: 'left', to: 'web/blog' }, - { - label: '关于', - position: 'left', - items: [ - { label: '常见问题', to: '/guides/faq' }, - // { label: '版本发布', to: '/changelog/1.0.0' }, - { label: '社区指南', to: '/about/community-guide' }, - { - label: '行为规范', - to: 'https://github.com/eleme/morjs/blob/master/CODE_OF_CONDUCT.md' - } - ] - }, - { type: 'docsVersionDropdown', position: 'right' }, - { - className: 'header-github-link', - position: 'right', - href: 'https://github.com/eleme/morjs' - } - ] -} diff --git a/website/config/sidebars.js b/website/config/sidebars.js deleted file mode 100644 index 4599278b..00000000 --- a/website/config/sidebars.js +++ /dev/null @@ -1,209 +0,0 @@ -module.exports = { - documentSidebar: [ - { - label: '指南', - type: 'category', - collapsed: false, - items: [ - { - label: '介绍', - type: 'category', - collapsed: false, - items: ['guides/README', 'guides/introduction/how-mor-works'] - }, - { - label: '教程', - type: 'category', - collapsed: false, - items: [ - 'guides/introduction/getting-started', - { - label: '开发一个 To-Do List', - type: 'category', - collapsed: true, - items: [ - 'guides/introduction/how-to-develop-todo-list_wechat', - 'guides/introduction/how-to-develop-todo-list' - ] - }, - 'guides/migrate-from-original-miniprogram-to-mor' - ] - }, - { - label: '基础用法', - type: 'category', - collapsed: false, - items: [ - 'guides/basic/directory-structure', - 'guides/basic/config', - 'guides/basic/runtime', - 'guides/basic/plugin', - 'guides/basic/mock', - 'guides/basic/env-variables', - 'guides/basic/cli', - 'guides/faq' - ] - }, - { - label: '进阶用法', - type: 'category', - collapsed: false, - items: [ - { - label: '条件编译', - type: 'category', - collapsed: true, - items: [ - 'guides/conditional-compile/code-level', - 'guides/conditional-compile/file-level' - ] - }, - 'guides/advance/complex-miniprogram-integration', - 'guides/advance/unity-of-forms' - ] - }, - { - label: '多端兼容性', - type: 'category', - collapsed: true, - items: [ - 'guides/compatibilities/wechat-to-other', - 'guides/compatibilities/alipay-to-wechat' - ] - } - ] - }, - { - label: 'Web 开发', - type: 'category', - collapsed: true, - items: [ - { - label: '介绍', - type: 'category', - collapsed: true, - items: ['web/basic/quickstart', 'web/basic/support'] - }, - { - label: '基础使用', - type: 'category', - collapsed: true, - items: ['web/introduction/basic', 'web/introduction/route'] - }, - { - label: '其它用法', - type: 'category', - collapsed: true, - items: ['web/support/custom-my', 'web/support/tabbar-support'] - } - ] - }, - { - label: '社区', - type: 'category', - collapsed: true, - items: [ - 'guides/contributing', - 'about/community-guide', - { - label: '规范', - type: 'category', - collapsed: true, - items: [ - { - label: '介绍', - type: 'category', - collapsed: true, - items: ['specifications/README'] - }, - { - label: '研发规范', - type: 'category', - collapsed: true, - items: [ - // 'specifications/development', - 'specifications/code-styles', - 'specifications/git-commit-and-review' - ] - }, - { - label: '技术规范', - type: 'category', - collapsed: true, - items: [ - 'specifications/js', - 'specifications/component', - 'specifications/runtime' - // 'specifications/plugin' - ] - }, - { - label: '文档规范', - type: 'category', - collapsed: true, - items: ['specifications/document'] - } - ] - } - ] - } - ], - apiSidebar: [ - { - label: '介绍', - type: 'category', - collapsed: false, - items: ['api/README'] - }, - { - label: '工程 API', - type: 'category', - collapsed: false, - items: [ - 'api/engineering-hooks', - 'api/takin', - 'api/engineering-takin', - 'api/engineering-mor' - ] - }, - { - label: '运行时 API', - type: 'category', - collapsed: false, - items: ['api/runtime-core', 'api/runtime-hooks', 'api/runtime-api'] - } - ], - blogSidebar: [ - { - label: 'Web 转端原理介绍', - type: 'category', - collapsed: false, - items: [ - 'web/blog/index', - 'web/blog/runtime', - 'web/blog/setdata', - 'web/blog/event', - 'web/blog/template', - 'web/blog/slot' - ] - }, - { - label: 'MorJS 开发博客', - type: 'category', - collapsed: false, - items: [ - 'guides/advance/use-community-component', - 'guides/advance/learn-create-component-library', - 'guides/advance/subpackage-volume-optimization' - ] - } - // { - // label: 'MorJS 更新日志', - // type: 'category', - // collapsed: false, - // items: [ - // 'changelog/1.0.0', - // ] - // } - ] -} diff --git a/website/docs/about/community-guide.md b/website/docs/about/community-guide.md deleted file mode 100644 index 41339455..00000000 --- a/website/docs/about/community-guide.md +++ /dev/null @@ -1,56 +0,0 @@ -# 社区指南 - -MorJS 的社区正在逐步成长中,如果你正在阅读本文,这说明你大概已经准备好加入 MorJS 社区了。欢迎! - -现在让我们来解答你能从社区中获得什么以及你能为社区做什么。 - -
- -## 资源 - -### 行为规范 - -这份 [行为规范](https://github.com/eleme/morjs/blob/master/CODE_OF_CONDUCT.md) 是一个易于发展我们所参与的技术社区的指南。 - -### 保持关注 - -- 关注我们的官方 [GitHub](https://github.com/eleme) 账号。 -- 关注我们的团队成员的 GitHub 账号。 -- 加入我们的社区钉钉群以获得最新消息。 - -### 获得帮助 - -GitHub:如果你想报告 bug 或者提出新特性需求,欢迎来 GitHub 提交 issue。我们也非常欢迎 pull request! -社区钉钉群:一个 MorJS 开发者相互认识和实时聊天的地方。 - -
- -## 参与方式 - -### 帮助同伴用户 - -贡献代码并不是对 MorJS 社区的唯一贡献形式。在 钉钉群 或 Github 上为 MorJS 的同伴回答问题也是一种非常有价值的贡献。 - -### 协助分流 Issue - -分流 issue 意味着收集缺失的信息、重现问题、验证问题的有效性并调查问题的原因等。 - -我们每天都会在 GitHub 仓库收到许多 issue。和我们的用户数量相比,我们的精力是非常有限的,所以光是 issue 的分流就会花费团队大量的精力。通过帮助我们分流这些 issue,你可以帮助我们变得更有效率,使我们能够把时间花在更优先的工作上。 - -你不必以修复问题为目的来分流这些 issue (尽管那也很好)。分享你的调查结果,例如导致该错误的提交记录,已经为我们节省了大量的时间。 - -### 贡献代码 - -贡献错误修复或新特性是你能做出的最直接的贡献形式。 - -MorJS 核心库提供了一份贡献指南,其中包含 pull request 指南以及有关构建设置和上层架构的信息,请确保在提交 pull request 之前阅读它们。 - -错误修复是我们随时欢迎的。而对于新特性来说,最好先在社区群里讨论用例和实现细节。 - -### 分享 (并积累) 经验 - -除了在 Github 或钉钉群回答问题、分享资源外,还有一些其他的方式可以分享并增长你的见识: - -开发学习资料。我们常说教学相长。如果你正在用 MorJS 做一些有趣的事情,你可以写一篇博客、组织研讨会、甚至创建一个 gist 分享到社交平台上:这些都能加强你的专项知识。 - -关注 (watch) 你关心的仓库。这样无论何时该仓库有新的动静,你都会第一时间收到通知,得到关于正在进行的讨论以及即将到来的新特性的新鲜情报。这是超棒的积累专业知识的方法,你最终将会有能力来解决问题 (issue) 并提交 pull request。 diff --git a/website/docs/api/README.md b/website/docs/api/README.md deleted file mode 100644 index 4c0d78e0..00000000 --- a/website/docs/api/README.md +++ /dev/null @@ -1,85 +0,0 @@ -# API 介绍 - -MorJS 提供了大量 API 给 编译时运行时 使用,共分为 工程 API运行时 API 两类 - -## 工程 API - -提供给编译流程及命令行使用,包括以下三类: - -- `Hooks`: mor 和 takin 对外暴露的 hook,提供给工程插件使用,下面以 `modifyUserConfig` 示例 - -```typescript -import type { Plugin, Runner } from '@morjs/cli' - -export default class MorJSPluginXXX implements Plugin { - name = 'MorJSPluginXXX' - - apply(runner: Runner) { - // modifyUserConfig: 可基于命令行选项修改用户配置 - runner.hooks.modifyUserConfig.tap(this.name, (userConfig, command) => { - const { outputPath } = command.options - // 获取命令行 outputPath 选项,若有则修改 userConfig 的 outputPath 配置为该值 - if (outputPath) userConfig.outputPath = outputPath - return userConfig - }) - } -} -``` - -- `Takin API`: 由 takin 提供的 api,下面以 `logger.info` 示例 - -```typescript -import { logger } from '@morjs/cli' - -logger.info('info 日志输出') -``` - -- `MorJS API`: mor 的 utils 对外开放的 api,下面以 `hexToRgb` 示例 - -```typescript -import { hexToRgb } from '@morjs/cli' - -const colorRGB = hexToRgb('#FFFFFF') -``` - -## 运行时 API - -提供给运行时流程使用,包括以下三类: - -- `Runtime Core`: mor 的 api 对外开放的 api,下面以 `aApp` 示例 - -```typescript -import { aApp } from '@morjs/core' - -aApp({ - onLaunch() { - console.log('app onlaunch') - } -}) -``` - -- `Runtime Hooks`: mor 运行时对应小程序的 hook,提供给运行时插件使用,下面以 `appOnShow` 示例 - -```typescript -import type { MorJSHooks, MorJSPlugin } from '@morjs/api' - -export default class RuntimePluginXXX implements MorJSPlugin { - pluginName = 'RuntimePluginXXX' - - apply = (morHooks: MorJSHooks): void => { - // appOnShow: 在 App 的 onShow 生命周期触发 - morHooks.appOnShow.tap(this.pluginName, function (this, options) { - console.log('触发小程序 appOnShow 生命周期') - }) - } -} -``` - -- `Runtime API`: mor 的 core 对外开放的 api,下面以 `getGlobalObject` 示例 - -```typescript -import { getGlobalObject } from '@morjs/api' - -const global = getGlobalObject() -console.log(global) // my(支付宝)| wx(微信) -``` diff --git a/website/docs/api/engineering-hooks.md b/website/docs/api/engineering-hooks.md deleted file mode 100644 index 8d808484..00000000 --- a/website/docs/api/engineering-hooks.md +++ /dev/null @@ -1,376 +0,0 @@ -# Hooks - -## 介绍 - -- 在插件的 `apply` 函数中,会得到一个 `runner` 对象,对象中会有如下 `takin` 提供的内置 `hook`,插件可使用 `tap` 来注册对应的 `hook`,`tap` 接受两个参数 - - - `name`: 插件名 - - `pluginHandle`: 插件逻辑 - -- 若插件有设置参数 `IMorJSPluginXXXOptions`,请将 `options` 的 `interface` 给 `export` 出去,方便可能需要集成的使用方进行引用 - -## 基础 Hooks - -```typescript -import type { Plugin, Runner, UserConfig } from '@morjs/cli' - -export interface IMorJSPluginXXXOptions { - key: value -} - -export default class MorJSPluginXXX implements Plugin { - name = 'MorJSPluginXXX' - pluginOptions: IMorJSPluginXXXOptions - - constructor(options?: IMorJSPluginXXXOptions) { - this.pluginOptions = { - ...options - } - } - - apply(runner: Runner) { - // initialize: 初始化, 当 runner 被初始化并完成插件加载之后运行 - runner.hooks.initialize.tap(this.name, () => { - // 打印当前 MorJS 版本 - console.log(`当前 MorJS 版本为 1.0.0 ⚑`) - }) - - // cli: 构建命令行时运行,可运行命令行注册,获取匹配的命令 - runner.hooks.cli.tap(this.name, (cli) => { - // 注册 abc 命令行并添加一个 cde 的选项,于是终端可执行 mor abc --cde 123 命令 - cli.command('abc', 'abc描述').option('--cde [xxx]', 'cde描述') - }) - - // matchedCommand: 获取到匹配命令的阶段 - runner.hooks.matchedCommand.tap(this.name, (command) => { - const { name, outputPath } = command.options - console.log(name, outputPath) // 获取命令行选项 - }) - - // loadConfig: 加载用户 config 阶段 - runner.hooks.loadConfig.tap(this.name, (command) => { - const { name, outputPath } = command.options - console.log(name, outputPath) - }) - - // modifyUserConfig: 可基于命令行选项修改用户配置 - runner.hooks.modifyUserConfig.tap(this.name, (userConfig, command) => { - const { outputPath } = command.options - // 获取命令行 outputPath 选项,若有则修改 userConfig 的 outputPath 配置为该值 - if (outputPath) userConfig.outputPath = outputPath - return userConfig - }) - - // registerUserConfig: 注册用户配置及校验 schema - runner.hooks.registerUserConfig.tap(this.name, (schema) => { - return schema.merge(UserConfigSchema) - }) - - // shouldRun: 是否需要运行后续逻辑(执行的时机为 校验用户配置之前) - runner.hooks.shouldRun.tap(this.name, () => { - return true - }) - - // shouldValidateUserConfig: 是否校验用户配置, 部分不使用配置的命令 - // 可使用该 hook 结合 runner 的上下文,来选择是否跳过用户配置校验 - runner.hooks.shouldValidateUserConfig.tap(this.name, () => { - if (runner.commandName === 'clean') return false - }) - - // userConfigValidated: 用户配置校验完成之后执行 - runner.hooks.userConfigValidated.tap(this.name, (userConfig) => { - // 这个阶段可以进行部分配置,如添加 mor 运行时相关 loader 处理 - console.log(userConfig) - }) - - // beforeRun: 开始 run 之前的 hook, 可用于准备一些运行命令需要的数据或内容 - runner.hooks.beforeRun.tap(this.name, () => { - const userConfig = runner.userConfig - console.log(userConfig) - }) - - // run: 运行命令逻辑 - runner.hooks.run.tap(this.name, (command) => {}) - - // done: runner 运行完成 - runner.hooks.done.tap(this.name, () => { - console.log(`编译完成`) - }) - - // failed: runner 运行失败 - runner.hooks.failed.tap(this.name, (error) => { - console.log('运行失败, 原因:', error) - }) - - // shutdown: runner 主动关闭 runner 时执行 - runner.hooks.shutdown.tap(this.name, () => { - // runner 关闭时自动关闭 server - if (devServer) await devServer.stop() - devServer = null - }) - } -} -``` - -## 编译 Hooks - -```typescript -import type { Plugin, Runner, UserConfig } from '@morjs/cli' - -export interface IMorJSPluginXXXOptions { - key: value -} - -export default class MorJSPluginXXX implements Plugin { - name = 'MorJSPluginXXX' - pluginOptions: IMorJSPluginXXXOptions - - constructor(options?: IMorJSPluginXXXOptions) { - this.pluginOptions = { - ...options - } - } - - apply(runner: Runner) { - // webpackWrapper: 用于获取 webpackWrapper - runner.hooks.webpackWrapper.tap(this.name, (webpackWrapper) => { - // 保存 webpackWrapper 提供给后续流程调用 - this.webpackWrapper = webpackWrapper - }) - - // compiler: 用于获取 webpack compiler - runner.hooks.compiler.tap(this.name, (compiler) => { - const userConfig = runner.userConfig - console.log(userConfig) - }) - - // entryBuilder: 用于获取 entryBuilder - runner.hooks.entryBuilder.tap(this.name, (entryBuilder) => { - this.entryBuilder = entryBuilder - }) - - // shouldAddPageOrComponent: 用于判断是否要处理页面或组件 - runner.hooks.shouldAddPageOrComponent.tap(this.name, (pageOrComponent) => { - if (pageOrComponent.startsWith('dynamicLib://')) return false - return true - }) - - // addEntry: 添加 entry 时触发, 可用于修改 entry 相关信息 - runner.hooks.addEntry.tap(this.name, (entryInfo) => { - // 把 'pages/main/' 页面的产物放到 'src/pages/main' 下 - if (entryInfo.name && entryInfo.name.startsWith('pages/main/')) { - entryInfo.entry.fullEntryName = 'src/' + entryInfo.entry.fullEntryName - entryInfo.entry.entryName = 'src/' + entryInfo.entry.entryName - entryInfo.entry.entryDir = 'src/' + entryInfo.entry.entryDir - entryInfo.name = 'src/' + entryInfo.name - } - - return entryInfo - }) - - // beforeBuildEntries: 解析所有 entries 文件之后, 生成 entries 之前执行 - runner.hooks.beforeBuildEntries.tap(this.name, (entryBuilder) => { - EntryBuilderMap.set(runner, entryBuilder) - }) - - // afterBuildEntries: 用于获取并修改构建出来的 entries - runner.hooks.afterBuildEntries.tap(this.name, (entries, entryBuilder) => { - this.entryBuilder = entryBuilder - return entries - }) - - // configParser: config(json) 文件解析 hook - runner.hooks.configParser.tap(this.name, (config, options) => { - // 删除抖音编译下,所有 json 文件的 componentPlaceholder 内容 - if (options.userConfig.target === 'bytedance') { - if (config?.componentPlaceholder) { - delete config.componentPlaceholder - } - } - return config - }) - - // scriptParser: script(js/ts) 文件解析 hook - runner.hooks.scriptParser.tap(this.name, (transformers, options) => { - // 给 app.ts 文件的 CApp({}) 方法插入 { globalApp: morGlobal.initApp } 作为最后一个参数 - if (!options.fileInfo.content?.includes('CApp')) return transformers - - transformers = transformers || {} - transformers.before = transformers.before || [] - - const transformer = tsTransformerFactory((node, context) => { - const factory = context.factory - if ( - ts.isExpressionStatement(node) && - ts.isCallExpression(node.expression) && - ts.isIdentifier(node.expression.expression) && - node.expression.expression.escapedText === 'CApp' - ) { - args.push( - factory.createObjectLiteralExpression( - [ - factory.createPropertyAssignment( - factory.createIdentifier('globalApp'), - factory.createPropertyAccessExpression( - factory.createIdentifier('morGlobal'), - factory.createIdentifier('initApp') - ) - ) - ], - false - ) - ) - - return [ - factory.createExpressionStatement( - factory.createCallExpression( - factory.createIdentifier('CApp'), - undefined, - [...node.expression.arguments, ...args] - ) - ) - ] - } - - return node - }) - - transformers.before.push(transformer) - return transformers - }) - - // templateParser: template(*xml) 文件解析 hook - runner.hooks.templateParser.tap(this.name, (tree, options) => { - // 替换 wxml 中的 morstyle 为 style - return tree.walk((node) => { - if (node.attrs && node.attrs.morStyle) { - node.attrs.style = node.attrs.morStyle - delete node.attrs.morStyle - } - - return node - }) - }) - - // styleParser: style(*css) 文件解析 hook - runner.hooks.styleParser.tap(this.name, (plugins, options) => { - return plugins - .concat - // 进行一些关于 *css 文件的处理 - () - }) - - // sjsParser: sjs(wxs/sjs) 文件解析 hook - runner.hooks.sjsParser.tap(this.name, (transformers, options) => { - // 添加 commonjs => esm 转换 修改引用路径 - if ( - options.fileInfo.content.includes('import') || - options.fileInfo.content.includes('require') - ) { - this.alterImportOrRequirePath(transformers, options.fileInfo.path) - } - - return transformers - }) - - // preprocessorParser: 文件预处理器 hook,该阶段会处理条件编译 - runner.hooks.preprocessorParser.tap( - this.name, - (fileContent, context, options) => { - if (!/\.(j|t)s$/.test(options.fileInfo.path)) return fileContent - // 对 js/ts 文件进行一些前置处理 - return fileContent - } - ) - - // postprocessorParser: 文件后置处理器 hook - runner.hooks.postprocessorParser.tap(this.name, (fileContent, options) => { - if (!/\.(w|a)xml$/.test(options.fileInfo.path)) return fileContent - // 对 *xml 文件进行一些后置处理 - return fileContent - }) - } -} -``` - -## 集成 Hooks - -```typescript -import type { Plugin, Runner, UserConfig } from '@morjs/cli' - -export interface IMorJSPluginXXXOptions { - key: value -} - -export default class MorJSPluginXXX implements Plugin { - name = 'MorJSPluginXXX' - pluginOptions: IMorJSPluginXXXOptions - - constructor(options?: IMorJSPluginXXXOptions) { - this.pluginOptions = { - ...options - } - } - - apply(runner: Runner) { - // moduleDownloaded: 下载模块阶段, 完成后触发 - runner.hooks.moduleDownloaded.tapPromise(this.name, (moduleInfo) => { - const { target } = runner.userConfig - if (target) { - // 对 moduleInfo 进行 scripts 脚本修改等操作 - } - }) - - // moduleBeforeScriptsExecuted: 前置脚本阶段, 完成后触发 - runner.hooks.moduleBeforeScriptsExecuted.tapPromise( - this.name, - (moduleInfo) => { - const { target } = runner.userConfig - if (['alipay', 'taobao'].includes(target)) { - // 对支付宝、淘宝端完成前置脚本后进行一些文件处理 - } - } - ) - - // moduleConfigLoaded: 配置载入阶段, 完成后触发 - runner.hooks.moduleConfigLoaded.tapPromise(this.name, (moduleInfo) => { - const { target } = runner.userConfig - if (target === 'wechat') { - // 对微信端配置载入后进行一些操作流程 - } - }) - - // moduleCopiedOrCompiled: 复制编译阶段, 完成后触发 - runner.hooks.moduleCopiedOrCompiled.tapPromise(this.name, (moduleInfo) => { - const { target } = runner.userConfig - if (target === 'bytedance') { - // 对抖音端复制编译完成后进行一些操作流程 - } - }) - - // moduleAfterScriptsExecuted: 后置脚本阶段, 完成后触发 - runner.hooks.moduleAfterScriptsExecuted.tapPromise( - this.name, - (moduleInfo) => { - const { target } = runner.userConfig - if (target === 'wechat') { - // 对微信端 scripts.after 脚本执行完成后进行一些操作流程 - } - } - ) - - // moduleComposed: 模块集成阶段, 完成后触发 - runner.hooks.moduleComposed.tapPromise(this.name, (moduleInfo) => { - const { target } = runner.userConfig - if (target === 'wechat') { - // 对微信端集成完成成后进行一些文件操作 - } - }) - - // moduleFailedAttempt: 失败重试阶段,模块集成失败后将自动尝试修复 - runner.hooks.moduleFailedAttempt.tapPromise(this.name, (moduleInfo) => { - // 模块集成失败后重试阶段介入一下错误输出上报或相关操作 - }) - } -} -``` diff --git a/website/docs/api/engineering-mor.md b/website/docs/api/engineering-mor.md deleted file mode 100644 index b2229f11..00000000 --- a/website/docs/api/engineering-mor.md +++ /dev/null @@ -1,112 +0,0 @@ -# MorJS API - -## tsTransformerFactory(visitor) - -生成 ts 的 transformer 插件,提供 visitor 作为参数,遍历所有 Node 节点 - -- `visitor`: 自定义节点 visitor - -## cssProcessorFactory(name, processor) - -postcss 插件 - -- `name`: css 处理器作为 postcss 插件的名称 -- `processor`: 自定义 css 处理器 - -## validKeysMessage(keys) - -基于可选值生成描述信息 - -- `keys`: 可选值 - -## hexToRgb(hex) - -将 16 进制的颜色值转换成 rgb 格式 - -- `hex`: 16 进制的颜色值 - -## isLightColor(r, g, b) - -是否是浅色 - -- `r`: rgb 色值区域中的 red -- `g`: rgb 色值区域中的 green -- `b`: rgb 色值区域中的 blue - -## senpmBinPATH(projectPath, env) - -设置 NPM .bin 路径以复用 npm bin 文件 - -- `projectPath`: 项目路径 -- `env`: 环境变量 - -## generateQrcodeForTerminal(input) - -生成二维码字符串 - -- `input`: 用于生成二维码的字符串 - -## expandExtsWithConditionalExt(exts, conditionalExts) - -将普通后缀扩展为普通后缀和带条件后缀的集合,条件后缀优先级高于普通后缀 - -- `exts`: 后缀列表 -- `conditionalExts`: 条件后缀 - -## WebpackWrapper - -webpack 封装,主要目的是 共用 webpack 的能力 - -```typescript -import { WebpackWrapper } from '@morjs/cli' - -const webpack = new WebpackWrapper() -``` - -## WebpackChain - -引用自 `webpack-chain-5` 的第三方依赖,直接 `export` 给开发者引用 - -## webpack - -引用自 `webpack` 的第三方依赖,直接 `export` 给开发者引用 - -## glob - -引用自 `takin` 的 `fastGlob` 对象,直接 `export` 给开发者引用 - -## posthtml - -引用自 `posthtml` 的第三方依赖,直接 `export` 给开发者引用 - -## typescript - -引用自 `typescript` 的第三方依赖,直接 `export` 给开发者引用 - -## micromatch - -引用自 `micromatch` 的第三方依赖,直接 `export` 给开发者引用 - -## postcss - -引用自 `postcss` 的第三方依赖,直接 `export` 给开发者引用 - -## slash - -引用自 `slash` 的第三方依赖,直接 `export` 给开发者引用 - -## takin - -引用自 `takin` 的依赖,直接 `export` 给开发者引用 - -## pRetry - -引用自 `p-retry` 的第三方依赖,直接 `export` 给开发者引用 - -## pQueue - -引用自 `p-queue` 的第三方依赖,直接 `export` 给开发者引用 - -## cjsToEsmTransformer - -引用自 `cjstoesm` 的 `cjsToEsmTransformer` 对象,直接 `export` 给开发者引用 diff --git a/website/docs/api/engineering-takin.md b/website/docs/api/engineering-takin.md deleted file mode 100644 index bea90d45..00000000 --- a/website/docs/api/engineering-takin.md +++ /dev/null @@ -1,967 +0,0 @@ -# Takin API - -> 关于什么是 `takin` 可以参见 [Takin 介绍](/api/takin) - -## Cli - -提供给 runner.hooks 的 Cli 实例,可通过 `cli.command().option()` 追加子命令和选项来干预命令行阶段实现自定义命令 - -```typescript -import type { Plugin, Runner } from '@morjs/cli' - -export default class MorJSPluginXXX implements Plugin { - name = 'MorJSPluginXXX' - - apply(runner: Runner) { - // 可通过该 hook 拿到一个 cli 的实例 - runner.hooks.cli.tap(this.name, (cli) => { - // 通过 cli.command 新建一个命令行指令 - const command = cli.command(COMMAND_NAME, 'command指令描述') - // 注册 options 选项 - command.option(rawName, '选项描述') - - // eg: 创建一个名为 gogogo 的命令行指令,并添加 --prod 选项配置 - // cli.command('gogogo', 'gogog 命令行').option('--prod', '开启生产模式') - // 那么在终端可运行 mor gogogo 或 mor gogogo --prod 命令行指令 - }) - } -} -``` - -## Config - -提供基础功能,用户配置支持 - -1. 支持自定义配置配置文件的名称,如 mor.config.js -2. 支持加载 js、ts、mjs、json 四种格式的配置文件 -3. 不同的文件使用不同的方式载入 -4. 支持用户自定义配置文件名称,并指定配置文件的支持类型,默认是 takin.config -5. 支持通过插件注册配置字段和校验 schema -6. 支持开启配置数组,并通过用户指定的字段来区分 -7. 支持配置合并(未完成) - -## logger - -`MorJS` 对于日志进行了约束和定义,提供了一套简洁、美观的固定日志方法,只需引入 `logger` 即可使用 - -### logger.init(level, options) - -用于初始化 `logger`,多次调用会重复初始化同一个 `logger` - -- `level`: 配置日志级别,必填 `string` 类型,支持 `info`|`success`|`warn`|`error`|`silent`,默认值 `info` -- `options`: 通用 logger 配置,必填 `object` 类型,含四个非必填配置 - - `prefix`: 日志前缀,非必填 `string` 类型,目前默认值 `[mor]` - - `debugPrefix`: debug 前缀,非必填 `string` 类型,目前默认值 MorJS - - `allowClearScreen`: 是否清空屏幕,非必填 `boolean` 类型,目前默认值 `true` - - `customLogger`: 自定义 `logger` 对象,非必填实例对象,用于取代现有 `logger` 实例 - -```typescript -import { logger } from '@morjs/cli' - -logger.init('info', { prefix: '[mor]', debugPrefix: 'mor' }) -``` - -### logger.withOptions(options) - -用于返回携带特定 `options` 的 `logger` 实例,该实例后续的调用都含有已配置的特定 `options` - -- `options`: 必填 `object` 类型,含以下个非必填配置 - - `clear`: 是否清空当前窗口,非必填 `boolean` 类型 - - `timestamp`: 是否携带时间戳,非必填 `boolean` 类型 - - `color`: 是否输出颜色,非必填 `boolean` 类型 - - `align`: 是否对齐,非必填 `boolean` 类型 - - `symbol`: 是否输出 symbol,非必填 `boolean`|`string` 类型 - - `update`: 是否为更新,非必填 `boolean` 类型 - - `depth`: 对象层级,非必填`null`|`number`类型 - -```typescript -import { logger } from '@morjs/cli' - -const logger = createLogger('info', { - debugPrefix: 'mor', - prefix: `[mor]` -}).withOptions({ color: false, align: true }) -``` - -### logger.info(msg, options) - -在控制台打印 `info` 类型的日志输出 - -- `msg`: 必填 `any` 类型,显示日志的输出内容 -- `options`: 非必填 `object` 类型,配置项与 `logger.withOptions` 的 `options` 一致 - -### logger.success(msg, options) - -在控制台打印 `success` 类型的日志输出,参数配置与 `logger.info` 一致 - -### logger.warn(msg, options) - -在控制台打印 `warn` 类型的日志输出,参数配置与 `logger.info` 一致 - -### logger.warnOnce(msg, options) - -在控制台打印 `warnOnce` 类型的日志输出,相同内容只会输出一次,参数配置与 `logger.info` 一致 - -### logger.error(msg, options) - -在控制台打印 `error` 类型的日志输出,参数配置与 `logger.info` 一致 - -```typescript -import { logger } from '@morjs/cli' - -logger.info('info 日志输出') -logger.success('success 日志输出') -logger.warn('warn 日志输出') -logger.warnOnce('warnOnce 日志输出,相同信息只输出一次') -logger.warnOnce('warnOnce 日志输出,相同信息只输出一次') -logger.error('error 日志输出') -``` - -
- -### logger.deprecate(deprecatedMsg, hint, error) - -在控制台打印一段 `warn` 类型的 deprecate 日志输出 - -- `deprecatedMsg`: 必填 `any` 类型,显示日志的输出内容 -- `hint`: 必填 `any` 类型,显示日志内容的提示 -- `error`: 非必填 `object` 类型,通用 `error` 结构 - -```typescript -import { logger } from '@morjs/cli' - -logger.deprecate('deprecatedMsg 日志输出', 'hint 提示') -``` - -### logger.debug(msg, ...args) - -基于 `debug npm` 的 `debug` 日志输出 - -```typescript -import { logger } from '@morjs/cli' - -logger.debug('debug 日志输出,仅在开启 debug 时显示') -``` - -### logger.time(label) & logger.timeEnd(label) - -耗时性能日志输出, 需要 `logger.time()` 配合 `logger.timeEnd()` 一起使用 - -- `label`: 必填 `string` 类型,打印同一 `label` 值从开始到结束之间的耗时,单位 ms - -### logger.clearScreen(type) - -清空当前屏幕 - -- `type`: 配置清屏设置,必填 `string` 类型,支持 `info`|`success`|`warn`|`error` - -### logger.hasErrorLogged(error) - -当前错误是否已输出,返回一个 `boolean` 值 - -- `error`: 非必填 `object` 类型,通用 `error` 结构 - -### logger.hasWarned - -当前 `logger` 实例的 `hasWarned` 项,用于记录是否打印 `warn` 级别及以上报错日志 - -### logger.hasErrored - -当前 `logger` 实例的 `hasErrored` 项,用于记录是否打印 `error` 级别及以上报错日志 - -### logger.options - -当前 `logger` 实例的 `options` 配置,具体值可参考 `logger.withOptions` 的 `options` 配置项 - -### logger.createLoading(msg, options) - -可以创建一个 loading 日志对象 - -- `msg`: 必填 `any` 类型,显示日志的输出内容 -- `options`: 非必填 `object` 类型,含四个非必填配置 - - `clear`: 是否清空当前窗口,非必填 `boolean` 类型 - - `timestamp`: 是否携带时间戳,非必填 `boolean` 类型 - - `color`: 是否输出颜色,非必填 `boolean` 类型 - - `align`: 是否对齐,非必填 `boolean` 类型 - - `symbol`: 是否输出 symbol,非必填 `boolean`|`string` 类型 - - `update`: 是否为更新,非必填 `boolean` 类型 - - `depth`: 对象层级,非必填 `null`|`number` 类型 - -`logger.createLoading(msg)` 返回携带特定 `options` 的 `loadingLogger` 的实例对象,该实例对象提供以下几个方法 - -- `.start(msg)`: 开始执行 `loadingLogger` 日志实例对象,并先打印一次 `msg` 内容 - - `msg`: 非必填 `any` 类型,显示日志的输出内容,优先级大于 `createLoading` 的 `msg` -- `.update(msg)`: 更新日志的输出内容 - - `msg`: 必填 `any` 类型,显示日志的输出内容 -- `.stop()`: 停止 `loadingLogger` 日志实例对象的执行 -- `.success(msg, opts)`: 在控制台打印 `success` 类型的日志输出,参数配置与 `logger.info` 一致 -- `.fail(msg, opts)`: 在控制台打印 `error` 类型的日志输出,参数配置与 `logger.info` 一致 -- `.error(msg, opts)`: 在控制台打印 `error` 类型的日志输出,参数配置与 `logger.info` 一致 - -以下为示例代码:(真实的显示效果应为,每下一行的打印显示会自动替换前一行的显示,这里为了方便截图我在 `init` 里设置了 `allowClearScreen`,`start` 和 `update` 的 icon 是一个类转圈的动效,开发者可以自己尝试看一下效果) - -```typescript -import { logger } from '@morjs/cli' - -const loading = logger.createLoading('创建进程日志').start() -try { - setTimeout(() => { - loading.update('当前进度50%') - }, 1500) - setTimeout(() => { - loading.stop() - loading.success('当前进程已完成') - }, 3000) -} catch (err) { - loading.fail(err) -} -``` - -
- -### logger.table(tableOptions, type, options) - -在控制台打印 `table` 表格类型的日志输出 - -- `tableOptions`: 必填 `object` 类型 - - `head`: 表格头的配置信息,`string[]` 类型 - - `rows`: 表格内容的配置信息,`string[][]` 类型 - - `colWidths`: 表格每列的宽度,`number[]` 类型 - - `colAligns`: 表格每列的对齐方式,`Array<'left' | 'middle' | 'right'>` 类型 - - 其他配置项可查看源码或 `typescript` 对应注释 -- `type`: 非必填 `string` 类型,支持 `info`|`success`|`warn`|`error` -- `options`: 非必填 `object` 类型,配置项与 `logger.withOptions` 的 `options` 一致 - -```typescript -const table = { - head: ['head1', 'head2', 'head3'], - rows: [ - ['rows1-1', 'rows1-2', 'rows1-3'], - ['rows2-1', 'rows2-2', 'rows2-3'], - ['rows3-1', 'rows3-2', 'rows3-3'] - ], - colWidths: [30, 20, 20] -} -logger.table(table) -``` - -
- -## downloader - -### downloader.file.parseOptions(pathOrOptions) - -解析 file 链接或选项 - -- `pathOrOptions`: 链接 `path` 或选项 `{ path, ...options }` - -```typescript -import { downloader } from '@morjs/cli' - -downloader.file.parseOptions(pathOrOptions) -``` - -### downloader.file.supportProtocol(url) - -判断是否支持处理当前链接(正则) - -- `url`: 链接 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.file.supportProtocol(url) // true / false -``` - -### downloader.file.getName(fileOptions) - -基于 file 链接选项获取名称 - -- `fileOptions`: file 链接选项 `{ path, ...options }` - -```typescript -import { downloader } from '@morjs/cli' - -downloader.file.getName(fileOptions) -``` - -### downloader.file.download(fileOptions, dest) - -下载 file 链接到指定目录 - -- `fileOptions`: file 链接选项 -- `dest`: 指定目录地址 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.file.download(fileOptions, dest) -``` - -### downloader.link.parseOptions(pathOrOptions) - -解析 link 链接或选项 - -- `pathOrOptions`: 链接或选项 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.link.parseOptions(pathOrOptions) -``` - -### downloader.link.supportProtocol(url) - -判断是否支持处理当前链接(正则) - -- `url`: 链接 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.link.supportProtocol(url) // true / false -``` - -### downloader.link.getName(linkOptions) - -基于 link 链接选项获取名称 - -- `linkOptions`: link 链接选项 `{ path, ...options }` - -```typescript -import { downloader } from '@morjs/cli' - -downloader.link.getName(linkOptions) -``` - -### downloader.link.download(linkOptions, dest) - -下载 link 链接到指定目录 - -- `linkOptions`: link 链接选项 -- `dest`: 指定目录地址 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.link.download(linkOptions, dest) -``` - -### downloader.git.addSupportGitSite(siteUrl, siteType) - -添加支持的 git 站点 - -- `siteUrl`: 站点地址, 如 github.com -- `siteType`: 站点类型, 如 git / gitlab / bitbucket - -```typescript -import { downloader } from '@morjs/cli' - -downloader.git.addSupportGitSite(siteUrl, siteType) -``` - -### downloader.git.getGitHash(repo) - -获取 git hash - -- `repo`: git repo 设置 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.git.getGitHash(repo) -``` - -### downloader.git.parseOptions(urlOrOptions) - -解析 git 选项或链接 - -- `urlOrOptions`: git 下载链接或选项 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.git.parseOptions(urlOrOptions) -``` - -### downloader.git.supportProtocol(url) - -判断是否支持处理当前链接 - -- `url`: 链接 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.git.supportProtocol(url) -``` - -### downloader.git.getName(options) - -从 git 仓库选项中获取名称 - -- `options`: git 仓库选项 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.git.getName(options) -``` - -### downloader.git.download(options, dest) - -下载 git repo 到指定的目录 - -- `options`: git 选项 -- `dest`: 下载目录 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.git.download(options, dest) -``` - -### downloader.tar.parseOptions(urlOrOptions) - -解析 tar 链接或选项 - -- `urlOrOptions`: 链接或选项 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.tar.parseOptions(urlOrOptions) -``` - -### downloader.tar.supportProtocol(url) - -判断是否支持处理当前链接(正则) - -- `url`: 链接 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.tar.supportProtocol(url) -``` - -### downloader.tar.getName(tarOptions) - -基于 tar 压缩包选项获取名称 - -- `tarOptions`: tar 压缩包选项 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.tar.getName(tarOptions) -``` - -### downloader.tar.download(tarOptions, dest) - -下载 tar 压缩包到指定目录 - -- `tarOptions`: tar 压缩包选项 -- `dest`: 指定目录地址 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.tar.download(tarOptions, dest) -``` - -### downloader.npm.setRegistryUrl(url) - -设置自定义 npm registry 地址 - -- `url`: 自定义 npm registry 地址 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.npm.setRegistryUrl(url) -``` - -### downloader.npm.getRegistryUrl(scope) - -返回 特定 scope 的 npm registry 地址 - -- `scope`: npm 分组 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.npm.getRegistryUrl(scope) -``` - -### downloader.npm.parseOptions(urlOrOptions) - -解析 npm 链接或选项 - -- `urlOrOptions`: npm 链接或选项 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.npm.parseOptions(urlOrOptions) -``` - -### downloader.npm.supportProtocol(url) - -判断是否支持处理当前链接 - -- `url`: 链接 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.npm.supportProtocol(url) -``` - -### downloader.npm.getName(npmOptions) - -从 npm 选项中获取名称 - -- `npmOptions`: npm 选项 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.npm.getName(npmOptions) -``` - -### downloader.npm.download(npmOptions, dest) - -下载 npm 到指定的目录 - -- `npmOptions`: npm 下载链接或选项 -- `dest`: 下载目录 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.npm.download(npmOptions, dest) -``` - -### downloader.registerDownloader(type, downloader) - -注册新的下载器 - -- `type`: 下载器类型 -- `downloader`: 下载器 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.npm.registerDownloader(type, downloader) -``` - -### downloader.getModuleName(type, options) - -获取下载模块名称 - -- `type`: 下载类型 -- `options`: 下载配置 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.npm.getModuleName(type, options) -``` - -### downloader.chooseDownloadType(options) - -基于下载配置选择下载方式 - -- `options`: 下载配置 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.chooseDownloadType(options) -``` - -### downloader.getAllDownloadTypes() - -获取所有下载类型 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.getAllDownloadTypes() -``` - -### downloader.parseOptions(type, options) - -解析下载链接或选项 - -- `type`: 下载类型 -- `options`: 下载链接或选项 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.parseOptions(type, options) -``` - -### downloader.download(type, options, dest) - -尝试通过不同的方式下载模块 - -- `type`: 下载方式 -- `options`: 下载配置 -- `dest`: 下载地址 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.download(type, options, dest) -``` - -### downloader.autoDetectDownloaderTypeAndOptions(url) - -基于 url 自动判断支持的下载器类型及下载选项 - -- `url`: 下载链接或地址 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.autoDetectDownloaderTypeAndOptions(url) -``` - -### downloader.tryDownloadByUrl(options, dest) - -自动基于不同的协议来下载模块 - -- `options`: 下载链接 -- `dest`: 下载地址 - -```typescript -import { downloader } from '@morjs/cli' - -downloader.tryDownloadByUrl(options, dest) -``` - -## utils - -封装定义了一些常用方法 - -### asArray(value) - -数组转换方法 - -- `value`: 需要转换为数组的值 - -```typescript -import { asArray } from '@morjs/cli' - -asArray(value) -``` - -### bundleMjsOrTsFile(cwd, fileName, mjs) - -使用 esbuild 读取 ts 或 mjs 文件内容 - -- `cwd`: 当前工作目录 -- `fileName`: 配置文件路径 -- `mjs`: 是否为 mjs 文件类型 - -```typescript -import { bundleMjsOrTsFile } from '@morjs/cli' - -bundleMjsOrTsFile(cwd, fileName, mjs) -``` - -### isSupportColorModifier() - -主要用于 logger 内部,标记是否支持 color modifier 如: bold strikethrough 等 - -```typescript -import { isSupportColorModifier } from '@morjs/cli' - -isSupportColorModifier() -``` - -### disableColorModifierSupport() - -将标记值改为 false - -```typescript -import { disableColorModifierSupport } from '@morjs/cli' - -disableColorModifierSupport() -``` - -### enableColorModifierSupport() - -将标记值改为 true - -```typescript -import { enableColorModifierSupport } from '@morjs/cli' - -enableColorModifierSupport() -``` - -### compose(fns) - -组合多个函数为一个,顺序执行 - -- `fns`: 函数列表 - -```typescript -import { compose } from '@morjs/cli' - -compose(fns) -``` - -### importJsOrMjsOrTsFromFile(cwd, filePath, isMjs, isTs, tempFilePath, autoDeleteTempFile) - -载入并解析 js、mjs 或 ts 文件 - -```typescript -import { importJsOrMjsOrTsFromFile } from '@morjs/cli' - -importJsOrMjsOrTsFromFile( - cwd, - filePath, - isMjs, - isTs, - tempFilePath, - autoDeleteTempFile -) -``` - -### interopRequireDefault(obj) - -改造传入的对象结构 - -- `obj`: 传入的对象值 - -```typescript -import { interopRequireDefault } from '@morjs/cli' - -interopRequireDefault(obj) -``` - -### isObject(value) - -判断是否为 object - -- `value`: 传入的对象值 - -```typescript -import { isObject } from '@morjs/cli' - -isObject(value) -``` - -### isUnicodeSupported() - -判断是否支持 unicode - -```typescript -import { isUnicodeSupported } from '@morjs/cli' - -isUnicodeSupported() -``` - -### lookupFile(dirs, files, extnames, options) - -查找文件 - -- `dirs`: 目录地址 -- `files`: 文件名 -- `extnames`: 后缀名 -- `options`: 查找选项 - -```typescript -import { lookupFile } from '@morjs/cli' - -lookupFile(dirs, files, extnames, options) -``` - -### objectEnum(t) - -通过数组创建对象 enum - -- `t`: 静态数组 - -```typescript -import { objectEnum } from '@morjs/cli' - -objectEnum(t) -``` - -### readJsonLike(filePath) - -读取类 json 文件,支持 json / jsonc / json5 三种格式 - -- `filePath`: 类 json 文件 - -```typescript -import { readJsonLike } from '@morjs/cli' - -readJsonLike(filePath) -``` - -### requireResolve(args) - -由于 jest 没有办法 mock require.resolve, 需要单独封装方法来解决单测问题 - -https://github.com/facebook/jest/issues/9543 - -## Generator - -用于构建脚手架: - -1. 指定某个模板,支持本地加载或网络加载,支持多种类型 - -- 基于 downloader 支持的各种类型:file 文件、git 仓库、link 软链、npm 包、tar 包 -- 下载后会调用 prompts 获取命令行交互结果,把结果作为参数抛给 lodash 的 template 模板里,通过模板 render 生成文件,写入模板到目标文件夹 - -2. 自定义模板 - -## deps - -将 `takin` 本身的依赖库 `export` 出去,避免重复依赖 - -### chalk - -引用自 `chalk` 的第三方依赖,直接 `export` 给开发者引用,可用于修改终端输出字符彩色样式 - -```typescript -import { chalk } from '@morjs/cli' - -chalk() -``` - -### debug - -引用自 `debug` 的第三方依赖,直接 `export` 给开发者引用,可用于 logger 的 debug 日志输出,返回一个修饰过的 console.error 函数 - -```typescript -import { debug } from '@morjs/cli' - -debug() -``` - -### execa - -引用自 `execa` 的第三方依赖,直接 `export` 给开发者引用,可用于执行终端进程的库,如 execa.command(`git clone ${repo.ssh}${dest}`) - -```typescript -import { execa } from '@morjs/cli' - -execa() -``` - -### esbuild - -引用自 `esbuild` 的第三方依赖,直接 `export` 给开发者引用,支持 typescript 和 jsx 的极速打包器,目前提供给 bundleMjsOrTsFile 方法使用 - -```typescript -import { esbuild } from '@morjs/cli' - -esbuild() -``` - -### fastGlob - -引用自 `fast-glob` 的第三方依赖,直接 `export` 给开发者引用,可提供遍历文件系统和返回路径名的方法,目前提供给 generator 使用 - -```typescript -import { fastGlob } from '@morjs/cli' - -fastGlob() -``` - -### fsExtra - -引用自 `fs-extra` 的第三方依赖,直接 `export` 给开发者引用,可用于文件操作,复制、建目录、删除等 fs 扩展操作 - -```typescript -import { fsExtra as fs } from '@morjs/cli' - -fs() -``` - -### got - -引用自 `got` 的第三方依赖,直接 `export` 给开发者引用,可用于支持 promise 的 request 请求,目前提供给 download 使用 - -```typescript -import { got } from '@morjs/cli' - -got() -``` - -### json5 - -引用自 `json5` 的第三方依赖,直接 `export` 给开发者引用,可用于支持 json5 格式的文件,提供更精简的 json 格式,去掉了 key 的双引号,同时支持注释 - -```typescript -import { json5 } from '@morjs/cli' - -json5() -``` - -### jsoncParser - -引用自 `jsonc-parser` 的第三方依赖,直接 `export` 给开发者引用,可用于支持 jsonc 格式的文件,用于序列化 jsonc 文件内容 - -```typescript -import { jsoncParser } from '@morjs/cli' - -jsoncParser() -``` - -### lodash - -引用自 `lodash` 的第三方依赖,直接 `export` 给开发者引用,提供大量封装的 js 方法,如「模板插入 template」「深拷贝 cloneDeep」「删除对象属性 omit」「判空 isEmpty」等 - -```typescript -import { lodash } from '@morjs/cli' - -lodash() -``` - -### prompts - -引用自 `prompts` 的第三方依赖,直接 `export` 给开发者引用,可用于创建交互命令行表单,目前提供给 generator 使用获取命令行交互结果 - -```typescript -import { prompts } from '@morjs/cli' - -prompts() -``` - -### tapable - -引用自 `tapable` 的第三方依赖,直接 `export` 给开发者引用,流程管理工具,主要用来串联插件,完善事件流执行 - -```typescript -import { tapable } from '@morjs/cli' - -tapable() -``` - -### tarFs - -引用自 `tar-fs` 的第三方依赖,直接 `export` 给开发者引用,可用于 tar 包的压缩与解压,目前提供给 download 使用 - -```typescript -import { tarFs } from '@morjs/cli' - -tarFs() -``` - -### zod - -引用自 `zod` 的第三方依赖,直接 `export` 给开发者引用,可用于以 typeScript 为基础的模式声明和验证校验手段 - -```typescript -import { zod } from '@morjs/cli' - -zod() -``` diff --git a/website/docs/api/runtime-api.md b/website/docs/api/runtime-api.md deleted file mode 100644 index 3546cb6e..00000000 --- a/website/docs/api/runtime-api.md +++ /dev/null @@ -1,389 +0,0 @@ -# Runtime API - -## createApi(adapters, options) - -初始化 MorJS API,默认会自动初始化一个全局的 mor api - -- `adapters`: 初始化选项 - - `adapters[x].initApi`: 初始化接口方法, 接受 apiOptions 作为参数 -- `options`: 初始化选项, 默认为 {} - -```typescript -import { createApi } from '@morjs/api' - -createApi([], {}) -``` - -## mor(adapters, options) - -初始化 mor 接口 - -## registerFactory(factoryName, factoryFunction) - -注册接口初始化工厂函数 - -- `factoryName`: 接口初始化工厂函数名称 -- `factoryFunction`: 接口初始化工厂函数 - -```typescript -import { registerFactory } from '@morjs/api' - -registerFactory(factoryName, factoryFunction) -``` - -## init(options) - -初始化一个新的 mor api 实例 - -- `options`: 选项 - -```typescript -import { init } from '@morjs/api' - -init(options) -``` - -## Base64.encode(this, input) - -对输入的值进行 encode 编码 - -- `this`: IBase64 对象本省 -- `input`: 需要进行 encode 编码的字符串 - -```typescript -import { Base64 } from '@morjs/api' - -Base64.encode(this, input) -``` - -## Base64.decode(this, input) - -对输入的值进行 decode 解码 - -- `this`: IBase64 对象本省 -- `input`: 需要进行 decode 解码的字符串 - -```typescript -import { Base64 } from '@morjs/api' - -Base64.decode(this, input) -``` - -## Base64.utf8Encode(this, input) - -对输入的值进行 utf8 格式的 encode 编码 - -- `this`: IBase64 对象本省 -- `input`: 需要进行 utf8 格式的 encode 编码的字符串 - -```typescript -import { Base64 } from '@morjs/api' - -Base64.utf8Encode(this, input) -``` - -## Base64.utf8Decode(this, input) - -对输入的值进行 utf8 格式的 decode 解码 - -- `this`: IBase64 对象本省 -- `input`: 需要进行 utf8 格式的 decode 解码的字符串 - -```typescript -import { Base64 } from '@morjs/api' - -Base64.utf8Decode(this, input) -``` - -## getEnv() - -获取小程序运行环境 - -```typescript -import { getEnv } from '@morjs/api' - -const env = getEnv() -``` - -## getEnvDesc() - -获取当前环境描述信息 - -```typescript -import { getEnvDesc } from '@morjs/api' - -const envDesc = getEnvDesc() -``` - -## getGlobalObject() - -获取全局对象,如支付宝的 my,微信的 wx - -```typescript -import { getGlobalObject } from '@morjs/api' - -const global = getGlobalObject() -``` - -## createEvent(reason, all) - -创建 Emitter 实例 - -- `reason`: 事件创建原因, 用于统计 -- `all`: 自定义 Map 用于存储事件名称和事件处理函数 - -```typescript -import { createEvent } from '@morjs/api' - -createEvent(reason, all) -``` - -## getAllEvents() - -获取所有 event 实例 - -```typescript -import { getAllEvents } from '@morjs/api' - -getAllEvents() -``` - -## event - -全局默认 Event - -## createHooks(reason) - -创建 hooks 对象 - -- `reason`: Hooks 创建原因 - -```typescript -import { createHooks } from '@morjs/api' - -createHooks(reason) -``` - -## getAllHooks() - -获取所有 hooks - -```typescript -import { getAllHooks } from '@morjs/api' - -getAllHooks() -``` - -## hooks - -获取全局共享属性,用于作为原子化的兜底实现 - -## applyPlugins(hooks, plugins) - -应用插件 - -- `hooks`: Hooks -- `plugins`: 插件列表 - -```typescript -import { applyPlugins } from '@morjs/api' - -applyPlugins(hooks, plugins) -``` - -## applySolutions(hooks, solutions) - -应用 Solutions - -- `hooks`: Hooks -- `solutions`: 插件集列表 - -```typescript -import { applySolutions } from '@morjs/api' - -applySolutions(hooks, solutions) -``` - -## logger.warn(msg) - -在控制台打印 `warn` 类型的日志输出 - -- `msg`: 显示日志的输出内容 - -```typescript -import { logger } from '@morjs/api' - -logger.warn(msg) -``` - -## logger.log(msg) - -在控制台打印 `log` 类型的日志输出 - -- `msg`: 显示日志的输出内容 - -```typescript -import { logger } from '@morjs/api' - -logger.log(msg) -``` - -## logger.error(msg) - -在控制台打印 `error` 类型的日志输出 - -- `msg`: 显示日志的输出内容 - -```typescript -import { logger } from '@morjs/api' - -logger.error(msg) -``` - -## logger.info(msg) - -在控制台打印 `info` 类型的日志输出 - -- `msg`: 显示日志的输出内容 - -```typescript -import { logger } from '@morjs/api' - -logger.info(msg) -``` - -## logger.debug(msg) - -在控制台打印 `debug` 类型的日志输出 - -- `msg`: 显示日志的输出内容,仅在开启 debug 时显示 - -```typescript -import { logger } from '@morjs/api' - -logger.debug(msg) -``` - -## logger.deprecated(msg) - -在控制台打印一段 `warn` 类型的 deprecate 日志输出 - -```typescript -import { logger } from '@morjs/api' - -logger.deprecated(msg) -``` - -## logger.time(label) & logger.timeEnd(label) - -耗时性能日志输出, 需要 `logger.time()` 配合 `logger.timeEnd()` 一起使用 - -- `label`: 必填 `string` 类型,打印同一 `label` 值从开始到结束之间的耗时,单位 ms - -```typescript -import { logger } from '@morjs/api' - -logger.time(label) -logger.timeEnd(label) -``` - -## ModuleManager - -模块管理,用于获取当前小程序中的插件、分包和模块等 - -## asArray(arr) - -确保一个对象是数组 - -1. 如果 对象 == null 则返回空数组 -2. 如果 对象不是数组 则返回包含该对象的数组 -3. 如果 对象是数组 直接返回 - -- `arr`: 需要转换为数组的参数 - -```typescript -import { asArray } from '@morjs/api' - -asArray(arr) -``` - -## compose(stack) - -将多个函数合并为一个函数 - -- `stack`: 函数堆栈 - -```typescript -import { compose } from '@morjs/api' - -compose(stack) -``` - -## generateId() - -生成 ID - -```typescript -import { generateId } from '@morjs/api' - -generateId() -``` - -## getSharedProperty(propName, context) - -获取全局共享属性,用于作为原子化的兜底实现 - -1. 首先查找上下文中对应的属性 -2. 如果不存在,则查找 getApp 中的 -3. 如果不存在,则查找 小程序环境的 globalObject, 如 my 中是否存在 -4. 如果不存在,则使用 SHARED 作为兜底 - -- `propName`: 共享属性名称 -- `context`: 当前执行环境的上下文 - -```typescript -import { getSharedProperty } from '@morjs/api' - -getSharedProperty(propName, context) -``` - -## hasOwnProperty(obj, propertyName) - -对象中是否包含对应的属性 - -- `obj`: 对象 -- `propertyName`: 属性名称 - -```typescript -import { hasOwnProperty } from '@morjs/api' - -hasOwnProperty(obj, propertyName) -``` - -## transformApis(mor, global, config, installAllGlobalApis, allowOverride) - -接口抹平转换 - -- MorJS: mor 接口对象 -- `global`: 小程序目标平台全局对象 -- `config`: 接口抹平配置 -- `installAllGlobalApis`: 是否在 mor 中添加所有的 API -- `allowOverride`: 是否允许覆盖 API - -```typescript -import { transformApis } from '@morjs/api' - -transformApis(mor, global, config, installAllGlobalApis, allowOverride) -``` - -## markAsUnsupport(apiName) - -返回暂不支持的 函数 - -- `apiName`: 接口名称 - -```typescript -import { markAsUnsupport } from '@morjs/api' - -markAsUnsupport(apiName) -``` diff --git a/website/docs/api/runtime-core.md b/website/docs/api/runtime-core.md deleted file mode 100644 index 266e22ff..00000000 --- a/website/docs/api/runtime-core.md +++ /dev/null @@ -1,257 +0,0 @@ -# Runtime Core - -## createApp(options, solution, extend) - -注册 App - -- `options`: MorJS 注册 App 的基础配置,必填 `object` 类型 -- `solution`: 运行时 Solution 支持,非必填 `MorJSSolution | MorJSSolution[]` 类型 -- `extend`: 模拟全局 App 构造函数,用于不存在 App 构造函数的环境,如 小程序插件 - -```typescript -import { createApp } from '@morjs/core' - -createApp({ - onLaunch() { - console.log('app onlaunch') - } -}) -``` - -## aApp(options, solution, extend) - -注册支付宝小程序 App,用法和 createApp 一致 - -```typescript -import { aApp } from '@morjs/core' - -aApp({ - onLaunch() { - console.log('app onlaunch') - } -}) -``` - -## wApp(options, solution, extend) - -注册微信小程序 App,用法和 createApp 一致 - -```typescript -import { wApp } from '@morjs/core' - -wApp({ - onLaunch() { - console.log('app onlaunch') - } -}) -``` - -## registerAppAdapters(adapters) - -注册应用转端适配器 - -## createPage - -Page 页面注册 - -- `options`: MorJS 注册 Page 的基础配置,必填 `object` 类型 - -```typescript -import { createPage } from '@morjs/core' - -createPage({ - onLoad() { - console.log('page onLoad') - } -}) -``` - -## aPage(options) - -支付宝 Page 页面注册,用法和 createPage 一致 - -```typescript -import { aPage } from '@morjs/core' - -aPage({ - onLoad() { - console.log('page onLoad') - } -}) -``` - -## wPage(options) - -微信 Page 页面注册,用法和 createPage 一致 - -```typescript -import { wPage } from '@morjs/core' - -wPage({ - onLoad() { - console.log('page onLoad') - } -}) -``` - -## registerPageAdapters(adapters) - -注册页面转端适配器 - -## enhancePage(options, sourceType) - -增强页面功能: 注入 adapters/hooks、转换声明周期等 - -- `options`: MorJS 注册 Page 的基础配置,必填 `object` 类型 -- `sourceType`: 非必填配置,支持 `w`|`a` 两种值,分别代表支付宝 DSL 与微信 DSL - -```typescript -import { enhancePage } from '@morjs/core' - -enhancePage(options, sourceType) -``` - -## createComponent(options, sourceType) - -组件注册 - -- `options`: MorJS 注册 Component 组件的基础配置,必填 `object` 类型 -- `sourceType`: 非必填配置,支持 `w`|`a` 两种值,分别代表支付宝 DSL 与微信 DSL - -```typescript -import { createComponent } from '@morjs/core' - -createComponent({ - props: {}, - methods: {} -}) -``` - -## aComponent(options, sourceType) - -支付宝 Component 组件注册,用法和 createComponent 一致 - -```typescript -import { aComponent } from '@morjs/core' - -aComponent({ - props: {}, - methods: {} -}) -``` - -## wComponent(options, sourceType) - -微信 Component 组件注册,用法和 createComponent 一致 - -```typescript -import { wComponent } from '@morjs/core' - -wComponent({ - props: {}, - methods: {} -}) -``` - -## registerComponentAdapters(adapters) - -注册组件转端适配器 - -## enhanceComponent(options, sourceType, features) - -增强组件功能: 注入 adapters/hooks、转换声明周期等 - -- `options`: 小程序组件配置 -- `sourceType`: 小程序组件源码类型, 编译时由 MorJS 自动填充 -- `features`: 功能特性配置 - -```typescript -import { enhanceComponent } from '@morjs/core' - -enhanceComponent(options, sourceType, features) -``` - -## PageToComponent(pageOptions, sourceType, features) - -将页面作为组件使用,仅供特殊场景下的使用,不保证完全的兼容性 - -- `pageOptions`: 页面配置 -- `sourceType`: 源码类型 -- `features`: 功能配置 - -```typescript -import { PageToComponent } from '@morjs/core' - -PageToComponent(pageOptions, sourceType, features) -``` - -## aPageToComponent(pageOptions, features) - -支付宝 Page 转组件辅助函数 - -- `pageOptions`: 页面配置 -- `features`: 功能配置 - -```typescript -import { aPageToComponent } from '@morjs/core' - -aPageToComponent(pageOptions, features) -``` - -## wPageToComponent(pageOptions, features) - -微信 Page 页面转组件辅助函数 - -- `pageOptions`: 页面配置 -- `features`: 功能配置 - -```typescript -import { wPageToComponent } from '@morjs/core' - -wPageToComponent(pageOptions, features) -``` - -## createPlugin(options) - -插件构造函数 - -- `options`: 插件选项 -- `options.getApp`: 插件使用的 getApp 构造函数 - -```typescript -import { createPlugin } from '@morjs/core' - -const plugin = createPlugin(options) -``` - -## aPlugin(options) - -支付宝插件构造函数,用法和 createPlugin 一致 - -```typescript -import { aPlugin } from '@morjs/core' - -const plugin = aPlugin(options) -``` - -## wPlugin(options) - -微信插件构造函数,用法和 createPlugin 一致 - -```typescript -import { wPlugin } from '@morjs/core' - -const plugin = wPlugin(options) -``` - -## init(solution) - -初始化, 创建 $hooks 及应用 solutions - -- `solution`: solution 解决方案 - -```typescript -import { init } from '@morjs/core' - -const { $hooks, pluginsNames } = init(solution) -``` diff --git a/website/docs/api/runtime-hooks.md b/website/docs/api/runtime-hooks.md deleted file mode 100644 index 052b4bb3..00000000 --- a/website/docs/api/runtime-hooks.md +++ /dev/null @@ -1,172 +0,0 @@ -# Runtime Hooks - -## 介绍 - -- 在插件的 `apply` 函数中,会得到一个 `morHooks` 对象,对象中会有下面的所有生命周期列表的 `hook`,插件可使用 `tap` 来注册对应的 `hook`,`tap` 接受两个参数: - - `pluginName`: 插件名 - - `pluginHandle`: 插件逻辑 -- 若插件有设置参数 `IRuntimePluginXXXOptions`,请将 `options` 的 `interface` 给 `export` 出去,方便可能需要集成的使用方进行引用 -- 插件调用方不能保证 `apply` 函数里面的 `this` 指向,因此建议都 `class` 下面的方法都用箭头函数,避免 `this` 指向问题 -- `hook` 里面的监听函数必须用普通函数,因为在 hook 调用的时候会动态修改 this 指向,指向当前的 `app`、`page`、`component` 实例 -- `hook` 里面的监听函数带两个参数: - - `this`: 可以指向当前的 `app`、`page`、`component` 实例 - - `options`: 可以拿到对应生命周期里面的参数 - -## Hooks 列表 - -```typescript -import type { MorJSHooks, MorJSPlugin } from '@morjs/api' - -export interface IRuntimePluginXXXOptions { - key: value -} - -export default class RuntimePluginXXX implements MorJSPlugin { - pluginName = 'RuntimePluginXXX' - pluginOptions: IRuntimePluginXXXOptions - - constructor(options?: IRuntimePluginXXXOptions) { - this.pluginOptions = { - ...options - } - } - - apply = (morHooks: MorJSHooks): void => { - /* App 相关 hooks */ - // appOnConstruct: 在应用初始化前执行,请注意不要进行长时间耗时的任务 - morHooks.appOnConstruct.tap(this.pluginName, function (this, options) { - console.log('app 应用 onConstruct 生命周期,初始化前触发') - }) - - // appOnInit: 已废弃 出于兼容性暂不移除,请直接使用 appOnConstruct - morHooks.appOnInit.tap(this.pluginName, function (this, options) { - console.log('app 应用 onInit 生命周期,初始化阶段触发') - }) - - // appOnLaunch: 在 onLaunch 生命周期触发,建议一般组件在这个生命周期执行初始化 - morHooks.appOnLaunch.tap(this.pluginName, function (this, options) { - console.log('app 应用 onLaunch 生命周期,初始化阶段完成时触发') - }) - - // appOnError: 在 App 的 onError 生命周期触发 - morHooks.appOnError.tap(this.pluginName, function (this, options) { - console.log('app 应用 onError 生命周期,小程序发生 js 错误时触发') - }) - - // appOnShow: 在 App 的 onShow 生命周期触发 - morHooks.appOnShow.tap(this.pluginName, function (this, options) { - console.log( - 'app 应用 onShow 生命周期,当小程序启动,或从后台进入前台显示时触发' - ) - }) - - // appOnHide: 在 App 的 onHide 生命周期触发 - morHooks.appOnHide.tap(this.pluginName, function (this, options) { - console.log( - 'app 应用 onHide 生命周期,小程序被隐藏时触发,例如跳转、按下设备 Home 键离开等' - ) - }) - - // appOnPageNotFound: 在 App 的 onPageNotFound 被调用时触发 - morHooks.appOnPageNotFound.tap(this.pluginName, function (this, options) { - console.log( - 'app 应用 onPageNotFound 生命周期,小程序要打开的页面不存在时触发' - ) - }) - - // appOnUnhandledRejection: 在 App 的 onUnhandledRejection 被调用时触发 - morHooks.appOnUnhandledRejection.tap( - this.pluginName, - function (this, options) { - console.log( - 'app 应用 onUnhandledRejection 生命周期,当 Promise 被 reject 且没有 reject 处理器时触发' - ) - } - ) - - /* Page 相关 hooks */ - // pageOnConstruct: 在页面初始化前执行,请注意这个生命周期会在应用启动后就立刻执行,并不是等用户切换到对应的页面才会执行 - morHooks.pageOnConstruct.tap(this.pluginName, function (this, options) { - console.log('page 页面 onConstruct 生命周期,初始化前触发') - }) - - // pageOnInit: 已废弃 出于兼容性暂不移除,请直接使用 pageOnConstruct - morHooks.pageOnInit.tap(this.pluginName, function (this, options) { - console.log('page 页面 onInit 生命周期,初始化阶段触发') - }) - - // pageOnLoad: 在 Page 的 onLoad 生命周期触发 - morHooks.pageOnLoad.tap(this.pluginName, function (this, options) { - console.log('page 页面 onLoad 生命周期,页面加载时触发') - }) - - // pageOnReady: 在 Page 的 onReady 生命周期触发 - morHooks.pageOnReady.tap(this.pluginName, function (this, options) { - console.log('page 页面 onReady 生命周期,页面初次渲染完成时触发') - }) - - // pageOnShow: 在 Page 的 onShow 生命周期触发 - morHooks.pageOnShow.tap(this.pluginName, function (this, options) { - console.log('page 页面 onShow 生命周期,页面显示时触发') - }) - - // pageOnHide: 在 Page 的 onHide 生命周期触发 - morHooks.pageOnHide.tap(this.pluginName, function (this, options) { - console.log('page 页面 onHide 生命周期,页面隐藏时触发') - }) - - // pageOnUnload: 在 Page 的 onUnload 生命周期触发 - morHooks.pageOnUnload.tap(this.pluginName, function (this, options) { - console.log('page 页面 onUnload 生命周期,页面卸载时触发') - }) - - /* Component 相关 hooks */ - // componentOnConstruct: 在 Component 创建前触发(组件注册的阶段) - morHooks.componentOnConstruct.tap( - this.pluginName, - function (this, options) { - console.log('component 组件 onConstruct 生命周期,注册阶段触发') - } - ) - - // componentOnInit: 在 Component 的 onInit 生命周期触发 - morHooks.componentOnInit.tap(this.pluginName, function (this, options) { - console.log('component 组件 onInit 生命周期,组件创建时触发') - }) - - // componentOnCreated: 在 Component 的 created 生命周期触发 - morHooks.componentOnCreated.tap(this.pluginName, function (this, options) { - console.log('component 组件 created 生命周期,组件实例刚刚被创建时执行') - }) - - // componentDidMount: 在 Component 的 didMount 生命周期触发 - morHooks.componentDidMount.tap(this.pluginName, function (this, options) { - console.log('component 组件 didMount 生命周期,组件创建完毕时触发') - }) - - // componentOnAttached: 在 Component 的 attached 生命周期触发 - morHooks.componentOnAttached.tap(this.pluginName, function (this, options) { - console.log( - 'component 组件 attached 生命周期,在组件实例进入页面节点树时执行' - ) - }) - - // componentDidUnmount: 在 Component 的 didUnmount 生命周期触发 - morHooks.componentDidUnmount.tap(this.pluginName, function (this, options) { - console.log('component 组件 didUnmount 生命周期,组件删除时触发') - }) - - // componentOnDetached: 在 Component 的 detached 生命周期触发 - morHooks.componentOnDetached.tap(this.pluginName, function (this, options) { - console.log( - 'component 组件 detached 生命周期,在组件实例被从页面节点树移除时执行' - ) - }) - - // componentOnError: 在 Component 的 onError 生命周期触发 - morHooks.componentOnError.tap(this.pluginName, function (this, options) { - console.log('component 组件 onError 生命周期,组件 JS 代码抛出错误时触发') - }) - } -} -``` diff --git a/website/docs/api/takin.md b/website/docs/api/takin.md deleted file mode 100644 index aa5b4ec8..00000000 --- a/website/docs/api/takin.md +++ /dev/null @@ -1,457 +0,0 @@ ---- -title: Takin 介绍 ---- - -# Takin - -## 什么是 Takin - -`takin` 是一个用于开发复杂命令行工具的基础库,提供如下的能力: - -- 相对完善及灵活的插件机制 -- 支持多配置及多任务机制 -- 高度可扩展的插件生态 -- 可灵活新增、定制及扩展命令行 -- 友好的 `typescript` 类型支持 -- 不绑定打包工具, 如 webpack、vite 等 -- 支持通过 API 调用注册命令 - -为什么开发这个工具而不是使用已有的 `build-scripts` ? - -在 MorJS 升级计划启动初期,的确曾仔细评估过是否要使用集团的 `build-scripts`, 毕竟其用户广泛、更加成熟且已经有了丰富的插件生态,但综合评估下来,由于种种限制因素,`build-scripts` 并不能很好的满足 MorJS 升级改造场景,如: - -- 写死的 `start|build|test` 命令且不支持扩展 -- 类型提示不友好, 如插件编写、用户配置等 -- 不支持扩展生命周期 -- 不支持自定义配置文件, 只能使用 build.json -- 绑定了 webpack 且因为某些原因暂时只能使用 webpack 4 -- 不支持通过 API 调用已注册的命令 -- 日志输出不够优美 - -所以,基于上述原因,我们开发了 `takin` 这个工具库,期望在满足 MorJS 本身架构诉求的基础上,能够进一步作为饿了么未来的命令行基础工具供各个团队使用和扩展。 - -## 原理及流程介绍 - - - -## 基本用法 - -`takin` 内部仅仅内置了部分全局命令行选项,并未内置任何命令,全部功能可通过插件来实现。 - -```bash -内置全局命令选项: - - --cwd [cwd] 当前工作目录, 默认为 process.cwd() - -c, --config [path] 指定自定义配置文件路径, 支持 .js, .ts, .json, .mjs 等类型, 如 takin.config.js - --ignore-config 忽略或不自动载入用户配置文件 - --no-autoload-plugins 关闭自动载入插件功能 (default: true) - -h, --help 显示帮助信息 -``` - -### 快速开发一个命令行工具 - -下面我们将演示如何快速开发一个命令行工具 👇🏻 - -```typescript -/** - * 0. 从安装 takin 作为依赖, 并新建一个 index.ts 开始 - * 执行命令: npm i takin --save - * 执行命令: touch index.ts - */ - -/** - * 1. 引入 takin 作为依赖 - */ -import * as takin from 'takin' - -/** - * 2. 为自己的命令行取一个名字, 比如 MorJS 并导出 - */ -export const mor = takin.takin('mor') - -/** - * 3. 编写你的第一个插件 - */ -class MyFirstTakinPlugin implements takin.Plugin { - name = 'MyFirstTakinPlugin' - apply(runner: takin.Runner) { - runner.hooks.cli.tap(this.name, function (cli) { - // 开启帮助信息显示 - cli.help() - - // 开启版本信息显示 - cli.version('1.0.0') - - // 注册命令 - cli - .command('compile [srcPath]', '编译命令, 支持指定源码目录') - .option('--output-path [outputPath]', '指定产物目录') - .option('--production', '是否开启生产模式') - // 注册命令行执行函数 - .action(function (command: takin.CommandOptions) { - // 打印命令行相关信息 - console.log(command) - }) - }) - - // 注册用户配置 - runner.hooks.registerUserConfig.tap(this.name, function (schema, zod) { - return schema.extend({ - mode: zod.nativeEnum(['production', 'development']).optional() - }) - }) - } -} - -/** - * 4. 应用插件 - */ -mor.use([new MyFirstTakinPlugin()]) - -/** - * 5. 调用 `run` 命令启动 - */ -mor.run() -``` - -编译上述文件为 `index.js` 文件之后(也可以直接使用 javascript 来编写以避免编译), 即可尝试运行文件, 如: - -``` -#### 获取帮助信息 -❯ node index.js -h - -mor/1.0.0 - -Usage: - $ mor [options] - -Commands: - compile [srcPath] 编译命令, 支持指定源码目录 - -For more info, run any command with the `--help` flag: - $ mor compile --help - -Options: - --cwd [cwd] 当前工作目录, 默认为 process.cwd() - -c, --config [path] 指定自定义配置文件路径, 支持 .js, .ts, .json, .mjs 等类型, 如 mor.config.js - --ignore-config 忽略或不自动载入用户配置文件 - --no-autoload-plugins 关闭自动载入插件功能 (default: true) - -h, --help Display this message - -v, --version Display version number - - - - -#### 获取编译命令帮助信息 -❯ node index.js compile -h - -mor/1.0.0 - -Usage: - $ mor compile [srcPath] - -Options: - --output-path [outputPath] 指定产物目录 - --production 是否开启生产模式 - --cwd [cwd] 当前工作目录, 默认为 process.cwd() - -c, --config [path] 指定自定义配置文件路径, 支持 .js, .ts, .json, .mjs 等类型, 如 mor.config.js - --ignore-config 忽略或不自动载入用户配置文件 - --no-autoload-plugins 关闭自动载入插件功能 (default: true) - -h, --help Display this message - - - -#### 执行编译命令 -❯ node index.js compile ./ --output-path ./dist --production -{ - name: 'compile', - args: [ './' ], - options: { - '--': [], - autoloadPlugins: true, - outputPath: './dist', - production: true - } -} -``` - -### 配置 takin 功能 - -#### 定制配置文件 - -`takin` 支持定义配置文件名称和类型, 详细如下: - -```typescript -import { takin } from 'takin' - -// 实例, 默认情况下在指定了名称之后 -// 即会自动开启对 mor.config.{ts/js/mjs/json} 等 4 中文件类型的配置支持 -const mor = takin('mor') - -// 也可以自定义新的配置文件名称, 如: -// 增加支持 mor.config.* 和 alsc.mor.config.* -// 配置后会优先读取 mor.config.* 如果未找到则尝试读取 alsc.mor.config.* -mor.config.setSupportConfigFileNames(['mor.config', 'alsc.mor.config']) - -// 也可以自定义支持的文件类型 -// 目前支持设置 ".js"、".json"、".ts"、".mjs" -// 如设置为仅支持 ts 或 js -mor.config.supportConfigExtensions(['.ts', '.js']) -``` - -#### 多配置能力 - -`takin` 支持一键开启多配置支持, 详细如下: - -```typescript -import { takin } from 'takin' - -// 实例 -const mor = takin('mor') - -// 开启多配置支持, 并通过 `name` 来区分不同配置 -// 多配置支持示例: `[{ name: 'config-one' }, { name: 'config-two' }]` -mor.config.enableMultipleConfig({ by: 'name' }) - -// 关闭多配置支持 -mor.config.disableMultipleConfig() - -// 开启 package.json 配置支持 -// 即允许通过 `package.json` 文件中的 MorJS 字段来获取配置 -// 如: `{ mor: {} }` -mor.config.enablePackageJsonConfig() - -// 关闭 package.json 配置支持 -mor.config.disablePackageJsonConfig() -``` - -## 接口及插件开发 - -### 插件定义 - -```typescript -/** - * 插件接口定义 - */ -interface Plugin { - /** - * 插件名称 - */ - name: string - /** - * 插件版本 - */ - version?: string - /** - * 插件执行顺序: - * - `设置为 enforce: 'pre'` 的插件 - * - 通过 takin.config.usePlugins 传入的插件 - * - 普通插件 - * - 设置为 `enforce: 'post'` 的插件 - */ - enforce?: ObjectValues - /** - * 插件回调函数: 当插件通过 takin 实例的 use 方法载入时自动触发, 并传入当前命令行的实例 - */ - onUse?: (takin: Takin) => void - /** - * 执行 Runner 插件逻辑, 通过 Hooks 来干预不同的阶段 - */ - apply: (runner: Runner) => void -} -``` - -### Hooks 支持 - -`takin` 中插件的扩展能力主要通过对 `Hooks` 的调用来实现, 目前支持的 `Hooks` 如下: - -```typescript -/** - * 可通过 takin.hooks 来使用 - * 通过插件中 onUse 方法传入 - */ -interface TakinHooks { - /** - * 配置文件载入完成, 可在这个阶段修改整体配置 - * 如果配置通过 run 方法直接传入则该 hook 不会执行 - */ - configLoaded: AsyncSeriesHook<[Config, CommandOptions]> - /** - * 配置完成筛选, 可在这个阶段调整需要运行的用户配置 - */ - configFiltered: AsyncSeriesWaterfallHook<[UserConfig[], CommandOptions]> -} - -/** - * 可通过 runner.hooks 来使用 - * 通过插件中的 apply 方法传入 - */ -interface RunnerHooks { - /** - * 初始化, 当 runner 被初始化并完成插件加载之后运行 - */ - initialize: SyncHook - /** - * 构建命令行时运行 - */ - cli: SyncHook - /** - * 获取到匹配命令的阶段 - */ - matchedCommand: AsyncSeriesHook - /** - * 加载用户 config 阶段 - */ - loadConfig: AsyncSeriesHook - /** - * 修改用户配置 - */ - modifyUserConfig: AsyncSeriesWaterfallHook<[UserConfig, CommandOptions]> - /** - * 注册用户配置及校验 schema - */ - registerUserConfig: AsyncSeriesWaterfallHook<[AnyZodObject, Zod]> - /** - * 是否需要运行后续逻辑 - * 执行的时机为 校验用户配置之前 - */ - shouldRun: SyncBailHook - /** - * 是否校验用户配置, 部分不使用配置的命令, 可使用该 hook 结合 runner 的上下文 - * 来选择是否跳过用户配置校验 - */ - shouldValidateUserConfig: SyncBailHook - /** - * 用户配置校验完成之后执行 - */ - userConfigValidated: AsyncSeriesHook - /** - * 开始 run 之前的 hook, 可用于准备一些运行命令需要的数据或内容 - */ - beforeRun: AsyncSeriesHook - /** - * 运行命令逻辑 - */ - run: HookMap> - /** - * runner 运行完成 - */ - done: AsyncParallelHook - /** - * runner 运行失败 - */ - failed: SyncHook -} -``` - -### 如何扩展 Hooks - -`takin` 支持通过对 `TakinHooks` 或 `RunnerHooks` 类型定义进行扩展以及调用 `registerHooks` 方法注册工厂函数的方式对 takin 本身的 hooks 进行扩展,如: - -```typescript -import { registerHooks, tapable as t } from 'takin' - -/** - * 扩展 takin.RunnerHooks 中的 hook - */ -declare module 'takin' { - interface RunnerHooks { - /** - * Compile Hook: config(json) 文件解析 hook - */ - configParser: t.AsyncSeriesWaterfallHook< - [Record, FileParserOptions] - > - - /** - * Compile Hook: script(js/ts) 文件解析 hook - */ - scriptParser: t.SyncWaterfallHook<[CustomTransformers, FileParserOptions]> - - /** - * Compile Hook: template(*xml) 文件解析 hook - */ - templateParser: t.AsyncSeriesWaterfallHook< - [PosthtmlNode, FileParserOptions] - > - - /** - * Compile Hook: style(*css) 文件解析 hook - */ - styleParser: t.AsyncSeriesWaterfallHook< - [PostCssAcceptedPlugin[], FileParserOptions] - > - - /** - * Compile Hook: sjs(wxs/sjs) 文件解析 hook - */ - sjsParser: t.SyncWaterfallHook<[CustomTransformers, FileParserOptions]> - - /** - * Compile Hook: 文件预处理器 hook - */ - preprocessorParser: t.AsyncSeriesWaterfallHook< - [string, Record, FileParserOptions] - > - - /** - * Compile Hook: 文件后置处理器 hook - */ - postprocessorParser: t.AsyncSeriesWaterfallHook<[string, FileParserOptions]> - } -} - -/** - * 注册自定义 hook 工厂, 和上方的 RunnerHooks 扩展一一对应 - */ -registerHooks({ - configParser() { - return new t.AsyncSeriesWaterfallHook(['config', 'options']) - }, - scriptParser() { - return new t.SyncWaterfallHook(['customTransformers', 'options']) - }, - templateParser() { - return new t.AsyncSeriesWaterfallHook(['tree', 'options']) - }, - styleParser() { - return new t.AsyncSeriesWaterfallHook(['postcssPlugins', 'options']) - }, - sjsParser() { - return new t.SyncWaterfallHook(['customTransformers', 'options']) - }, - preprocessorParser() { - return new t.AsyncSeriesWaterfallHook([ - 'fileContent', - 'conditionalCompileContext', - 'options' - ]) - }, - postprocessorParser() { - return new t.AsyncSeriesWaterfallHook(['fileContent', 'options']) - } -}) -``` - -通过上述方法注入的 `Hooks` 扩展可在插件中直接使用, 如: - -```typescript -import * as takin from 'takin' - -class MyTakinPlugin implements takin.Plugin { - name = 'MyTakinPlugin' - apply(runner: takin.Runner) { - runner.hooks.configParser.tap(...) - runner.hooks.scriptParser.tap(...) - runner.hooks.templateParser.tap(...) - runner.hooks.styleParser.tap(...) - runner.hooks.sjsParser.tap(...) - runner.hooks.preprocessorParser.tap(...) - runner.hooks.postprocessorParser.tap(...) - } -} -``` - -### 接口 - -参加文档: [Takin API](/api/engineering-takin.md) diff --git a/website/docs/guides/README.md b/website/docs/guides/README.md deleted file mode 100644 index 93d22700..00000000 --- a/website/docs/guides/README.md +++ /dev/null @@ -1,61 +0,0 @@ -# MorJS 介绍 - - - -## MorJS 是什么? - -Mor (发音为 /mɔːr/,类似 more) 是饿了么开发的**一款基于小程序 DSL 的,可扩展的多端研发框架**。使用小程序原生 DSL 构建,使用者只需书写一套(微信或支付宝)小程序,就可以通过 MorJS 的转端编译能力,将源码分别编译出可以在不同端(微信/支付宝/百度/字节/钉钉/快手/QQ/淘宝/Web…)运行的产物。 - -MorJS 以多端编译为基础,配以面向全生命周期的插件体系,覆盖从源码到构建产物的每个阶段,支持各类功能扩展和业务需求,无论是基础的页面和组件还是复杂的分包和插件,MorJS 都可以胜任,帮助你高效地开发多端小程序。 - -## 优势与核心能力 - -MorJS 是一套基于小程序 DSL (支付宝或微信) 的框架。他的易用性、标准化和灵活性,使得开发者能更好地专注于业务,让开发成本,招聘、管理、测试各方面成本都大幅下降,提高开发者的工作效率。 - -- ⭐️ **易用性**: - - 💎 **DSL 支持**:可使用微信小程序 DSL 或 支付宝小程序 DSL 编写小程序,无额外使用成本; - - 🌴 **多端支持**:支持将一套小程序转换为各类小程序平台及 Web 应用, 节省双倍人力; - - 🚀 **快速接入**:仅需引入两个包,增加一个配置文件,即可简单快速接入到现有小程序项目; -- 🌟 **标准化**: - - 📦 **开箱即用**:内置了脚手架、构建、分析、多端编译等完整研发能力,仅需一个依赖即可上手开发; - - 🌈 **表现一致**:通过编译时+运行时抹平多端差异性,让不同平台的小程序获得一致的用户体验; - - 🖇 **形态转换**:支持同一个项目的不同的形态,允许小程序、分包、插件不同形态之间的相互转换; -- ✨ **灵活性**: - - 🎉 **方便扩展**:MorJS 将完备的生命周期和内部功能插件化,使用插件(集)以满足功能和垂直域的分层需求; - - 📚 **类型支持**:除小程序标准文件类型外,还支持 ts、less/scss、jsonc/json5 等多种文件类型; - - 🧰 **按需适配**:可根据需求选择性接入适配能力,小项目仅需编译功能,中等项目可结合编译和页面注入能力,大型项目推荐使用复杂小程序集成能力; - -## MorJS 的由来 - -继 2017 年小程序诞生以来,由于其独特的商业模式和轻应用的用户体验,在移动社交电商等领域不断取得亮眼成绩。目前各大平台都相继推出了自己的小程序,饿了么 C 端业务需要在不同平台小程序进行投放,这些项目大多是以支付宝或微信原生 DSL 编写,面对业务渠道的不断增加,我们尝试了多种方法来兼容多端适配,但由于不同平台间小程序代码写法、能力支持的差异性逐步变大,过去的方案无法满足新业务的需求,我们需要一套跨端研发框架能解决以下诉求: - -- **原生 DSL 支持**,方便现有小程序 DSL 编写的存量业务使用; -- **降低性能开销**,尽可能轻运行时,减少编译构建的时长; -- **便捷的使用**,一键转换为支持各小程序平台使用的产物; -- **拓展的功能**,提供针对大型复杂小程序的解耦方案; -- **灵活的配置**,能够简单的增加修改多套不同端的项目配置; -- **产物优化能力**,压缩构建产物体积,减少小程序包大小; - -在明确这几点后,我们调研了业界所有主流技术框架,发现并没有能完全满足我们需求的方案,所以我们决定自研 MorJS。 - -## 什么时候不用 MorJS - -如你所见,MorJS 是一套基于小程序 DSL (支付宝、微信) 的框架,如果你, - -- 期望使用 React 或 Vue 的方式来编写小程序 -- 期望使用 Web 的方式开发 -- 有很强的 webpack 自定义需求和主观意愿 -- 需要以 微信小程序或支付宝小程序 DSL 以外的方式开发 -- 需要跑在 Node 14 以下的环境中 - -MorJS 可能不适合你。 - -## 项目使用情况 - -截止目前,MorJS 支持 **3** 种编译形态(小程序、小程序插件、小程序分包),并支持 **9** 个目标平台的转换(微信、支付宝、百度、字节、快手、钉钉、手淘、QQ、Web),未来还将进一步扩展平台支持(如 鸿蒙、快应用等),支撑了饿了么 C 端多数业务在全渠道上的研发和投放。我们期望能把其中的技术细节、架构设计和技术思考呈现给大家,未来结合开源社区的共建和使用场景的扩展,来促进 Mor 框架能力进一步提升,以更好的为所有的小程序开发者服务。 - -## MorJS 社区服务群 - -如果在使用 MorJS 中遇到问题,钉钉扫码或搜索群号「`29445021084`」即可加入 👇 - - diff --git a/website/docs/guides/advance/complex-miniprogram-integration.md b/website/docs/guides/advance/complex-miniprogram-integration.md deleted file mode 100644 index 6006f700..00000000 --- a/website/docs/guides/advance/complex-miniprogram-integration.md +++ /dev/null @@ -1,787 +0,0 @@ -# 复杂小程序集成 - -## 背景 - -从 2017 年微信小程序发布开始,随着小程序的逐步发展、迭代和大量功能的开发,小程序巨大化的问题越来越突出。虽然小程序平台方提供了分包、插件两种方式来帮助小程序开发者来实现代码和功能的解耦。然而在实际的实践中,随着同一个小程序中的不同的业务逐步拆分到不同的团队,以及分包、插件、NPM 包的大量使用,不同业务团队之间的接口调用问题、包大小的管理问题、最终的小程序产物合并问题等越来越突出,基于这个背景和需求,整合饿了么在大型小程序上的各类最佳实践和解决方案,从工程化的角度出发,我们推出了 **复杂小程序集成能力**。 - -相关功能主要由 `@morjs/plugin-composer` 插件提供。 - -## 动机 - -多个独立的构建可以组成一个独立的小程序,这些独立构建之间不应该存在强依赖关系,因此可以独立开发、调试和部署。 - -除宿主之外,分包、插件和模块并不要求一定要采用 `MorJS` 来编写,只要符合接入方式的规范,理论上采用任何小程序框架的小程序或原生小程序均可以进行独立开发和集成。 - -_注:小程序、分包、插件的打包方式归属于编译,不在这里体现。_ - -## 目标 - -- 提供统一的集成研发方式和流程 -- 提供标准、可复用的集成产物规范 -- 为复杂小程序提供解耦工具和集成方法 -- 标准化小程序宿主、小程序插件、小程序分包、小程序模块之间的通信及能力注入方式 -- 提供统一的路由调用,方便多形态的小程序在多种环境下路由的一致性 -- 转 Web 之后,可基于微应用的方式进行组合(未实现) - -## 示意图 - - - -## 概念 - -### 集成 - -将小程序宿主和相关子模块通过拉包、编译、构建、合并等一系列处理之后,合并为一个完整小程序的过程 - -### 模块类型 - -- **宿主**:小程序主体,拥有小程序完整的权限,有 `appId`,可使用插件和分包,并可为不同的插件和分包提供共享的数据和方法 -- **主包**:小程序分包的一种,每个小程序只有一个主包,用于放置默认启动页面/TabBar 页面,以及一些所有分包都需用到公共资源/JS 脚本 -- **分包**:小程序分包,分为普通分包和独立分包,可申请小程序权限,使用体感接近于小程序宿主 -- **插件**:小程序插件,独立发布,嵌套在小程序宿主中使用,可被订阅使用,不可单独申请小程序权限 - -### 集成模式 - -- **组合模式**: 集成时的模块通过自定义的脚本完成编译,不经过 `MorJS` 编译处理,`MorJS` 仅会执行脚本以及操作模块产物 -- **编译模式**: 集成时的模块相关页面或组件会合并进入到 `MorJS` 的编译流程中,并与宿主产物一同输出 - -### 集成状态 - -集成过程中模块在不同阶段所处的状态,用于判断模块是否需要执行当前操作,初始状态为 **0**,最终状态为 **6**,详细状态及含义如下: - -- **0**:初始状态 -- **1**:模块已下载 -- **2**:模块前置脚本已执行 -- **3**:模块配置已载入 -- **4**:模块已完成编译或拷贝 -- **5**:模块后置脚本已执行 -- **6**:模块已集成 - -### 下载类型 - -集成过程中,用于将模块下载到指定位置的方式,可分为如下 5 种下载类型: - -- **npm**:通过 `NPM` 的方式下载,即模块以 `NPM` 包的方式发布和管理 -- **git**:通过 `Git` 的方式下载,即模块以 `Git` 仓库的方式发布和管理 -- **tar**:通过 `Tar` 压缩包的方式下载,即模块以某个存放在网络或 `CDN` 上的 `Tar` 资源形式存在 -- **link**:通过本地软链的方式下载,即模块存储在本地某个目录中,通过软链的形式,将模块链接到指定位置 -- **file**:通过本地目录拷贝的方式下载,即模块存储在本地某个目录中,通过拷贝整个目录的方式,将模块复制到指定位置 - -### 集成脚本 - -集成过程中,模块需要自定义执行的脚本命令,通常用于生成模块实际用于集成的产物: - -- **before**:前置脚本,单一模块成功下载后执行的脚本 -- **after**:后置脚本,单一模块已完成产物的拷贝或编译之后执行的脚本 -- **composed**:已集成脚本,所有模块完成集成后,集成流程结束前执行的脚本 - -## 集成配置 - -### 集成开启方式 - -MorJS 的集成可在两种方式下使用,一种是**直接集成**,一种是**编译时自动集成** - -#### 直接集成 - -通过 `mor compose` 命令控制,不涉及到编译流程,不处理 `mode` 为 `compile` 的模块,主要的功能是将宿主和各个分包合并在一起组合成一个完整的小程序。 - -#### 编译时自动集成 - -通过 `mor compile` 命令控制,涉及到编译流程,通常用于配合当前宿主或分包的线下研发。 - -编译时 MorJS 支持通过两种方式开启集成,使用任何一种均可: - -1. 通过命令 `mor compile --compose` 中的 `--compose` 在编译时自动开启集成 -2. 通过在 MorJS 配置文件中添加 `{ compose: true }` 来自动开启集成 - -#### 两者的主要区别 - -`mor compile --compose` 可以认为是相当于先执行项目的编译 `mor compile`, 然后将当前项目作为宿主(`host`)或其中一个模块(`module`)进行集成 `mor compose` - -### 集成模块配置 - -在 `mor.config.ts` 通过设置 `host: {}` 或 `modules: [{}]` 来配置宿主或子模块,如: - -> 有关 MorJS 配置的详细信息,参见:[配置说明](/guides/basic/config#%E9%85%8D%E7%BD%AE%E8%AF%B4%E6%98%8E) - -```typescript -export default defineConfig([ - { - // 宿主配置 - host: {} - - // 子模块(如:分包等) - modules: [{}] - } -]) -``` - -上述示例中的 `host` 和 `modules` 的配置方式基本一致,其中 `host` 只能配置一个,`modules` 可以配置多个,详细的配置方式如下: - -```typescript -{ - /** - * 模块名称, 可选值, 默认会基于 `npm` 或 `git` 或 `tar` 或 `link` 或 `file` 配置自动生成 - */ - name: '', - - /** - * 模块集成模式, 默认为 `compose` - * - compose: 通过 compose 方式集成, 通过拷贝的方式复制到产物目录 - * - compile: 通过 compile 方式集成, 需要通过 mor 编译流程 - */ - mode: 'compose', - - /** - * 模块类型, 默认为 `subpackage` - * - 声明为 宿主(host) 的模块,模块中包含 app.json 并作为其他模块集成的目标,配置在 `host` 中的模块,该类型固定为 `host ` - * - 声明为 主包(main) 的模块,会将页面插入到小程序 app.json 的 pages 中 - * - 声明为 分包(subpackage) 的模块,会将页面插入到小程序 app.json 的 subPackages 中 - * - 声明为 插件(plugin) 的模块: 功能研发中 - */ - type: 'subpackage', - - /** - * 下载配置 - * - * npm / git / tar / link / file 均用于下载模块, 只需要配置一个即可 - * - * 如果同时配置了多个,则只会有一个下载配置生效,优先级为:npm > git > tar > link > file - */ - /* 通过 npm 配置模块下载 */ - // 字符串方式配置,如: - npm: 'your_package@1.2.0', - // 对象方式配置,如: - npm: { - // npm 名称 - name: 'your_package', - // npm 版本, 默认为 `latest` - version: '1.2.0' - }, - - /* 通过 git 仓库配置模块下载 */ - // 字符串方式配置,如: - git: 'git@github.com:abc/cde.git#master' - // 对象方式配置,如: - // 注意: branch/tag/commit 的优先级为 commit > tag > branch, 相关字段均配置后,会按照优先级取用 - git: { - // 仓库地址, 支持 git/http/https/ssh 协议链接 - url: 'git@github.com:abc/cde.git', - // 分支配置, 默认为 HEAD - branch: 'develop', - // 标签配置 - tag: 'v1.1.0', - // Git 提交 commit id - commit: 'abcdefghijklmnopqrstuvwxyz', - }, - - /* 通过 tar 配置模块下载 */ - // 字符串方式配置,如: - tar: 'https://your_domain.com/abc.tar.gz', - // 对象方式配置,如: - tar: { - url: 'https://your_domain.com/abc.tar.gz', - // 支持增加扩展参数, 参见 got 配置 - }, - - /* 通过 link 配置(软链)模块下载 */ - // 字符串方式配置,如: - link: '/Users/yourHomeDir/Workspace/yourCustomHostPath', - // 对象方式配置,如: - link: { - path: '/Users/yourHomeDir/Workspace/yourCustomHostPath' - }, - - /* 通过 file 配置(复制)模块下载 */ - // 字符串方式配置,如: - file: '/Users/yourHomeDir/Workspace/yourCustomHostPath', - // 对象方式配置,如: - file: { - path: '/Users/yourHomeDir/Workspace/yourCustomHostPath' - }, - - // 构建产物目录配置, 默认为 `dist` - // dist 配置的作用是告知 mor 当前模块的产物所存放的目录位置 - dist: 'dist', - - /** - * 集成构建过程中可执行的脚本, 可选配置 - */ - scripts: { - // 执行脚本时的公共环境变量, 可选配置 - // mor 默认会注入如下环境变量: - // MOR_COMPOSER_MODULE_CWD: 当前模块工作目录 - // MOR_COMPOSER_MODULE_TYPE: 当前模块类型 - // MOR_COMPOSER_MODULE_HASH: 当前模块 hash 信息, 用于 mor 内部判断是否需要重新下载模块 - // MOR_COMPOSER_MODULE_ROOT: 当前模块根目录 - // MOR_COMPOSER_MODULE_SOURCE: 当前模块源码目录 - // MOR_COMPOSER_MODULE_OUTPUT_FROM: 当前模块原始产物目录 - // MOR_COMPOSER_MODULE_OUTPUT_TO: 当前模块集成产物目录 - env: {}, - - // 模块编译或拷贝前执行脚本, 可选配置 - before: [ - // 可以直接以字符串的方式配置命令 - 'npm i', - - // 也可以以对象的方式配置 - { - // 需要执行的命令 - command: 'cd some_dir && mor compile', - // 该命令的自定义环境变量 - env: { - CUSTOM_ENV: 'CUSTOM_ENV_VALUE' - }, - // 该命令的选项, 参见 execa.command 的 options 配置 - options: { - shell: true - } - }, - ], - - // 模块编译完成后或拷贝后执行脚本,配置方式同 before,可选配置 - after: [], - - // 所有模块完成集成之后执行脚本,配置方式同 before,可选配置 - composed: [], - - // 脚本执行公共选项, 参见 execa.command 的 options 配置 - options: {} - }, - - /** - * 模块配置内容,参见下方集成产物规范的 [config].json 描述 - */ - config: undefined -} -``` - -## 集成产物规范 - -集成产物是指可用于参与到小程序集成的标准模块产物,具备以下特点: - -- 框架无关 -- 可复用 -- 自描述 - -模块文件目录结构: - -```bash -[module name] - 以模块名称命名的模块根目录,可以由模块配置的 `name` 指定或基于下载配置自动生成 -├── [hash] - 模块源码或产物所在目录, `hash` 是由模块配置中的 `git`/`npm`/`tar`/`dist`/`mode` 字段生成的 MD5 值,用于辅助判断是否需要重新下载模块 -│   ├── [dist?] - 模块产物所在目录,以 mor.compose.json 中的 output.from 指向目录为准 -│   │   └── [config].json - 模块产物配置文件,不同的模块类型的配置文件均不相同,与 mor.compose.json 文件的 config 字段作用相同 -└── mor.compose.json - 模块描述文件 -``` - -### 集成产物临时目录 - -MorJS 会将集成产物统一存放到项目根目录的 `.mor/composer` 临时目录中,其中宿主模块会统一放在 `.mor/composer/hosts` 目录中,子模块会统一放在 `.mor/composer/modules` 目录中。 - -集成的宿主模块和各个子模块的状态都是独立维护的,比如某次执行集成命令: - -```bash -[mor] ℹ ┌──────────────────────────────────────────────┬────────────────┬──────┬──────┬──────┐ - │ 模块 (共 6 个, 集成终态: 已集成) │ 版本 │ 类型 │ 模式 │ 结果 │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┼──────┤ - │ miniprogram_host │ * │ 宿主 │ 编译 │ ✔ │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┼──────┤ - │ subpackage1 │ dev/1.0.0 │ 分包 │ 组合 │ ✖ │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┼──────┤ - │ subpackage2 │ feat/1.0.0 │ 分包 │ 组合 │ ✔ │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┼──────┤ - │ subpackage3 │ feature/1.0.0 │ 分包 │ 组合 │ ✔ │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┼──────┤ - │ subpackage4 │ dev/1.1.0 │ 分包 │ 组合 │ ✔ │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┼──────┤ - │ subpackage5 │ feature/1.1.0 │ 分包 │ 组合 │ ✔ │ - └──────────────────────────────────────────────┴────────────────┴──────┴──────┴──────┘ -``` - -上方集成的模块中,`subpackage1` 模块集成失败,可直接通过删除目录 `.mor/composer/modules/subpackage1` 后重新运行命令,也可以通过命令行 - -```bash -npx mor clean all -``` - -来清理 MorJS 的缓存目录 `node_modules/.cache/mor` 和临时文件目录 `.mor` 后,重新运行之前的集成命令。 - -通常情况下,推荐只删除出问题的模块,这样当再次运行集成命令时,已完成集成的模块,会被跳过,可大大节约集成时间。 - -### 模块描述文件 —— mor.compose.json - -模块描述文件的主要作用是:描述一个名为 `name` 状态为 `state` 的模块需要将自身的产物通过集成模式 `mode` 的方式从目录 `output.from` 集成到目录 `output.to` 中,并将配置 `config` 合并到小程序的 `app.json` 文件中。 - -```javascript -{ - // 模块名称,该名称和模块所在目录名称一致 - "name": "miniapp-subpackage-name", - // 模块类型 - "type": "subpackage", - // 集成模式 - "mode": "compose", - // 模块 hash 目录,基于模块配置生成,用于确保当前模块内容的唯一性 - "hash": "dc66928b089d5e14b77bdbdb09f4b60a", - // 模块所在目录 - "root": ".mor/composer/modules/miniapp-subpackage-name", - // 模块源代码所在目录,通常用于结合脚本生成最终产物 - "source": ".mor/composer/modules/miniapp-subpackage-name/dc66928b089d5e14b77bdbdb09f4b60a", - // 模块集成状态 - "state": 2, - // 模块产物输出配置 - "output": { - // 当前模块的产物所在目录 - "from": ".mor/composer/modules/miniapp-subpackage-name/dc66928b089d5e14b77bdbdb09f4b60a", - // 需要将当前模块产物复制到的目标目录 - "to": "dist/subpackageName" - }, - // 模块配置文件,作用同 app.json/plugin.json/subpackage.json - "config": { - "type": "main", - "root": "subpackageName", - "pages": [ - "pages/index/index" - ] - } -} -``` - -### 模块产物配置文件 —— [config].json - -模块配置文件,不同类型的模块配置文件按照如下规则配置: - -- 宿主(`host`):使用 `app.json` 配置文件,该文件和小程序的 `app.json` 配置方式一致 -- 主包(`main`):使用 `subpackage.json` 配置文件,该文件和小程序的 `app.json` 的 `subpackages` 字段条目配置方式一致,区别在于扩展了 `"type": "main"` 用于标记当前模块为主包模块 -- 分包(`subpackage`):使用 `subpackage.json` 配置文件,该文件和小程序的 `app.json` 的 `subpackages` 字段条目配置方式一致 -- 插件(`plugin`):使用 `plugin.json` 配置文件,该文件和小程序插件的 `plugin.json` 配置方式一致 - -模块配置示例 - -```javascript -/* 配置示例 */ - -// 小程序 app.json 配置示例 -// 详细配置可参见微信小程序或支付宝小程序 app.json 配置 -{ - "pages": [ - "pages/todos/todos", - "pages/add-todo/add-todo" - ], - // subpackages 或 subPackages 均可 - "subPackages": [ - { - "root": "my", - "pages": [ - "pages/profile/profile" - ] - } - ] -} - -// 小程序插件 plugin.json 配置示例 -// 详细配置可参见微信小程序或支付宝小程序 plugin.json 配置 -{ - "publicComponents": { - "list": "components/list/list" - }, - "publicPages": { - "hello-page": "pages/index/index" - }, - "pages": [ - "pages/index/index", - "pages/another/index" - ], - // 插件导出的模块文件 - "main": "index.js" -} - -// 小程序分包 subpackage.json 配置示例 -// 配置方式同 app.json 中的 subpackages 的单个分包配置方式一致 -{ - // type 字段为 mor 独有, 用于标识该分包为 "subpackage" 或 "main" - // 区别是: 集成时 "subpackage" 类型的分包会被自动合并到 app.json 的 subpackages 字段中 - // "main" 类型的分包会被自动合并到 app.json 的 pages 字段中 (即: 合并至主包) - "type": "subpackage", - // root 字段将影响集成时分包产物合并至宿主小程序时的根目录 - "root": "my", - // 注意: 编译分包以 pages 作为实际路径进行解析 - "pages": [ - "pages/profile/profile" - ] -} -``` - -### 实际模块示例 - -```bash -miniapp-subpackage-name -├── dc66928b089d5e14b77bdbdb09f4b60a -│ ├── dist -│ │   ├── components -│ │   ├── pages -│ │   │   └── index -│ │   │      ├── index.js -│ │   │      ├── index.json -│ │   │      ├── index.wxml -│ │   │      └── index.wxss -│   │   └── subpackage.json -└── mor.compose.json -``` - -## 用法举例 - -这里会简单列举三种集成研发模式,来帮助大家理解集成的具体作用和使用方法。 - -### 主/子分包研发模式 - -业务可基于业务对小程序中的分包进行拆分,以达到各个业务相互解耦,独立迭代的目的,参见下方分包配置示例: - -```typescript -import { defineConfig, takin } from '@morjs/cli' - -export default defineConfig([ - { - name: 'tt', - sourceType: 'alipay', - target: 'bytedance', - modules: [ - // 主入口包 - { - name: 'miniapp-entry', - git: { - url: 'git@github.com:abc/miniapp-entry.git', - branch: 'dev/1.0.0' - }, - scripts: { - before: ['npm i', 'npm run build:dy'] - }, - dist: 'dist/dy' - }, - - // 搜索分包 - { - git: { - url: 'git@github.com:abc/eleme-miniapp-plugin-search.git', - branch: 'feat/upgrade-to-mor-2' - }, - scripts: { - before: ['npm i', 'cd plugin && npm i', 'mor compile --name dy'] - }, - dist: 'miniprogram_tt/dist' - }, - - // 红包分包 - { - git: { - url: 'git@github.com:abc/vouchers.git', - branch: 'feature/dy' - }, - scripts: { - before: ['npm i', 'cd plugin && npm i', 'mor compile --name dy'] - }, - dist: 'dist/bytedance' - }, - - // 订单列表 - { - git: { - url: 'git@github.com:abc/miniapp-plugin-orderlist.git', - branch: 'dev/dy/10.12.5' - }, - scripts: { - before: ['npm i', 'npm run build:dy'] - }, - dist: 'build/_bytedance' - }, - - // 平台(地址管理) - { - git: { - url: 'git@github.com:abc/king-home-alipay.git', - branch: 'feature/dy' - }, - scripts: { - before: ['npm i', 'mor compile --name douyin_subpackage'] - }, - dist: 'dist' - } - ] - } -]) -``` - -通过 `MorJS` 命令:`mor compile --compose` 即可集成上述配置中宿主和相关的分包。 - -运行结果示例: - -```bash -[mor] ⚑ 当前 MorJS 为开源版本: @morjs/cli@1.0.0 -[mor] ℹ 发现配置文件: mor.config.ts -[mor] ✔ 配置文件加载成功: mor.config.ts -[mor] ℹ 小程序集成功能已开启 -[mor] ℹ 即将开始集成以下模块(最大并发数: 4): -[mor] ℹ ┌──────────────────────────────────────────────┬────────────────┬──────┬──────┐ - │ 模块 (共 6 个, 集成终态: 已集成) │ 版本 │ 类型 │ 模式 │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┤ - │ miniprogram_host │ * │ 宿主 │ 编译 │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┤ - │ miniapp-entry │ dev/dy_10.12.5 │ 分包 │ 组合 │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┤ - │ eleme-ad_eleme-miniapp-plugin-search │ feat/upgrade-… │ 分包 │ 组合 │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┤ - │ mini-foundation_vouchers │ feature/dy │ 分包 │ 组合 │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┤ - │ eleme_miniapp-plugin-orderlist │ dev/dy/10.12.5 │ 分包 │ 组合 │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┤ - │ alsc-mini-app_king-home-alipay │ feature/dy │ 分包 │ 组合 │ - └──────────────────────────────────────────────┴────────────────┴──────┴──────┘ -[mor] ℹ 模块 eleme_miniapp-plugin-orderlist 前置脚本开始执行... -[mor] ℹ 模块 eleme_miniapp-plugin-orderlist 执行命令: npm i -[mor] ℹ 模块 alsc-mini-app_king-home-alipay 开始下载... -[mor] ℹ 模块 eleme-ad_eleme-miniapp-plugin-search 前置脚本开始执行... -[mor] ℹ 模块 eleme-ad_eleme-miniapp-plugin-search 执行命令: npm i -[mor] ℹ 模块 mini-foundation_vouchers 前置脚本开始执行... -[mor] ℹ 模块 mini-foundation_vouchers 执行命令: npm i -[mor] ✔ 模块 alsc-mini-app_king-home-alipay 下载成功 -[mor] ℹ 模块 alsc-mini-app_king-home-alipay 前置脚本开始执行... -[mor] ℹ 模块 alsc-mini-app_king-home-alipay 执行命令: npm i -[mor] ℹ 模块 eleme_miniapp-plugin-orderlist 执行命令: npm run build:dy -[mor] ✔ 模块 eleme_miniapp-plugin-orderlist 前置脚本执行成功, 耗时: 27.440s -[mor] ℹ 模块 alsc-mini-app_king-home-alipay 执行命令: mor compile --name douyin_subpackage -[mor] ✔ 模块 alsc-mini-app_king-home-alipay 前置脚本执行成功, 耗时: 70.623s -[mor] ℹ 模块 mini-foundation_vouchers 执行命令: cd plugin && npm i -[mor] ℹ 模块 mini-foundation_vouchers 执行命令: mor compile --name dy -[mor] ℹ 模块 eleme-ad_eleme-miniapp-plugin-search 执行命令: cd plugin && npm i -[mor] ✔ 模块 mini-foundation_vouchers 前置脚本执行成功, 耗时: 93.399s -[mor] ℹ 模块 eleme-ad_eleme-miniapp-plugin-search 执行命令: mor compile --name dy -[mor] ✔ 模块 eleme-ad_eleme-miniapp-plugin-search 前置脚本执行成功, 耗时: 115.475s -[mor] ℹ 准备配置中, 即将开始编译 👇 - 配置名称: tt - 编译目标: 字节小程序 - 编译环境: development - 编译类型: 小程序 - 编译模式: bundle - 源码类型: alipay - 源码目录: src - 输出目录: dist/bytedance -[mor] ℹ 已开启缓存, 可通过 --no-cache 关闭 -[mor] ℹ 已开启 node_modules 组件处理 -[mor] ℹ 开始编译 ... -[mor] ℹ 依赖分析中 ... -[mor] ℹ 依赖分析完成: 耗时: 86.012583 ms -[mor] ℹ 模块集成结果: -[mor] ℹ ┌──────────────────────────────────────────────┬────────────────┬──────┬──────┬──────┐ - │ 模块 (共 6 个, 集成终态: 已集成) │ 版本 │ 类型 │ 模式 │ 结果 │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┼──────┤ - │ miniprogram_host │ * │ 宿主 │ 编译 │ ✔ │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┼──────┤ - │ miniapp-entry │ dev/dy_10.12.5 │ 分包 │ 组合 │ ✔ │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┼──────┤ - │ eleme-ad_eleme-miniapp-plugin-search │ feat/upgrade-… │ 分包 │ 组合 │ ✔ │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┼──────┤ - │ mini-foundation_vouchers │ feature/dy │ 分包 │ 组合 │ ✔ │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┼──────┤ - │ eleme_miniapp-plugin-orderlist │ dev/dy/10.12.5 │ 分包 │ 组合 │ ✔ │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┼──────┤ - │ alsc-mini-app_king-home-alipay │ feature/dy │ 分包 │ 组合 │ ✔ │ - └──────────────────────────────────────────────┴────────────────┴──────┴──────┴──────┘ -[mor] ✔ 集成产物目录: dist/bytedance -[mor] ✔ 编译完成, 耗时: 127941.680666 ms -``` - -用小程序 IDE 打开 dist/bytedance 目录即可预览集成后的完整小程序。 - -### SDK 研发模式 - -业务可将通用页面封装置某个 `NPM` 包中作为通用功能,如统一宿主的 `Solution` 配置,参见下方示例: - -```typescript -import { defineConfig } from '@morjs/cli' -export default defineConfig([ - { - name: 'tt', - target: 'bytedance', - // 配置需要的 SDK - modules: [ - { - // 指定 npm 名称和版本 - npm: { - name: 'mor-runtime-solution-standard-eleme', - version: '1.0.4' - }, - // 通过编译的模式参与集成 - mode: 'compile', - // 作为主包模块进行集成 - type: 'main', - // mor-runtime-solution-standard-eleme 包中的产物地址 - dist: './src', - // 通过配置注入的页面内容:涉及 webview 和登录的页面和组件,由当前 solution 统一收口维护 - // 集成编译后,配置中的页面将会合并至 app.json 的 pages 字段中 - config: { - pages: { - 'pages/container/index': 'pages/container/index', - 'pages/container-transnavbar/index': - 'pages/container-transnavbar/index', - 'pages/auth/index': 'pages/auth/index', - 'pages/havana/index': 'pages/havana/index' - } - } - } - ] - } -]) -``` - -通过 `MorJS` 命令:`mor compile --compose` 即可集成上述配置中的页面。 - -运行结果示例: - -```bash -[mor] ⚑ 当前 MorJS 为开源版本: @morjs/cli@1.0.0 -[mor] ℹ 发现配置文件: mor.config.ts -[mor] ✔ 配置文件加载成功: mor.config.ts -[mor] ℹ 小程序集成功能已开启 -[mor] ℹ 即将开始集成以下模块(最大并发数: 4): -[mor] ℹ ┌──────────────────────────────────────────────┬────────────────┬──────┬──────┐ - │ 模块 (共 2 个, 集成终态: 已集成) │ 版本 │ 类型 │ 模式 │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┤ - │ miniprogram_host │ * │ 宿主 │ 编译 │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┤ - │ ali_mor-runtime-solution-standard-eleme_1_0… │ 1.0.4........ │ 主包 │ 编译 │ - └──────────────────────────────────────────────┴────────────────┴──────┴──────┘ -[mor] ℹ 准备配置中, 即将开始编译 👇 - 配置名称: tt - 编译目标: 字节小程序 - 编译环境: development - 编译类型: 小程序 - 编译模式: bundle - 源码类型: alipay - 源码目录: src - 输出目录: dist/bytedance -[mor] ℹ 已开启缓存, 可通过 --no-cache 关闭 -[mor] ℹ 已开启 node_modules 组件处理 -[mor] ℹ 开始编译 ... -[mor] ℹ 依赖分析中 ... -[mor] ℹ 依赖分析完成: 耗时: 1639.405709 ms -[mor] ℹ 模块集成结果: -[mor] ℹ ┌──────────────────────────────────────────────┬────────────────┬──────┬──────┬──────┐ - │ 模块 (共 2 个, 集成终态: 已集成) │ 版本 │ 类型 │ 模式 │ 结果 │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┼──────┤ - │ miniprogram_host │ * │ 宿主 │ 编译 │ ✔ │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┼──────┤ - │ ali_mor-runtime-solution-standard-eleme_1_0… │ 1.0.4........ │ 主包 │ 编译 │ ✔ │ - └──────────────────────────────────────────────┴────────────────┴──────┴──────┴──────┘ -[mor] ✔ 集成产物目录: dist/bytedance -[mor] ✔ 编译完成, 耗时: 14175.584625 ms -``` - -### 小程序插件研发模式 - -由于小程序插件无法独立运行,且对产物目录结构有特殊的要求,如: - -```bash -dist -├── miniprogram -├── plugin -└── mini.project.json -``` - -基于这种情况,我们可以利用 `MorJS` 的集成功能,来实现插件研发,参考配置如下: - -```typescript -import { defineConfig } from '@morjs/cli' - -export default defineConfig([ - { - name: 'alipay_plugin', - sourceType: 'alipay', - target: 'alipay', - // 编译类型为 插件 - compileType: 'plugin', - compileMode: 'bundle', - // 配置插件宿主 - host: { - git: { - url: 'git@github.com:abc/king-home-alipay.git', - branch: 'master' - }, - scripts: { - before: ['npm i', 'npm run compile:ali'] - }, - dist: '_ali' - }, - outputPath: 'dist', - // 插件源码目录 - srcPath: 'plugin', - autoClean: true - } -]) -``` - -通过 `MorJS` 命令:`mor compile --name alipay_plugin --compose` 即可集成上述配置中的小程序插件及其宿主。 - -运行结果示例: - -```bash -[mor] ⚑ 当前 MorJS 为开源版本: @morjs/cli@1.0.0 -[mor] ℹ 发现配置文件: mor.config.ts -[mor] ✔ 配置文件加载成功: mor.config.ts -[mor] ℹ 小程序集成功能已开启 -[mor] ℹ 即将开始集成以下模块(最大并发数: 4): -[mor] ℹ ┌──────────────────────────────────────────────┬────────────────┬──────┬──────┐ - │ 模块 (共 1 个, 集成终态: 已集成) │ 版本 │ 类型 │ 模式 │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┤ - │ alsc-mini-app_king-home-alipay │ master │ 宿主 │ 组合 │ - └──────────────────────────────────────────────┴────────────────┴──────┴──────┘ -[mor] ℹ 准备配置中, 即将开始编译 👇 - 配置名称: alipay_plugin - 编译目标: 支付宝小程序 - 编译环境: development - 编译类型: 插件 - 编译模式: bundle - 源码类型: alipay - 源码目录: plugin - 编译产物: dist/plugin - 输出目录: dist -[mor] ℹ 已开启缓存, 可通过 --no-cache 关闭 -[mor] ℹ 启动文件监听模式 -[mor] ℹ 开始编译 ... -[mor] ℹ 依赖分析中 ... -[mor] ℹ 依赖分析完成: 耗时: 12.790667 ms -[mor] ⠼ 正在编译, 进度: 99.00% -[mor] ℹ 模块集成结果: -[mor] ℹ ┌──────────────────────────────────────────────┬────────────────┬──────┬──────┬──────┐ - │ 模块 (共 1 个, 集成终态: 已集成) │ 版本 │ 类型 │ 模式 │ 结果 │ - ├──────────────────────────────────────────────┼────────────────┼──────┼──────┼──────┤ - │ alsc-mini-app_king-home-alipay │ master │ 宿主 │ 组合 │ ✔ │ - └──────────────────────────────────────────────┴────────────────┴──────┴──────┴──────┘ -[mor] ✔ 集成产物目录: dist/miniprogram -[mor] ✔ 编译完成, 耗时: 1544.04675 ms -``` - -用小程序 IDE 打开 dist 目录即可预览小程序插件。 - -## 命令行说明 - -除了通过 [配置](/guides/basic/config#集成相关配置) 的方式来使用集成能力之外,部分功能也可以结合命令行来使用,命令行的优先级高于用户配置,具体参见下方说明: - -```bash -集成相关命令行用法: - $ mor compose 或 mor compile --compose - -集成相关命令行选项: - --with-modules 指定需要参与集成的模块, 基于模块的名称筛选, 支持 glob 模式,如需指定多个,可用逗号(,)分割,示例: --with-modules '*eleme-solution,*plugin-entry' 或 --with-modules '*eleme-solution,*plugin-entry' - --without-modules 排除不需要集成的模块, 基于模块的名称筛选, 支持 glob 模式,用法和 --with-modules 类似 - --from-state 控制模块集成时的初始状态, 可选值: 0-6,每个状态码对应的含义参见文档内 `集成状态` 的描述 - --to-state 控制模块集成时的最终状态, 可选值: 0-6,每个状态码对应的含义参见文档内 `集成状态` 的描述 - --concurrency 控制模块集成时的并发数量,默认会基于本机 CPU 核数和内存 GB 数生成一个并发数量 - --combine-modules 合并模块配置(主要用于合并分包配置的页面到主包中),用于适配抖音小程序的流加载 -``` - -## 集成流程定制 - -`MorJS` 提供了若干 `Hooks` 用于支持工程插件定制集成流程。 - -有关集成 `Hooks` 可参见文档:[工程 API - Hooks - 集成 Hooks](/api/engineering-hooks#集成-hooks) - -关于如何编写工程插件,可参见文档:[插件 - 如何开发插件 - 开发工程插件](/guides/basic/plugin#%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E6%8F%92%E4%BB%B6) diff --git a/website/docs/guides/advance/learn-create-component-library.md b/website/docs/guides/advance/learn-create-component-library.md deleted file mode 100644 index 1b8c17ca..00000000 --- a/website/docs/guides/advance/learn-create-component-library.md +++ /dev/null @@ -1,170 +0,0 @@ -# 五分钟教会你如何让小程序组件库支持多端 - -## 背景 - -上文 [《MorJS 使用社区组件库指南》](https://mor.eleme.io/guides/advance/use-community-component) 我们提到了 MorJS 能够支持在业务转端的同时,将业务所引用的社区组件库一同转端,而针对很多定制属性较强的项目,大多会自行维护一套组件库提供给多个项目使用,本文教会你如何让你的小程序组件库支持多端,与上文的区别在于: - -- 上文是将社区组件库作为源码的一部分,通过 MorJS 编译业务代码的同时,将 node_modules 中的组件也作为源码编译的一部分,生成能够在不同端运行的产物; -- 本文是将小程序组件库单独编译,生成能够分别在不同端引入使用的组件进行发包,支持不同项目自行引用 npm 包,组件库与业务、框架解耦; - -## 已有组件库快速上手 - -组件库转端需要使用 MorJS 提供的一码多端能力,总体流程为: - -项目接入 MorJS => 添加多端编译配置 => 配置脚本 => 编译构建生成产物 => 发包 - -### 接入 MorJS - -在组件库项目中添加必要的依赖: - -```shell -$ npm i @morjs/cli -D && npm i @morjs/core --save -``` - -### 添加配置文件 - -在项目根目录下增加文件 mor.config.ts,修改需要编译的配置 - -```typescript -import { defineConfig, UserConfig } from '@morjs/cli' - -// 公共配置 -const CommonConfig: UserConfig = { - sourceType: 'wechat', // 源码类型: 微信 DSL - srcPath: './src/components', // 源码目录,指定组件库源代码所在的目录 - compileMode: 'default', // 编译模式,由于组件库不是完整项目,需使用转换模式编译 - autoInjectRuntime: { - // 运行时自动注入配置 - api: 'minimal' // API 运行时抹平注入,使用最小替换将仅替换函数调用 - }, - compilerOptions: { - // ts 编译配置 - esModuleInterop: false, // 开启 ES 模块互操作性,针对 ES Module 提供 Commonjs 兼容 - declaration: true, // 生成 (.d.ts) 文件 - target: 'ES5', // 输出的 ES 版本 - module: 'CommonJS' // 模块输出类型 - } -} - -export default defineConfig([ - // 第一套配置: 微信 DSL 编译 - { - ...CommonConfig, - name: 'wx', - target: 'wechat', // 编译目标: 微信 - outputPath: './miniprogram_dist/lib' // 输出产物目录 - }, - // 第二套配置: 微信转支付宝 - { - ...CommonConfig, - name: 'ali', - target: 'alipay', // 编译目标: 支付宝 - outputPath: './alipay/lib' // 输出产物目录 - }, - // 第三套配置: 微信转抖音 - { - ...CommonConfig, - name: 'dy', - target: 'bytedance', // 编译目标: 抖音 - outputPath: './bytedance/lib' // 输出产物目录 - }, - // 第四套配置: 微信转 Web - { - ...CommonConfig, - name: 'web', - target: 'web', // 编译目标: Web - outputPath: './lib' // 输出产物目录 - } -]) -``` - -### 编译调试 - -在项目目录终端下执行编译命令启动项目,即可构建生成对应的多端产物,分别用对应平台的 IDE 打开即可开发预览。 - -你也可以针对不同端,在 package.json 中添加单端的编译命令和相关配置,在终端执行对应的编译命令生成单端的编译产物进行开发调试。 - -相关文档可参考:[《MorJS 基础用法 - 命令行》](https://mor.eleme.io/guides/basic/cli) - -```json -{ - "name": "my-component", - "version": "1.0.0", - "scripts": { - "build": "mor compile --production", // 开启生产环境构建所有端 - "dev:wx": "mor compile --name wx", // 编译构建配置名为 wx 的产物 - "dev:ali": "mor compile --name ali --production", // 编译构建配置名为 ali 的产物 - "dev:dy": "mor compile --name dy --production" // 编译构建配置名为 dy 的产物 - } -} -``` - -### 构建发包 - -在项目目录终端执行打包构建命令编译项目,生成对应的多端产物,产物目录取决与配置文件各端的 outputPath 配置,该目录需要和 package.json 中多端适配输出目录一致。 - -相关文档可参考:[《MorJS - 多端组件库规范》](https://mor.eleme.io/specifications/component) - -```json -{ - "name": "my-component", - "version": "1.0.0", - // 缺省目录设置,未指定端的小程序组件文件会从该目录下获取, - "main": "lib", - // 微信小程序的入口配置 - "miniprogram": "miniprogram_dist", - // 支付宝小程序的入口配置 - "alipay": "alipay", - // 字节小程序的入口配置 - "bytedance": "bytedance", - // 建议配置只输出组件内容目录 - "files": ["lib", "miniprogram_dist", "alipay", "bytedance"] -} -``` - -修改 package.json 的包名 name 和版本号 version,运行 `npm publish` 进行发包。 - -## 开始一个新组件库项目 - -如果你还没有开始写组件库,想要重新开始一个新的多端组件库项目,欢迎你使用官方脚手架工具来创建新项目: - -1. 选定项目目录,并在目录终端执行以下任一命令: - -```shell -$ npm init mor # npm 创建项目 -$ yarn create mor # yarn 创建项目 -$ pnpm create mor # pnpm 创建项目 -``` - -2. 选择工程类型 MorJS 多端组件库,按照提示完成初始化操作 - -```shell -✔ 请选择工程类型 › MorJS 多端组件库 -✔ 请选择源码类型 › 微信小程序 DSL -✔ 请输入 小程序 的名称 … my-components -✔ 请输入 小程序 的描述 … my first components -✔ 用户名 … yourUserName -✔ 邮箱 … your@gmail.com -✔ 请输入 Git 仓库地址 … https://github.com/yourUserName/myapp -✔ 请选择 npm 客户端 › npm / pnpm / yarn -… -``` - -3. 编译与调试,在终端运行 `tnpm run dev`,将生成的产物用各端对应的 IDE 打开进行预览调试 - -4. 构建与发包,在终端运行 `tnpm run build`,生成对应各端的小程序产物,修改 package.json 的包名 name 和版本号 version,运行 `npm publish` 进行发包 - -## Q&A - -- Q: 转端过程中,发现小程序的 JSAPI 转端后不兼容怎么办? -- A: 修改 mor.config.ts 中的 autoInjectRuntime.api 配置,默认 minimal 时只做最小替换,设置为 true 或 enhanced 时,MorJS 会接管 JSAPI 调用并提供接口兼容支持 - ---- - -- Q: 个别情况下,组件转端表现不一致该怎么办? -- A: 各个小程序平台的兼容性问题,超出多端编译覆盖范围的,需要自行处理,可考虑使用条件编译进行分端兼容 - ---- - -- Q: 组件库中使用的字体资源文件会被一同编译吗? -- A: 会,Mor 编译时,针对业务的静态资源会全部拷过去,不依赖构建关系 diff --git a/website/docs/guides/advance/subpackage-volume-optimization.md b/website/docs/guides/advance/subpackage-volume-optimization.md deleted file mode 100644 index 3bcbd7f9..00000000 --- a/website/docs/guides/advance/subpackage-volume-optimization.md +++ /dev/null @@ -1,55 +0,0 @@ -# 主包体积优化 - -## 背景 - -互联网时代中人们对信息的需求逐渐趋向快捷化、方便化、效率化,为了适应快节奏的社会发展,小程序应运而生,作为快时代的产物,各平台小程序逐渐进入大众用户的视野,成为人们生活中不可或缺的一部分,不用安装 APP,不用记住网址,随用随取简单方便。 - -小程序作为轻量级应用,为了保障顺畅运行,各平台对于小程序体积大小有着严格的规定,而随着业务需求的不断累积,通常小程序的体积也在不断增大,官方也推出了支持小程序分包加载功能,将小程序划分成不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载,但是每个使用分包小程序必定含有一个主包。(关于主包分包的概念可参考文档:[复杂小程序集成-概念-模块类型](/guides/advance/complex-miniprogram-integration#%E6%A8%A1%E5%9D%97%E7%B1%BB%E5%9E%8B)) - -以目前几个主流平台为例,支付宝、微信小程序都要求单个分包/主包大小不能超过 2M,所以对于优化小程序主包,降低小程序主包大小,成为大多数开发者都将面临的问题。 - -## 动机 - -主包中并非所有组件、文件都会被主包及多个分包使用,部分公共 js 代码、node_modules 代码和 npm 组件文件可能仅在某一个分包中使用,只要通过解析各文件依赖,建立分组关系,在编译时动态的将文件调配到不同分包中去,让分包自己的模块仅编译到自身路径内,仅分包间共享的模块才会进入主包,对于从未使用(引用)的代码或模块在编译时并不会一同打到产物中,以此用于优化主包体积。 - -相比与主包需要尽可能压缩自身体积,分包显然自身容量有较大的余留,那么把各个分包依赖的内容直接编译到对应分包中去,可以最大化利用分包自身的容量大小,在主包中由于该依赖内容不再有相关使用(引用),根据文件依赖的分析,在编译时这些已被冗余到各个分包的依赖就不会被一同打到主包产物中,减小主包体积的同时提升分包利用率。 - -## 目标 - -- 建立完整的文件依赖关系树和各分包分组信息模型 -- 提供编译时的动态分组优化能力,动态调配不同分包文件 -- 为独立分分包编译提供完整的冗余编译方案 - -## 概念 - -### 模块依赖图 - -1. 模块依赖图:主要用于 Entry 构建的依赖关系建立和动态分组,包含一个小程序主包 mainGroup、一个根模块 rootModule(用于形成带顶端的树状结构, 可减少循环次数及明确父类归属)、N 个普通 Module(随 Entry 分析及文件变化动态删减)、N 个普通 Group(用于各个分包)、N 个 无效的 Module(用于标记被变更或被删除的模块); -2. 普通 Module:一个文件是一个 module,以文件的全路径作为 module 标识,包含 文件地址、依赖信息、被依赖信息 及 分组信息; -3. 普通 Group:模块的分组信息,一个分包对应一个组,包含名称以及相关的模块; - -### 分包动态编译优化 - -分包编译时动态优化,是在编译过程中,通过文件依赖树及分组关系,动态的将文件调配到不同分包中去,比如仅某一个分包使用的 npm 组件提取到自己分包中,以及 node_modules 自动提取到分包中等,分包间共享模块会进入主包,分包自己的模块会进入分包。 - -### 独立分包冗余编译 - -将分包依赖的内容直接编译到对应分包中去,不论这些依赖是否和已有的分包有重叠,也不管是不是主包的组件,都会以冗余的方式编译到每个分包中去,最大化利用分包自身容量大小。 - -## 方案 - -### 模块依赖图 - -一个完整的项目,经过模块依赖图的分析,会给每个文件 Module 进行相关的依赖分析和分组,以文件的全路径作为唯一标识,分析构建其依赖图,对于各分包的文件分组到各自对应分包,对于主包文件若是被多个分包共享依赖则分组到主包,若是仅被某一个分包使用则会动态分组到该分包,而通过这些文件 Module 、分组 Group 等结构组成一张完整的模块依赖图,编译时通过各个文件的文件依赖树和分组关系,对应 entries 的文件信息进行编译产出产物。 - -
- -### 分包动态编译优化 - -分包在执行编译的过程中,编译每个文件时会通过文件依赖树找到对应依赖及其文件信息,根据两者的分组关系,动态将公共 js 代码、node_modules 代码和 npm 组件文件调配到不同分包中去,生成该分包内的公共模块文件,而拆分出来的文件则因为在主包中不被任何其他模块依赖,将从主包编译中删除 - -
- -### 独立分包冗余编译 - -将分包依赖的内容直接编译到对应分包中去,不论这些依赖是否和已有的分包有重叠,也不管是不是主包的组件,都会以冗余的方式编译到每个分包中去,最大化利用分包自身容量大小。 diff --git a/website/docs/guides/advance/unity-of-forms.md b/website/docs/guides/advance/unity-of-forms.md deleted file mode 100644 index 13935351..00000000 --- a/website/docs/guides/advance/unity-of-forms.md +++ /dev/null @@ -1,489 +0,0 @@ -# 小程序形态一体化 - -## 背景 - -随着饿了么的业务场景和范围快速拓展,诞生了诸如: - -- 支付宝小程序作为分包接入微信小程序 -- 淘宝 / 支付宝插件作为分包接入微信小程序 -- 支付宝小程序作为插件接入淘宝小程序插件 -- 支付宝插件作为分包接入微信或抖音小程序 - -等诉求,之前业务的做法是针对每个端,如微信、支付宝、淘宝、抖音,各自维护一套代码,但这样做不仅功能同步迭代周期很长,而且 BUG 较多,迭代维护困难,研发过程异常痛苦。 - -为了解决这个问题,我们从工程化角度出发,期望能够在尽量减少业务代码修改的前提下,以同构的方式支持同一个项目以不同的形态(如小程序、小程序插件和小程序分包)投放在不同的渠道(微信、支付宝、淘宝、抖音等),因而诞生了小程序形态一体化的能力支持。 - -## 能力概览 - -支持小程序、小程序插件以及小程序分包之间的相互转换: - -- **小程序** ↔ **小程序分包** -- **小程序** ↔ **小程序插件** -- **小程序插件** ↔ **小程序分包** -- **小程序插件** ↔ **小程序** -- **小程序分包** ↔ **小程序插件** -- **小程序分包** ↔ **小程序** - -形态转换示意图 👇🏻 - - - -## 形态差异 - -形态差异是指 **小程序**、**小程序分包**、**小程序插件** 三种不同形态的运行方式差异以及转换为其他形态之后产生的差异,具体如下: - -- **`getApp` 差异** - - **小程序:** 可通过 `getApp()` 来获取全局 `App` 实例及实例上挂载的属性或方法 - - **小程序插件:** 无法调用 `getApp()` - - **小程序分包:** 可通过 `getApp()` 来获取全局 `App` 实例及实例上挂载的属性或方法;但当通过小程序转换为分包后,分包自身原本调用的 `getApp` 将失效,并被替换为宿主小程序的 `getApp` -- **`App 应用生命周期` 差异** - - **小程序:** 应用会执行 `onLaunch`、`onShow`、`onHide` 等生命周期 - - **小程序插件:** 无应用生命周期 - - **小程序分包:** 无应用生命周期 -- **`全局样式`(如:`app.wxss` 或 `app.acss`)差异** - - **小程序:** 可通过全局样式来声明全局样式 - - **小程序插件:** 无全局样式 - - **小程序分包:** 无全局样式 -- **`NPM` 使用限制** - - **小程序:** 各个小程序平台支持和限制情况不一 - - **小程序插件:** 各个小程序平台支持和限制情况不一 - - **小程序分包:** 各个小程序平台支持和限制情况不一 -- **`MorJS 运行时插件/解决方案`使用差异** - - **小程序:** 可正常使用 - - **小程序插件:** 因为无 `App` 无法使用 - - **小程序分包:** 因为无 `App` 无法使用 -- **接口调用限制** - - **小程序:** 无限制 - - **小程序插件:** 存在大量的接口调用限制,如 [开发支付宝小程序插件](https://opendocs.alipay.com/mini/plugin/plugin-development) 或 [开发微信小程序插件](https://developers.weixin.qq.com/miniprogram/dev/framework/plugin/development.html) - - **小程序分包:** 无限制 -- **路由差异** - - **小程序:** 转换到其他形态后自身路由会发生变化 - - **小程序插件:** 转换到其他形态后自身路由会发生变化,跳转插件页面需要包含 `plugin://` 或 `dynamic-plugin://` 等前缀,小程序或分包则不需要 - - **小程序分包:** 转换到其他形态后自身路由会发生变化 -- **`getCurrentPages` 差异** - - **小程序:** 无限制 - - **小程序插件:** 无法通过 `getCurrentPages` 获取到小程序的页面堆栈 - - **小程序分包:** 无限制 -- **页面或组件样式差异** - - **小程序:** 无限制 - - **小程序插件:** 基本选择器只支持 ID 与 class 选择器,不支持标签、属性、通配符选择器 - - **小程序分包:** 无限制 - -等等,相关形态差异可结合各个小程序平台查看,这里仅罗列常见的部分。 - -## 解决方案 - -### 适用范围 - -MorJS 的形态一体化方案重点在于解决上述差异中业务难以自行适配的部分,如: - -- `getApp` 差异 -- `App 应用生命周期` 差异 -- `全局样式`(如:`app.wxss` 或 `app.acss`)差异 -- `NPM` 使用限制 -- `MorJS 运行时插件/解决方案` - -等。其他差异,建议业务自行兼容或基于 MorJS 的 [文件纬度条件编译](/guides/conditional-compile/file-level.md) 或 [代码纬度条件编译](/guides/conditional-compile/code-level.md) 来自行分端兼容。 - -### 实现方案 - -为了帮助大家更好的理解一体化方案的逻辑,这里会通过一些示例性的代码来解释下一体化背后的实现思路,实际的实现代码会复杂很多,有兴趣的同学可以直接看 MorJS 源码。 - -#### 入口配置说明 - -不同形态的入口文件可通过配置 `compileType` 来指定: - -- `miniprogram`: 以小程序的方式编译, 入口配置文件为 `app.json` -- `plugin`: 以插件的方式编译, 入口配置文件为 `plugin.json` -- `subpackage`: 以分包的方式编译, 入口配置文件为 `subpackage.json` - -有关 MorJS 配置文件说明可参见文档:[MorJS 基础 - 配置](/guides/basic/config#集成相关配置) - -入口文件配置示例如下: - -```javascript -/* 配置示例 */ - -// 小程序 app.json 配置示例 -// 详细配置可参见微信小程序或支付宝小程序 app.json 配置 -{ - "pages": [ - "pages/todos/todos", - "pages/add-todo/add-todo" - ], - // subpackages 或 subPackages 均可 - "subPackages": [ - { - "root": "my", - "pages": [ - "pages/profile/profile" - ] - } - ] -} - -// 小程序插件 plugin.json 配置示例 -// 详细配置可参见微信小程序或支付宝小程序 plugin.json 配置 -{ - "publicComponents": { - "list": "components/list/list" - }, - "publicPages": { - "hello-page": "pages/index/index" - }, - "pages": [ - "pages/index/index", - "pages/another/index" - ], - // 插件导出的模块文件 - "main": "index.js" -} - -// 小程序分包 subpackage.json 配置示例 -// 配置方式同 app.json 中的 subpackages 的单个分包配置方式一致 -{ - // type 字段为 mor 独有, 用于标识该分包为 "subpackage" 或 "main" - // 区别是: 集成时 "subpackage" 类型的分包会被自动合并到 app.json 的 subpackages 字段中 - // "main" 类型的分包会被自动合并到 app.json 的 pages 字段中 (即: 合并至主包) - "type": "subpackage", - // root 字段将影响集成时分包产物合并至宿主小程序时的根目录 - "root": "my", - // 注意: 编译分包以 pages 作为实际路径进行解析 - "pages": [ - "pages/profile/profile" - ] -} -``` - -默认情况下不同 `compileType` 对应的入口配置文件会直接从 `srcPath` 和 `srcPaths` 所指定的源码目录中直接载入。 - -如需要定制入口配置文件的路径可通过 [customEntries 配置](/guides/basic/config#customentries---自定义入口文件配置) 来自定义。 - -#### 差异抹平思路 - -##### 多形态下的 `getApp` 调用和 `App` 生命周期抹平 - -通过在小程序插件和小程序分包模式下增加 `app.js` 入口文件的支持,并模拟 `App` 生命周期调用和为所有的页面和组件注入 `getApp` 方法来实现,具体可参见下图示例: - - - -##### 多形态下的全局样式支持(如 `app.acss` 或 `app.wxss`) - -小程序编译时通过自动将全局样式文件(`app.acss` 或 `app.wxss` 等)注入到每个页面和组件的样式文件中作为引用来实现对全局样式的兼容,具体可参见下图示例: - - - -##### `NPM` 组件库支持差异抹平 - -基于 MorJS 本身提供的 `bundle` 模式,结合 [多端组件库规范](/specifications/component) 和 [JS 依赖库规范](/specifications/js) 来自动在编译的过程中,自动将小程序、小程序插件、小程序分包的 JS 依赖统一打包并将使用到的组件库自动提取到 `npm_components` 文件夹来规避不同形态下的依赖问题以及不同小程序平台本身的 NPM 支持差异问题,编译流程如下: - - - -## 配置示例 - -业务可参考下方的配置示例来实现小程序形态一体化的配置。 - -### 前置准备 - -相关功能需要以下或更新版本的 MorJS 依赖,开始前请在项目中的 `package.json` 检查并设置。 - -```bash -npm i @morjs/cli@2 -D -npm i @morjs/core@2 --save -``` - -### 小程序转分包 - -#### 1、在项目根目录创建 `subpackage.json` 文件 - -将需要转换为分包的页面填写进去,如: - -```json -{ - "root": "takeout_delicious_food", - "pages": ["index/index"] -} -``` - -注意:当前需要业务方手动添加该文件,如果需要转换的小程序 `app.json` 已存在分包配置,需要将分包中的页面也添加至 `subpackage.json` 的 `pages` 中,注意页面路径为`分包名称+路径`,不要写错。 - -#### 2、在 `mor.config.ts` 文件中增加分包编译配置 - -```typescript -import { defineConfig } from '@morjs/cli' - -export default defineConfig([ - // ⭐️⭐️⭐️ 重点看这里:分包编译配置 ⭐️⭐️⭐️ - { - // 编译名称,可随意修改 - name: 'wechat_subpackage', - // 源码类型, 这里以支付宝小程序 DSL 为例 - sourceType: 'alipay', - target: 'wechat', - // 指定编译类型为分包! - compileType: 'subpackage', - // 分包只能使用 bundle 打包模式 - compileMode: 'bundle', - // 如果分包需要使用宿主的 npm 依赖,且不希望该依赖参与打包 - // 可以在 externals 中指定 npm 包的名称,在项目中正常引用即可 - // 注意:微信环境下需要自行触发 构建 NPM 操作 - externals: [] - } -]) -``` - -完成以上配置后,即可执行对应的分包编译,编译完成后,将对应编译产物文件夹直接放到对应的宿主中即可。 - -#### 3、接入注意事项 - -- 分包的打包模式默认会查找 `mor.subpackage.app.js`,如果该文件不存在,则会直接使用 `app.js`,故小程序转分包如无特别需求可以不使用 `mor.subpackage.app.js`,如果配置了 `mor.subpackage.app.js` 则将使用该文件,并忽略 `app.js`。如果需要两个文件并存,那么可以考虑把公共逻辑抽象到一个单独文件中 -- 分包的打包方式,仅提供直接将完整小程序编译为可直接作为分包运行的文件夹,业务方接入到微信还有一些内容需要适配,差异无法全部抹平,具体参见文档:[《多端差异性总结》](/guides/compatibilities/alipay-to-wechat.md) -- 小程序转分包后, `app.onLaunch` 会在首次打开分包页面时调用,`app.onShow` 以及其他方法如 `onError` 等 不会被调用,这块儿的差异需要业务方自行处理 -- 分包模式会对 `getApp` 方法进行兜底处理,分包模式下通过 `getApp` 调用获得的 `app` 为宿主和分包的混合产物,宿主的属性和方法可以通过 `app.$host` 获取,具体逻辑可以查看产物中的 `mor.subpackage.global.js` 文件 -- 分包模式下如果会将 app.acss 注入到各个页面和组件的样式中作为引用,原因为部分业务团队重度依赖全局样式 -- 业务中如有用到自有封装的 npm package,这部分需要自行确保多端支持 -- 如果需要使用宿主已提供的 npm package,可以将对应的包名添加到上述配置示例的 `externals` 中,然后在项目中正常引用即可。如项目中出现此类需求,建议抽象出来一个单独的 js 文件,可以通过文件或源代码纬度的条件编译来为不同端提供支持,避免造成对业务代码的污染 -- 风险点: 分包没有固定初始化入口,故为了能够正常初始化项目代码,编译时在每个页面和组件的 JS 文件顶部引入了初始化的文件,用于确保分包的初始化 - -### 小程序转插件 - -#### 1、在项目根目录创建 `plugin.json` 文件 - -将需要转换为分包的页面填写进去(这里仅举例支付宝小程序的插件配置,微信略有区别,请自行查看各方文档:[支付宝插件](https://opendocs.alipay.com/mini/plugin/plugin-development) 或 [微信插件](https://developers.weixin.qq.com/miniprogram/dev/framework/plugin/development.html)),如: - -```json -{ - "publicComponents": { - "demo-component": "components/demo/index" - }, - "publicPages": { - "index-page": "pages/index/index" - }, - "pages": ["pages/index/index"], - "main": "index" -} -``` - -注意:当前需要业务方手动添加该文件,如果需要转换的小程序 `app.json` 存在分包配置,需要将分包中的页面也添加至 `plugin.json` 的 `pages` 中,注意页面路径为`分包名称+路径`,不要写错,同时插件需要对外开放的页面需要填写到对应的 `publicPages` 中 。 - -#### 2、在 `mor.config.ts` 文件中增加插件编译配置 - -```typescript -import { defineConfig } from '@morjs/cli' - -export default defineConfig([ - // ⭐️⭐️⭐️ 重点看这里:分包编译配置 ⭐️⭐️⭐️ - { - // 编译名称,可随意修改 - name: 'alipay_plugin', - // 源码类型, 这里以支付宝小程序 DSL 为例 - sourceType: 'alipay', - target: 'alipay' - // 指定编译类型为插件! - compileType: 'plugin', - // 插件只能使用 bundle 打包模式 - compileMode: 'bundle', - // 开启集成模式 - compose: true, - host: { - // miniprogram 为本地的小程序宿主 - // 可自行增加最简单的小程序宿主 - // 也可以使用 mor init 在该文件夹下生成 - file: './miniprogram', - dist: '.' - } - }, -]) -``` - -完成以上配置后,即可执行对应的插件编译,编译完成后,即可在对应的小程序开发者工具中进行调试。 - -#### 3、配置 `index.js` 文件 - -插件可以在 `index.js` 中输出能力,宿主在使用插件运行时插件的时候可以直接通过 `getApp().$plugin.instances.[插件名称]` 来访问到插件输出的能力。 - -```typescript -import { aPlugin } from '@morjs/core' - -class PluginEntry extends aPlugin { - constructor() { - // 必须要调用 super - super({ getApp }) - } - - // 提供了一个方法 x 可以供宿主小程序调用 - x() { - return 1 - } -} - -export default new PluginEntry() -``` - -#### 4、配置已有的 `app.js` 或使用 `mor.plugin.app.js` - -插件工程默认会查找 `mor.plugin.app.js`,如果该文件不存在,则会直接使用 `app.js`,故小程序转插件如无特别需求可以不使用 `mor.plugin.app.js` - -如果配置了 `mor.plugin.app.js` 则将使用该文件,并忽略 `app.js`,如果需要两个文件并存,那么可以考虑把公共逻辑抽象到一个单独文件中 - -```javascript -import { aApp } from '@morjs/core' - -// 和普通小程序一样使用 mor 的运行时解决方案和插件 -import SolutionStandard from 'mor-runtime-solution-standard' - -// 需要加载插件化的运行时解决方案 -import SolutionPlugin from 'mor-runtime-solution-plugin' - -// 初始化app,里面的实例是 getApp 返回的实例 -aApp( - { - onLaunch() { - console.log('plugin app onLaunch') - }, - onShow() { - console.log('plugin app onShow') - }, - onHide() { - console.log('plugin app onHide') - } - }, - [ - SolutionStandard({ exlog: { biz: 'a1.b2' } }), - // 初始化 插件 solution - SolutionPlugin({ type: 'plugin' }) - ] -) -``` - -#### 5、宿主小程序如何对接插件工程? - -##### 如果是 MorJS 标准小程序宿主 - -```javascript -import { aApp } from '@morjs/core' - -// 引入插件 Solution -import SolutionPlugin from 'mor-runtime-solution-plugin' - -aApp( - { - // 业务逻辑代码 - onLaunch(options) { - // 初始化插件调用 - this.$plugin.init({ - plugins: [ - { - // 插件名称,同 app.json 里面的插件配置名称一致 - name: 'myPlugin', - // 如果是动态插件的话,需要传插件 id 和 version - id: '', - version: '', - // 拓展给插件的方法和属性 - extend: { - shopId: '123', - login() { - console.log('call $host login method') - }, - getUserId() { - return '456' - } - } - } - ] - }) - } - }, - [ - // 增加 插件初始化 Solution,并设置类型 type 为 host - SolutionPlugin({ type: 'host' }) - ] -) -``` - -##### 如果是普通小程序宿主 - -```javascript -import PluginSDK from 'mor-runtime-plugin-plugin-init/lib/sdk' - -App({ - // 业务逻辑代码 - onLaunch(options) { - // 初始化 SDK - this.$plugin = new PluginSDK({ $host: this }) - - // 初始化插件调用 - this.$plugin.init({ - plugins: [ - { - // 插件名称,同 app.json 里面的插件配置名称一致 - name: 'myPlugin', - // 如果是动态插件的话,需要传插件 id 和 version - id: '', - version: '', - // 拓展给插件的方法和属性 - extend: { - shopId: '123', - login() { - console.log('call $host login method') - }, - getUserId() { - return '456' - } - } - } - ] - }) - } -}) -``` - -#### 6、接入注意事项 - -1. 小程序转插件的功能和 [MorJS 插件工程](https://yuque.antfin-inc.com/alsc-f2e/mor/plugin-usage) 基本一致,可以点击文档查看具体用法和限制 -2. 宿主需要接入插件 SDK 之后,才具备将宿主方法注入到插件的能力 - -### 插件转分包 - -#### 1、在项目根目录创建 `subpackage.json` 文件 - -将插件的 `plugin.json` 转换为分包的配置,如: - -```json -{ - "root": "takeout_delicious_food", - "pages": ["index/index"] -} -``` - -注意:当前需要业务方手动添加该文件,注意页面路径为`分包名称+路径`,不要写错。 - -#### 2、在 `mor.config.ts` 文件中增加分包编译配置 - -```typescript -{ - // 编译名称,可随意修改 - name: 'wechat_subpackage', - // 源码类型, 这里以支付宝小程序 DSL 为例 - sourceType: 'alipay', - target: 'wechat' - // 指定编译类型为分包! - compileType: 'subpackage', - // 分包只能使用 bundle 打包模式 - compileMode: 'bundle', - // 如果分包需要使用宿主的 npm 依赖,且不希望该依赖参与打包 - // 可以在 externals 中指定 npm 包的名称,在项目中正常引用即可 - // 注意:微信环境下需要自行触发 构建 NPM 操作 - externals: [] - }, -``` - -完成以上配置后,即可执行对应的分包编译,编译完成后,将对应编译产物文件夹直接放到对应的宿主中即可。 - -### 其他情况 - -剩余三种形态转换的配置方式由于和上述三种配置方式类似,这里不再赘述: - -- **分包转插件:** 可参考 [插件转分包](unity-of-forms#插件转分包),思路基本一致 -- **插件转小程序:** 本质上只需要增加 `app.json` 配置文件,修改或新增一套配置并将 `compileType` 指定为 `miniprogram` 即可 -- **分包转小程序:** 本质上只需要增加 `app.json` 配置文件,修改或新增一套配置并将 `compileType` 指定为 `miniprogram` 即可 diff --git a/website/docs/guides/advance/use-community-component.md b/website/docs/guides/advance/use-community-component.md deleted file mode 100644 index 3ec53896..00000000 --- a/website/docs/guides/advance/use-community-component.md +++ /dev/null @@ -1,164 +0,0 @@ -# MorJS 使用社区组件库指南 - -## 背景 - -距离 MorJS 开源已经有一段时间了,随着使用人数的上升,较多开发者将现有小程序项目接入 MorJS 框架都会提出一个疑问,项目中除了开发同学写的原生业务代码外,很多项目还用到了第三方的组件库,这些社区组件库能够被一同转成其他小程序端么? - -答案是:可以,只要是(微信/支付宝)小程序原生开发的组件,理论上是可以一并转换的,使用方式上,需按照对应平台 npm 组件的规范 来使用,本次我们将分别对使用到社群中提及频率较高的 [Vant Weapp](https://github.com/youzan/vant-weapp)、[TDesign](https://github.com/Tencent/tdesign-miniprogram)、[Wux Weapp](https://github.com/wux-weapp/wux-weapp/) 的项目进行转端(如果你的项目选用的是其他组件库,也可以参考以下流程) - -## 一. 项目接入 MorJS - -使用 MorJS 提供的一码多端能力,自然需要用到 MorJS 本身,我们针对不同业务场景,提供了两种接入方式: - -- 新项目使用 create-mor 创建项目,文档参考:[《MorJS - 快速上手》](https://mor.eleme.io/guides/introduction/getting-started) -- 已有项目添加必要依赖进行接入,文档参考:[《MorJS - 原生小程序接入》](https://mor.eleme.io/guides/migrate-from-original-miniprogram-to-mor) - -完成以上接入后,可在项目目录终端下执行编译命令启动项目 npm run dev,多端产物已构建在 dist 目录下,分别用对应平台的 IDE 打开即可开发预览。 - -``` -. -├── dist // 产物目录,可在 mor.config.* 中通过 outputPath 配置进行修改 -│ ├── alipay // 支付宝端产物,可在用支付宝 IDE 进行预览调试 -│ ├── wechat // 微信端产物,可在用微信 IDE 进行预览调试 -│ └── web // 转 web 产物,可在浏览器中进行预览调试 -├── node_modules // 安装 node 后用来存放用包管理工具下载安装的包的文件夹 -├── src // 源码目录,可在 mor.config.* 中通过 srcPath 配置进行修改 -├── mor.config.ts // MorJS 配置文件,用于提供多套编译配置 -└── package.json // 项目的基础配置文件 -``` - -## 二. 项目接入社区组件库 - -根据对应的社区组件库文档进行接入,如果你的项目选用的是其他组件库,也可以参考以下流程进行接入。 - -请注意,项目所使用的组件库和项目的小程序 DSL 需要为同一套源码,例如选择使用微信 DSL 写的项目,引入的组件库需要是 for 微信小程序的组件库,支付宝 DSL 亦然。 - -### 接入 [Vant Weapp](https://github.com/youzan/vant-weapp) 流程 - -1. 安装:通过 npm 安装组件库 `npm i @vant/weapp -S --production` -2. 配置:MorJS 工程默认配置下,可直接跳过这步 - -- app.json 配置:小程序新版组件库与 [Vant Weapp](https://github.com/youzan/vant-weapp) 可能存在一定样式冲突问题,请根据业务需求及项目表现,自行决定是否需要去除新版基础组件样式,如需去除删除 app.json 文件的 `"style": "v2"` 配置项即可 -- project.config.json 配置:MorJS 默认的 bundle 模式无需修改此项配置 -- 构建 npm 包:MorJS 默认的 bundle 模式无需构建此项 -- typescript 支持:MorJS 本身支持 typescript,无需配置此项 - -3. 使用:在对应的 json 文件中配置所用组件对应的路径,在 xml 中直接使用组件即可 - -> 配置组件路径有两种方式:可以按照 组件库规范 来引用组件,或按照实际路径引用组件 - -```json -{ - "usingComponents": { - "van-button": "@vant/weapp/button/index", // 按照规范引用 button 组件 - "van-popup": "@vant/weapp/lib/popup/index" // 按照实际路径引用 popup 组件 - } -} -``` - -### 接入 [TDesign](https://github.com/Tencent/tdesign-miniprogram) 流程 - -1. 安装:通过 npm 安装组件库 `npm i tdesign-miniprogram -S --production` -2. 配置:MorJS 工程默认配置下,可直接跳过这步 - -- app.json 配置:小程序新版组件库与 [TDesign](https://github.com/Tencent/tdesign-miniprogram) 可能存在一定样式冲突问题,请根据业务需求及项目表现,自行决定是否需要去除新版基础组件样式,如需去除删除 app.json 文件的 `"style": "v2"` 配置项即可 -- 构建 npm 包:MorJS 默认的 bundle 模式无需构建此项 -- typescript 支持:MorJS 本身支持 typescript,无需配置此项 - -3. 使用:在对应的 json 文件中配置所用组件对应的路径,在 xml 中直接使用组件即可 - -> 配置组件路径有两种方式:可以按照 组件库规范 来引用组件,或按照实际路径引用组件 - -```json -{ - "usingComponents": { - "van-button": "tdesign-miniprogram/button/button", // 按照规范引用 button 组件 - "van-popup": "tdesign-miniprogram/miniprogram_dist/popup/popup" // 按照实际路径引用 popup 组件 - } -} -``` - -### 接入 [Wux Weapp](https://github.com/wux-weapp/wux-weapp/) 流程 - -1. 安装:通过 npm 安装组件库 `npm i wux-weapp -S --production` -2. 配置:MorJS 工程默认配置下,无需进行 npm 构建或单独拷贝组件产物 -3. 使用:在对应的 json 文件中配置所用组件对应的路径,在 xml 中直接使用组件即可 - -> 配置组件路径有两种方式:可以按照 组件库规范 来引用组件,或按照实际路径引用组件 - -```json -{ - "usingComponents": { - "van-button": "wux-weapp/button/index", // 按照规范引用 button 组件 - "van-popup": "wux-weapp/packages/lib/popup/index" // 按照实际路径引用 popup 组件 - } -} -``` - -## 三. 添加组件库转端配置 - -接入社区组件库后,执行编译命令 npm run dev 启动项目会发现,仅本端的编译是正常执行的,转为其他端的编译会报类似 Can't resolve 'xxx' in 'xxx' 的错误,这是因为 MorJS 默认是不会在编译环节动态编译处理 node_modules 的 NPM 组件的,所以导致引入使用的组件无法载入,需要通过添加 mor.config.ts 中的 processNodeModules 配置,让编译环节处理 node_modules 中的组件 - -相关文档可参考:[《MorJS 基础用法 - 配置 processNodeModules》](https://mor.eleme.io/guides/basic/config/#processnodemodules---%E6%98%AF%E5%90%A6%E5%A4%84%E7%90%86-node_modules) - -```typescript -import { defineConfig } from '@morjs/cli' - -export default defineConfig([ - { - name: 'ali', - sourceType: 'wechat', // 源码类型: 微信 DSL - target: 'alipay', // 编译目标: 支付宝小程序 - processNodeModules: { - include: [ - /@vant\/weapp/, // 添加处理 @vant/weapp 组件 - /tdesign\-miniprogram/, // 添加处理 tdesign-miniprogram 组件 - /wux\-weapp/ // 添加处理符合 wux-weapp 组件 - ] - } - } -]) -``` - -> 之所以 MorJS 编译默认不处理 node_modules 的 NPM 组件,原因大致有以下几点: - -- 动态编译性能差:node_modules 里面文件繁多,需要所有文件都去判断是否需要进行编译处理,效率较低,会一定程度上影响编译效率; -- 排查问题困难:动态转换会变成黑箱,使用方无法直接感知到转换过程中所做的处理; -- 无法直接给原生小程序复用:组件在满足一定条件下,是可以同时给非 MorJS 的小程序工程使用的,如果采用动态编译就能且只能给 MorJS 工程使用; -- 降低了组件提供方的自测责任:在 NPM 组件 输出时直接提供了编译后产物,能够要求 NPM 组件 做好对应测试,而不是依赖于 MorJS 动态编译来确保可用性; -- … - -## 四. 编译调试 - -在项目目录终端下执行编译命令启动项目,即可构建生成对应的多端产物,默认是放在项目 dist 目录下,分别用对应平台的 IDE 打开即可开发预览。 - -你也可以针对不同端,在 package.json 中添加单端的编译命令和相关配置,在终端执行对应的编译命令生成单端的编译产物进行开发调试。 - -相关文档可参考:[《MorJS 基础用法 - 命令行》](https://mor.eleme.io/guides/basic/cli) - -```json -{ - "scripts": { - "dev": "mor compile -w", // 编译构建所有端并开启文件变更监听 - "dev:ali": "mor compile --name ali", // 编译构建配置名为 ali 的产物 - "dev:wx": "mor compile --name wx", // 编译构建配置名为 wx 的产物 - "dev:dy": "mor compile --name dy", // 编译构建配置名为 dy 的产物 - "build": "mor compile --production" // 开启生产环境构建所有端 - } -} -``` - -## Q&A - -- Q: 为什么 MorJS 接入组件库不需要执行 IDE 构建 npm 包? -- A: 默认的 bundle 打包模式下,MorJS 会生成闭包并基于规则合并 js 文件,同时将小程序多端组件自动提取到产物对应的 npm_components 目录,但如果 compileMode 配置的是 transform 模式,会因为该编译模式下并不处理 node_modules 和多端组件,所以得走常规的微信构建 npm - ---- - -- Q: 为什么我按照规范(xxx/button/index)引用组件转其他端会报 Can't resolve 'xxx' in 'xxx' 的错误? -- A: MorJS 是通过目录结构结合 package.json 的 [目录指向字段配置](https://mor.eleme.io/specifications/component#%E7%9B%AE%E5%BD%95%E5%AD%97%E6%AE%B5%E9%85%8D%E7%BD%AE) 来实现的,若转端读取的字段入口对应目录下没有组件产物,编译引入组件时将报上述错误,可以把使用路径改为组件实际路径,或联系组件开发者补充 main 入口字段 - ---- - -- Q: 社区组件库中使用的字体资源文件会被一同编译吗? -- A: 不会,针对 node_modules 中的非预期文件类型不会进行处理,请把资源文件改为引用 cdn 资源 diff --git a/website/docs/guides/basic/cli.md b/website/docs/guides/basic/cli.md deleted file mode 100644 index b3685ec2..00000000 --- a/website/docs/guides/basic/cli.md +++ /dev/null @@ -1,223 +0,0 @@ -# 命令行 - -## 概览 - -可通过 `mor -h` 查看帮助信息。 - -命令说明: `[]` 代表可选参数, `<>` 代表必填参数 - -```bash -.__ __ ___ ____ ____ _ ___ -| \/ | / _ \ | _ \ / ___|| | |_ _| -| |\/| || | | || |_) | | | | | | | -| | | || |_| || _ < | |___ | |___ | | -|_| |_| \___/ |_| \_\ \____||_____||___| - -用法: - $ mor - -命令: - 默认选项描述 - compile 编译小程序工程 - clean 清理 mor 清理缓存/临时目录 - compose 小程序集成功能 - generate [...args] 生成器, 命令别名 [g] - init [projectDir] 初始化/创建 MorJS 项目、插件、脚手架等, 命令别名 [create] - analyze 分析小程序相关 bundle 信息 - -更多信息可通过 `--help` 选项,运行下方命令获取: - $ mor --help - $ mor compile --help - $ mor clean --help - $ mor compose --help - $ mor generate --help - $ mor init --help - $ mor analyze --help - -选项: - --verbose 开启框架调试日志 - -h, --help 显示帮助信息 - -v, --version 显示版本信息 - --cwd 当前工作目录, 默认为 process.cwd() - -c, --config 指定自定义配置文件路径, 支持 .ts, .js, .mjs, .json, .jsonc, .json5 等类型, 如 mor.config.ts - --ignore-config 忽略或不自动载入用户配置文件 - --no-autoload-plugins 关闭自动载入插件功能 (默认: true) - --name 指定配置名称, 如不指定则代表选择所有配置 - --plugins 指定需要运行的插件, 如: plugin1,plugin2 -``` - -## 编译命令 — `compile` - -可通过 `mor compile -h` 查看帮助信息。 - -```bash -用法: - $ mor compile 编译命令 - - 支持的小程序或应用类型 (target): - alipay 支付宝小程序 - baidu 百度小程序 - bytedance 字节小程序 - dingding 钉钉小程序 - kuaishou 快手小程序 - qq QQ 小程序 - taobao 淘宝小程序 - web Web 应用 - wechat 微信小程序 - -选项: - --source-type 源码类型, 用于判断小程序页面或组件使用了哪种 DSL, 可选值为 wechat, alipay - -t, --target 编译目标, 将当前的工程编译为目标小程序工程, 可选值为 alipay, wechat, baidu, bytedance, qq, taobao, dingding, kuaishou, web, eleme - --compile-mode 编译模式, 将当前工程以指定的编译模式编译, 编译模式差异参见官方文档, 可选值为 bundle, transform, transfer, default - --compile-type 编译形态, 将当前工程编译为指定形态, 可选值为 miniprogram, plugin, subpackage - -d, --devtool [devtool] 开发工具, 控制是否生成, 以及如何生成 source map, 参见 https://webpack.js.org/configuration/devtool - --no-devtool 关闭 devtool (默认: true) - --mock 是否开启 mock 功能, --production 状态下会自动关闭 mock 功能 - --minimize 是否开启压缩, --production 状态下会自动开启 (默认: false) - --js-minimizer [minimizer] JS 代码压缩器, 可选值为 terser, esbuild, swc - --no-js-minimizer 关闭 JS 压缩 (默认: true) - --css-minimizer [minimizer] CSS 代码压缩器, 默认为 esbuild, 可选值为 esbuild, csso, cssnano, cleancss, parcelcss - --no-css-minimizer 关闭 CSS 压缩 (默认: true) - --xml-minimizer XML 代码压缩器, 目前仅支持 html-terser - --no-xml-minimizer 关闭 XML 压缩 (默认: true) - --mode 开发模式, 设置开发模式, 可选值为 production, development, none - --production 是否开启生产模式, 等同于 --mode production - --auto-clean 是否自动清空输出目录, (默认: false) - -w, --watch 是否开启监听模式, (默认: false) - -s, --src-path 源代码根目录, 默认为 src - -o, --output-path 编译产物输出目录, 不同的 target 会有默认的输出目录, 如 dist/wechat - --ignore 忽略文件或目录, 各个配置中的 outputPath 会被自动添加到忽略目录 - --no-cache 是否关闭缓存 (默认: true) - --cache 是否开启缓存, mode = development 下默认开启, mode = production 状态下默认关闭 (默认: null) - --process-node-modules 是否自动处理 node_modules 中的多端组件库, 默认情况为 false, 开启后会自动处理 node_modules 中的文件的转端 - --global-object 全局对象配置, 不同的 target 会有默认的全局对象, 通常情况下无需设置 - --analyze 是否开启 bundle analyzer - --no-progress 关闭进度显示 (默认: true) - --emit-web-intermediate-assets 生成 web 转端中间产物 (方便调试) - --compose 开启小程序集成功能 - --with-modules 指定需要参与集成的模块, 支持 glob 模式, 该配置需要开启集成后生效 - --without-modules 排除不需要集成的模块, 支持 glob 模式, 该配置需要开启集成后生效 - --from-state 控制模块集成时的初始状态, 可选值: 0-6, 该配置需要开启集成后生效 - --to-state 控制模块集成时的最终状态, 可选值: 0-6, 该配置需要开启集成后生效 - --concurrency 控制模块集成时的并发数量 - --combine-modules 合并模块配置 (主要用于合并分包配置的页面到主包中) - --verbose 开启框架调试日志 - -h, --help 显示帮助信息 - --cwd 当前工作目录, 默认为 process.cwd() - -c, --config 指定自定义配置文件路径, 支持 .ts, .js, .mjs, .json, .jsonc, .json5 等类型, 如 mor.config.ts - --ignore-config 忽略或不自动载入用户配置文件 - --no-autoload-plugins 关闭自动载入插件功能 (默认: true) - --name 指定配置名称, 如不指定则代表选择所有配置 - --plugins 指定需要运行的插件, 如: plugin1,plugin2 -``` - -## 清理命令 — `clean` - -可通过 `mor clean -h` 查看帮助信息。 - -```bash -用法: - $ mor clean 清理缓存/临时目录 - -选项: - --verbose 开启框架调试日志 - -h, --help 显示帮助信息 - --cwd 当前工作目录, 默认为 process.cwd() - -c, --config 指定自定义配置文件路径, 支持 .ts, .js, .mjs, .json, .jsonc, .json5 等类型, 如 mor.config.ts - --ignore-config 忽略或不自动载入用户配置文件 - --no-autoload-plugins 关闭自动载入插件功能 (默认: true) - --name 指定配置名称, 如不指定则代表选择所有配置 - --plugins 指定需要运行的插件, 如: plugin1,plugin2 -``` - -## 集成命令 — `compose` - -可通过 `mor compose -h` 查看帮助信息。 - -```bash -用法: - $ mor compose - -选项: - --with-modules 指定需要参与集成的模块, 支持 glob 模式, 该配置需要开启集成后生效 - --without-modules 排除不需要集成的模块, 支持 glob 模式, 该配置需要开启集成后生效 - --from-state 控制模块集成时的初始状态, 可选值: 0-6, 该配置需要开启集成后生效 - --to-state 控制模块集成时的最终状态, 可选值: 0-6, 该配置需要开启集成后生效 - --concurrency 控制模块集成时的并发数量 - --combine-modules 合并模块配置 (主要用于合并分包配置的页面到主包中) - --verbose 开启框架调试日志 - -h, --help 显示帮助信息 - --cwd 当前工作目录, 默认为 process.cwd() - -c, --config 指定自定义配置文件路径, 支持 .ts, .js, .mjs, .json, .jsonc, .json5 等类型, 如 mor.config.ts - --ignore-config 忽略或不自动载入用户配置文件 - --no-autoload-plugins 关闭自动载入插件功能 (默认: true) - --name 指定配置名称, 如不指定则代表选择所有配置 - --plugins 指定需要运行的插件, 如: plugin1,plugin2 -``` - -## 分析命令 — `analyze` - -可通过 `mor analyze -h` 查看帮助信息。 - -```bash -用法: - $ mor analyze - -选项: - --mode 依赖分析模式, 可选值为 server, static, json, disabled - --host 依赖分析 HTTP 服务域名, 仅在 mode 为 server 时生效 - --port 依赖分析 HTTP 服务端口号, 仅在 mode 为 server 时生效 - --report-filename 生成报告文件的名称, 仅在 mode 为 static 时生效 - --report-title 生成报告文件的标题, 仅在 mode 为 static 时生效 - --default-sizes 分析报告中展示模块大小的定义方式, 可选值为 stat, parsed, gzip - --open 浏览器中打开 - --no-open 不在浏览器中打开 (默认: true) - --generate-stats-file 是否生成 stats 文件 - --stats-filename stats 文件名称 - --verbose 开启框架调试日志 - -h, --help 显示帮助信息 - --cwd 当前工作目录, 默认为 process.cwd() - -c, --config 指定自定义配置文件路径, 支持 .ts, .js, .mjs, .json, .jsonc, .json5 等类型, 如 mor.config.ts - --ignore-config 忽略或不自动载入用户配置文件 - --no-autoload-plugins 关闭自动载入插件功能 (默认: true) - --name 指定配置名称, 如不指定则代表选择所有配置 - --plugins 指定需要运行的插件, 如: plugin1,plugin2 -``` - -## 脚手架命令 — `create` 或 `init` - -可通过 `mor generate -h` 查看帮助信息 - -```bash -用法: - $ mor init [projectDir] - -选项: - --template, -t