diff --git a/examples/with-rax-mpa/build.json b/examples/with-rax-mpa/build.json index 36274c827..54274f427 100644 --- a/examples/with-rax-mpa/build.json +++ b/examples/with-rax-mpa/build.json @@ -1,14 +1,9 @@ { - "targets": ["web", "weex", "kraken"], - "weex": { + "targets": ["harmony"], + "harmony": { "mpa": true }, - "kraken": { - "mpa": true - }, - "web": { - "mpa": true - }, - "swc": true, + "minify": false, + "compileDependencies": [], "webpack5": true } diff --git a/examples/with-rax-mpa/src/app-worker.ts b/examples/with-rax-mpa/src/app-worker.ts new file mode 100644 index 000000000..844159649 --- /dev/null +++ b/examples/with-rax-mpa/src/app-worker.ts @@ -0,0 +1,5 @@ +export default { + onCreate() { + console.info('app created'); + } +} diff --git a/examples/with-rax-mpa/src/app.json b/examples/with-rax-mpa/src/app.json index 88d3d6fed..7796e5b06 100644 --- a/examples/with-rax-mpa/src/app.json +++ b/examples/with-rax-mpa/src/app.json @@ -4,10 +4,6 @@ "name": "home", "source": "pages/Home/index", "spm": "b456" - }, - { - "name": "about", - "source": "pages/About/app" } ], "spm": "a123", diff --git a/examples/with-rax-mpa/src/components/Logo/index.tsx b/examples/with-rax-mpa/src/components/Logo/index.tsx index aaef65e4c..f006aa7db 100644 --- a/examples/with-rax-mpa/src/components/Logo/index.tsx +++ b/examples/with-rax-mpa/src/components/Logo/index.tsx @@ -1,17 +1,13 @@ import { createElement, PureComponent } from 'rax'; -import Image from 'rax-image'; import './index.css'; class Logo extends PureComponent { render() { - const source = { - uri: `${process.env.PUBLIC_URL}/rax.png`, - }; return ( - ); } diff --git a/examples/with-rax-mpa/src/pages/About/app.json b/examples/with-rax-mpa/src/pages/About/app.json deleted file mode 100644 index 23abfb45d..000000000 --- a/examples/with-rax-mpa/src/pages/About/app.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "routes": [ - { - "path": "/", - "source": "./index" - } - ], - "window": { - "title": "Rax App" - } -} diff --git a/examples/with-rax-mpa/src/pages/About/app.ts b/examples/with-rax-mpa/src/pages/About/app.ts deleted file mode 100644 index 1b97b148c..000000000 --- a/examples/with-rax-mpa/src/pages/About/app.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { runApp } from 'rax-app'; -import staticConfig from './app.json'; - -runApp({ - app: { - onShow() { - console.log('app show...'); - }, - onHide() { - console.log('app hide...'); - }, - getInitialData: async () => { - return { - a: 1, - b: 2, - }; - }, - }, -}, staticConfig); diff --git a/examples/with-rax-mpa/src/pages/About/index.css b/examples/with-rax-mpa/src/pages/About/index.css deleted file mode 100644 index 85ae2d072..000000000 --- a/examples/with-rax-mpa/src/pages/About/index.css +++ /dev/null @@ -1,16 +0,0 @@ -.about { - align-items: center; - margin-top: 200rpx; -} - -.title { - font-size: 45rpx; - font-weight: bold; - margin: 20rpx 0; -} - -.info { - font-size: 36rpx; - margin: 8rpx 0; - color: #555; -} diff --git a/examples/with-rax-mpa/src/pages/About/index.tsx b/examples/with-rax-mpa/src/pages/About/index.tsx deleted file mode 100644 index 497f0c129..000000000 --- a/examples/with-rax-mpa/src/pages/About/index.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { createElement, PureComponent } from 'rax'; -import View from 'rax-view'; -import Text from 'rax-text'; -import './index.css'; - -class About extends PureComponent { - render() { - return ( - - About Page - - ); - } -} - -export default About; diff --git a/examples/with-rax-mpa/src/pages/Home/index.css b/examples/with-rax-mpa/src/pages/Home/index.css index a8814796d..419d53f7a 100644 --- a/examples/with-rax-mpa/src/pages/Home/index.css +++ b/examples/with-rax-mpa/src/pages/Home/index.css @@ -1,16 +1,24 @@ .home { + box-sizing: border-box; + display: flex; + flex-direction: column; + flex-shrink: 0; + align-content: flex-start; align-items: center; margin-top: 200rpx; + width: 100%; } .title { font-size: 35rpx; font-weight: bold; margin: 20rpx 0; + display: block; } .info { font-size: 36rpx; margin: 8rpx 0; color: #555; + display: block; } diff --git a/examples/with-rax-mpa/src/pages/Home/index.tsx b/examples/with-rax-mpa/src/pages/Home/index.tsx index 7febb5b2d..394e80a80 100644 --- a/examples/with-rax-mpa/src/pages/Home/index.tsx +++ b/examples/with-rax-mpa/src/pages/Home/index.tsx @@ -1,16 +1,14 @@ import { createElement } from 'rax'; -import View from 'rax-view'; -import Text from 'rax-text'; import Logo from '@/components/Logo'; import './index.css'; export default function Home(props) { return ( - - - Welcome to Your Rax App - More information about Rax - +
+ + Welcome to Your Rax App + More information about Rax +
); } diff --git a/packages/platform-loader/src/TraverseImport.js b/packages/platform-loader/src/TraverseImport.js index 20f85fe3c..3eff33b1a 100644 --- a/packages/platform-loader/src/TraverseImport.js +++ b/packages/platform-loader/src/TraverseImport.js @@ -20,6 +20,7 @@ module.exports = function traverseImport(options, inputSource, sourceMapOption) 'bytedance-microapp': ['isByteDanceMicroApp'], 'kuaishou-miniprogram': ['isKuaiShouMiniProgram'], 'baidu-smartprogram': ['isBaiduSmartProgram'], + harmony: ['isHarmony'], }; /** diff --git a/packages/plugin-rax-app/src/constants.js b/packages/plugin-rax-app/src/constants.js index 99df5afe3..4b0cef0d6 100644 --- a/packages/plugin-rax-app/src/constants.js +++ b/packages/plugin-rax-app/src/constants.js @@ -6,6 +6,7 @@ module.exports = { SSR: 'ssr', WEEX: 'weex', KRAKEN: 'kraken', + HARMONY: 'harmony', MINIAPP, WECHAT_MINIPROGRAM, BYTEDANCE_MICROAPP, diff --git a/packages/plugin-rax-app/src/launch/setupBuild.ts b/packages/plugin-rax-app/src/launch/setupBuild.ts index 742aa09b9..8d5397df8 100644 --- a/packages/plugin-rax-app/src/launch/setupBuild.ts +++ b/packages/plugin-rax-app/src/launch/setupBuild.ts @@ -9,6 +9,7 @@ import { WEB, WEEX, KRAKEN, + HARMONY, } from '../constants'; const highlightPrint = chalk.hex('#F4AF3D'); @@ -74,6 +75,15 @@ export default (api) => { console.log(); } }); + + if (targets.includes(HARMONY)) { + console.log(highlightPrint('[HARMONY] Bundle at:')); + console.log( + ' ', + chalk.underline.white(path.resolve(rootDir, outputDir, HARMONY)), + ); + console.log(); + } } }); }; diff --git a/packages/plugin-rax-app/src/launch/setupDev.ts b/packages/plugin-rax-app/src/launch/setupDev.ts index cb807321f..0883f89db 100644 --- a/packages/plugin-rax-app/src/launch/setupDev.ts +++ b/packages/plugin-rax-app/src/launch/setupDev.ts @@ -8,7 +8,7 @@ import chokidar from 'chokidar'; import { platformMap } from 'miniapp-builder-shared'; import logWebpackConfig from '../utils/logWebpackConfig'; -import { MINIAPP_PLATFORMS, MINIAPP, WEB, WEEX, KRAKEN, DEV_URL_PREFIX } from '../constants'; +import { MINIAPP_PLATFORMS, MINIAPP, WEB, WEEX, KRAKEN, DEV_URL_PREFIX, HARMONY } from '../constants'; import generateTempFile from '../utils/generateTempFile'; const highlightPrint = chalk.hex('#F4AF3D'); @@ -20,6 +20,7 @@ interface IDevInfo { weex?: string[]; kraken?: string[]; pha?: string[]; + harmony?: string[]; }; compiledTime?: number; publicPath?: string; @@ -51,9 +52,11 @@ export default function (api) { let webEntryKeys = []; let weexEntryKeys = []; let krakenEntryKeys = []; + let harmonyEntryKeys = []; let webMpa = false; let weexMpa = false; let krakenMpa = false; + let harmonyMpa = false; let isFirstCompile = true; let pha = false; watchAppJson(rootDir, log); @@ -78,16 +81,19 @@ export default function (api) { const webWebpackInfo = getWebpackInfo(configs, 'web'); const weexWebpackInfo = getWebpackInfo(configs, 'weex'); const krakenWebpackInfo = getWebpackInfo(configs, 'kraken'); + const harmonyWebpackInfo = getWebpackInfo(configs, 'harmony'); devInfo.publicPath = webWebpackInfo.publicPath; webEntryKeys = Object.keys(webWebpackInfo.entry); weexEntryKeys = Object.keys(weexWebpackInfo.entry); krakenEntryKeys = Object.keys(krakenWebpackInfo.entry); + harmonyEntryKeys = Object.keys(harmonyWebpackInfo.entry); webMpa = userConfig.web && userConfig.web.mpa; weexMpa = userConfig.weex && userConfig.weex.mpa; krakenMpa = userConfig.kraken && userConfig.kraken.mpa; + harmonyMpa = userConfig.harmony && userConfig.harmony.mpa; pha = userConfig.web && userConfig.web.pha; // Remove outputDir when start devServer @@ -212,6 +218,18 @@ export default function (api) { }); } + if (targets.includes(HARMONY)) { + devInfo.urls.harmony = []; + // Use Weex App to scan ip address (mobile phone can't visit localhost). + console.log(highlightPrint(' [Harmony] Development server at: ')); + weexEntryKeys.forEach((entryKey) => { + const harmonyUrl = `${urlPrefix}/harmony/${harmonyMpa ? entryKey : 'index'}.js`; + devInfo.urls.weex.push(harmonyUrl); + console.log(` ${chalk.underline.white(harmonyUrl)}`); + console.log(); + }); + } + /** * @TODO: Delete it first, and then open it after the PHA supports it */ diff --git a/packages/plugin-rax-app/src/userConfig/atoms/inlineStyle.js b/packages/plugin-rax-app/src/userConfig/atoms/inlineStyle.js index 51e407241..e682a1c1d 100644 --- a/packages/plugin-rax-app/src/userConfig/atoms/inlineStyle.js +++ b/packages/plugin-rax-app/src/userConfig/atoms/inlineStyle.js @@ -1,4 +1,4 @@ -const { WEB, WEEX, DOCUMENT, SSR, KRAKEN, MINIAPP, WECHAT_MINIPROGRAM, BYTEDANCE_MICROAPP, BAIDU_SMARTPROGRAM, KUAISHOU_MINIPROGRAM } = require('../../constants'); +const { WEB, WEEX, DOCUMENT, SSR, KRAKEN, MINIAPP, WECHAT_MINIPROGRAM, BYTEDANCE_MICROAPP, BAIDU_SMARTPROGRAM, KUAISHOU_MINIPROGRAM, HARMONY } = require('../../constants'); const { createCSSRule } = require('rax-webpack-config'); const { isWebpack4 } = require('@builder/compat-webpack4'); const getPostCssPlugin = require('../../getPostCssPlugin'); @@ -8,7 +8,9 @@ const webStandardList = [ ]; const inlineStandardList = [ - WEEX, KRAKEN, + WEEX, + KRAKEN, + HARMONY, ]; const miniappStandardList = [ diff --git a/packages/plugin-rax-harmony/CHANGELOG.md b/packages/plugin-rax-harmony/CHANGELOG.md new file mode 100644 index 000000000..ee12962c6 --- /dev/null +++ b/packages/plugin-rax-harmony/CHANGELOG.md @@ -0,0 +1,3 @@ +# Changelog + +## v1.0.0 diff --git a/packages/plugin-rax-harmony/package.json b/packages/plugin-rax-harmony/package.json new file mode 100644 index 000000000..55838d61f --- /dev/null +++ b/packages/plugin-rax-harmony/package.json @@ -0,0 +1,31 @@ +{ + "name": "build-plugin-rax-harmony", + "version": "1.0.0", + "description": "rax harmony app plugin", + "main": "lib/index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "files": [ + "lib", + "!lib/**/*.map" + ], + "keywords": [ + "plugin", + "rax" + ], + "author": "Rax Team", + "license": "MIT", + "peerDependencies": { + "build-scripts": "^1.0.0", + "rax": "^1.0.0" + }, + "dependencies": { + "@builder/mpa-config": "^4.0.0", + "fs-extra": "^9.0.1", + "@builder/app-helpers": "^2.1.0", + "react-dev-utils": "^11.0.0", + "loader-utils": "^2.0.0", + "@builder/compat-webpack4": "^1.0.0" + } +} diff --git a/packages/plugin-rax-harmony/src/BundleShellPlugin/LiteShell.ts b/packages/plugin-rax-harmony/src/BundleShellPlugin/LiteShell.ts new file mode 100644 index 000000000..5f5acf5fd --- /dev/null +++ b/packages/plugin-rax-harmony/src/BundleShellPlugin/LiteShell.ts @@ -0,0 +1,17 @@ +import BaseShell from './Shell'; + +const requireModuleMethod = ` +function requireModule(moduleName) { + return requireNative(moduleName.slice(1)); +} +`; + +export default class LiteShell extends BaseShell { + generateApp() { + return `${requireModuleMethod} + var options = ${this.content}; + + new ViewModule(options); + `; + } +} diff --git a/packages/plugin-rax-harmony/src/BundleShellPlugin/RichShell.ts b/packages/plugin-rax-harmony/src/BundleShellPlugin/RichShell.ts new file mode 100644 index 000000000..96f622a08 --- /dev/null +++ b/packages/plugin-rax-harmony/src/BundleShellPlugin/RichShell.ts @@ -0,0 +1,90 @@ +import getPageName from '../utils/getPageName'; +import BaseShell from './Shell'; + +const requireModuleMethod = ` +function requireModule(moduleName) { + const systemList = ['system.router', 'system.app', 'system.prompt', 'system.configuration', + 'system.image', 'system.device', 'system.mediaquery', 'ohos.animator', 'system.grid', 'system.resource'] + var target = '' + if (systemList.includes(moduleName.replace('@', ''))) { + target = $app_require$('@app-module/' + moduleName.substring(1)); + return target; + } + var shortName = moduleName.replace(/@[^.]+\.([^.]+)/, '$1'); + target = requireNapi(shortName); + if (target !== 'undefined' && /@ohos/.test(moduleName)) { + return target; + } + if (typeof ohosplugin !== 'undefined' && /@ohos/.test(moduleName)) { + target = ohosplugin; + for (let key of shortName.split('.')) { + target = target[key]; + if(!target) { + break; + } + } + if (typeof target !== 'undefined') { + return target; + } + } + if (typeof systemplugin !== 'undefined') { + target = systemplugin; + for (let key of shortName.split('.')) { + target = target[key]; + if(!target) { + break; + } + } + if (typeof target !== 'undefined') { + return target; + } + } + return target; +} +`; + +export default class RichShell extends BaseShell { + generateApp() { + return ` + $app_define$('@app-application/app', [], function($app_require$, $app_exports$, $app_module$) { + ${requireModuleMethod} + + ${this.content}; + + $app_exports$.default = result.default; + $app_exports$.manifest = ${JSON.stringify(this.pluginOptions.manifest)}; + $app_module$.exports = $app_exports$.default; + }); + + $app_bootstrap$('@app-application/app', undefined, undefined); + `; + } + + generatePage() { + const pageName = getPageName(this.options.filename); + return ` + $app_define$('@app-component/${pageName}', [], function($app_require$, $app_exports$, $app_module$) { + ${requireModuleMethod} + + $app_exports$.default = { + onReady() { + var document = this.app.doc; + document.body.__rendered = true; + ${this.content} + } + }; + + $app_module$.exports = $app_exports$.default; + + $app_module$.exports.template = { + type: 'div', + children: [], + }; + + $app_module$.exports.style = {}; + }); + + $app_bootstrap$('@app-component/${pageName}', undefined, undefined); + `; + } +} diff --git a/packages/plugin-rax-harmony/src/BundleShellPlugin/Shell.ts b/packages/plugin-rax-harmony/src/BundleShellPlugin/Shell.ts new file mode 100644 index 000000000..824579d4a --- /dev/null +++ b/packages/plugin-rax-harmony/src/BundleShellPlugin/Shell.ts @@ -0,0 +1,31 @@ +import type { IBundleShellPluginOptions, IShellOptions } from '../types'; + +export default class BaseShell { + content: string; + pluginOptions: IBundleShellPluginOptions; + options: IShellOptions; + isPageFile: boolean; + constructor(content: string, pluginOptions: IBundleShellPluginOptions, options: IShellOptions) { + this.content = content; + this.pluginOptions = pluginOptions; + this.options = options; + + this.isPageFile = options.filename !== 'app.js'; + } + + generate(): string { + // In harmony app, app.js is different from page js file + if (this.isPageFile) return this.generatePage(); + return this.generateApp(); + } + + generatePage(): string { + // Default return + return this.content; + } + + generateApp(): string { + // Default return + return this.content; + } +} diff --git a/packages/plugin-rax-harmony/src/BundleShellPlugin/index.ts b/packages/plugin-rax-harmony/src/BundleShellPlugin/index.ts new file mode 100644 index 000000000..066fbcc28 --- /dev/null +++ b/packages/plugin-rax-harmony/src/BundleShellPlugin/index.ts @@ -0,0 +1,72 @@ +import { processAssets, emitAsset } from '@builder/compat-webpack4'; +import * as webpackSources from 'webpack-sources'; +import * as webpack from 'webpack'; +import { IBundleShellPluginOptions } from '../types'; +import { DEVICE_LEVEL } from '../constants'; +import LiteShell from './LiteShell'; +import RichShell from './RichShell'; +import getPageName from '../utils/getPageName'; + +const PLUGIN_NAME = 'BundleShell'; +const { RawSource } = webpack.sources || webpackSources; + + +export default class BundleShell { + pluginOptions: IBundleShellPluginOptions = { + appType: 'rich', + manifest: {}, + }; + options: any; + constructor(options: IBundleShellPluginOptions) { + this.pluginOptions = options; + } + apply(compiler) { + processAssets({ + pluginName: PLUGIN_NAME, + compiler, + }, ({ assets, callback, compilation }) => { + Object.keys(assets) + .forEach((filename) => { + let outputFileName = filename.replace(/\.js$/, ''); + if (!/^app\.js(\.map)?$/.test(filename)) { + outputFileName = `pages/${getPageName(filename)}`; + } + if (/\.js$/.test(filename)) { + transformJSFile(filename, { compilation, assets, pluginOptions: this.pluginOptions, outputFileName: `${outputFileName}.js` }); + } + + if (/\.js\.map$/.test(filename)) { + moveMapFile(filename, { compilation, assets, outputFileName: `${outputFileName}.js.map` }); + } + }); + + // Generate manifest.json + emitAsset(compilation, 'manifest.json', + new RawSource( + JSON.stringify(this.pluginOptions.manifest, null, compiler.options.mode === 'production' ? 0 : 2), + )); + callback(); + }); + } +} + +function transformJSFile(filename: string, { compilation, assets, pluginOptions, outputFileName }) { + const originalContent = assets[filename].source?.(); + delete assets[filename]; + + const shellOptions = { + filename, + }; + const shell = pluginOptions.appType === DEVICE_LEVEL.LITE + ? new LiteShell(originalContent, pluginOptions, shellOptions) + : new RichShell(originalContent, pluginOptions, shellOptions); + + emitAsset(compilation, outputFileName, new RawSource(shell.generate())); +} + +function moveMapFile(filename: string, { compilation, assets, outputFileName }) { + const originalContent = assets[filename]; + delete assets[filename]; + + emitAsset(compilation, outputFileName, originalContent); +} diff --git a/packages/plugin-rax-harmony/src/addWorkerEntry.ts b/packages/plugin-rax-harmony/src/addWorkerEntry.ts new file mode 100644 index 000000000..072406393 --- /dev/null +++ b/packages/plugin-rax-harmony/src/addWorkerEntry.ts @@ -0,0 +1,12 @@ +import * as path from 'path'; +import getFilePath from './utils/getFilePath'; + +export default function addWorkerEntry(config, { rootDir }) { + const workerEntry = getFilePath(path.join(rootDir, 'src/app-worker')); + + if (workerEntry) { + // worker file output name is app.js + const workerEntryConfig = config.entry('app'); + workerEntryConfig.add(workerEntry); + } +} diff --git a/packages/plugin-rax-harmony/src/constants.ts b/packages/plugin-rax-harmony/src/constants.ts new file mode 100644 index 000000000..0bb610a9c --- /dev/null +++ b/packages/plugin-rax-harmony/src/constants.ts @@ -0,0 +1,6 @@ +export const GET_RAX_APP_WEBPACK_CONFIG = 'getRaxAppWebpackConfig'; +export const DEVICE_LEVEL = { + RICH: 'rich', + LITE: 'lite', + CARD: 'card', +}; diff --git a/packages/plugin-rax-harmony/src/index.ts b/packages/plugin-rax-harmony/src/index.ts new file mode 100644 index 000000000..24c76d807 --- /dev/null +++ b/packages/plugin-rax-harmony/src/index.ts @@ -0,0 +1,88 @@ +import * as setMPAConfig from '@builder/mpa-config'; +import { getMpaEntries } from '@builder/app-helpers'; +import { GET_RAX_APP_WEBPACK_CONFIG } from './constants'; +import BundleShellPlugin from './BundleShellPlugin'; +import addWorkerEntry from './addWorkerEntry'; +import type { IBundleShellPluginOptions } from './types'; +import { isWebpack4 } from '@builder/compat-webpack4'; +import getManifest from './utils/getManifest'; +import setupAppEntry from './setupAppEntry'; + +/* +TODO: +- 鸿蒙应用 vendors 为 false,不可配置 + */ + +export default (api) => { + const { getValue, context, registerTask, onGetWebpackConfig } = api; + const { userConfig, command, rootDir } = context; + + const getWebpackBase = getValue(GET_RAX_APP_WEBPACK_CONFIG); + const tempDir = getValue('TEMP_PATH'); + const target = 'harmony'; + const chainConfig = getWebpackBase(api, { + target: 'harmony', + babelConfigOptions: { styleSheet: true }, + progressOptions: { + name: 'Harmony', + }, + }); + + let entries = [setupAppEntry(chainConfig, context)]; + + chainConfig.name(target); + + registerTask(target, chainConfig); + + onGetWebpackConfig(target, (config) => { + const { harmony = {} } = userConfig; + const { mpa, appType = 'rich' } = harmony; + const staticConfig = getValue('staticConfig'); + + // base config + if (isWebpack4) { + config.output.libraryTarget('var'); + config.output.libraryExport('result'); + } else { + config.output.merge({ + library: { + name: 'result', + type: 'var', + }, + }); + } + + // set mpa config + if (mpa) { + entries = getMpaEntries(api, { + target, + appJsonContent: staticConfig, + }); + + setMPAConfig.default(api, config, { + targetDir: tempDir, + type: target, + entries, + }); + } + + addWorkerEntry(config, { rootDir }); + + config.output.devtoolModuleFilenameTemplate('webpack:///[absolute-resource-path]'); + config.devtool('nosources-source-map'); + + const bundleShellPluginOptions: IBundleShellPluginOptions = { + appType, + manifest: getManifest(entries, { staticConfig, nativeConfig: harmony.nativeConfig }), + }; + + config.plugin('BundleShellPlugin').use(BundleShellPlugin, [bundleShellPluginOptions]); + + if (command === 'start') { + // Add webpack hot dev client + Object.keys(config.entryPoints.entries()).forEach((entryName) => { + config.entry(entryName).prepend(require.resolve('react-dev-utils/webpackHotDevClient')); + }); + } + }); +}; diff --git a/packages/plugin-rax-harmony/src/setupAppEntry.ts b/packages/plugin-rax-harmony/src/setupAppEntry.ts new file mode 100644 index 000000000..6c2d6353e --- /dev/null +++ b/packages/plugin-rax-harmony/src/setupAppEntry.ts @@ -0,0 +1,21 @@ +import * as path from 'path'; +import getFilePath from './utils/getFilePath'; + +export default (config, context) => { + const { + rootDir, + } = context; + + // SPA + const appEntry = getFilePath(path.join(rootDir, './src/app')); + + if (appEntry) { + const entryConfig = config.entry('index'); + entryConfig.add(appEntry); + } + + return { + entryName: 'index', + entryPath: appEntry, + }; +}; diff --git a/packages/plugin-rax-harmony/src/types/index.ts b/packages/plugin-rax-harmony/src/types/index.ts new file mode 100644 index 000000000..eaad80bc2 --- /dev/null +++ b/packages/plugin-rax-harmony/src/types/index.ts @@ -0,0 +1,14 @@ +export interface IBundleShellPluginOptions { + appType: string; + manifest: IManifest; +} + +export interface IManifest { + appID?: string; + pages?: string[]; + [key: string]: unknown; +} + +export interface IShellOptions { + filename: string; +} diff --git a/packages/plugin-rax-harmony/src/utils/getFilePath.ts b/packages/plugin-rax-harmony/src/utils/getFilePath.ts new file mode 100644 index 000000000..d69b4a655 --- /dev/null +++ b/packages/plugin-rax-harmony/src/utils/getFilePath.ts @@ -0,0 +1,9 @@ +import * as fs from 'fs-extra'; + +export default function getFilePath(filePath) { + const ext = ['.ts', '.js', '.tsx', '.jsx'].find((extension) => fs.existsSync(`${filePath}${extension}`)); + if (!ext) { + return; + } + return require.resolve(`${filePath}${ext}`); +} diff --git a/packages/plugin-rax-harmony/src/utils/getManifest.ts b/packages/plugin-rax-harmony/src/utils/getManifest.ts new file mode 100644 index 000000000..91f3b9a98 --- /dev/null +++ b/packages/plugin-rax-harmony/src/utils/getManifest.ts @@ -0,0 +1,22 @@ +import { merge } from '@builder/pack/deps/lodash'; +import type { IManifest } from '../types'; + +const DEFAULT_MANIFEST = { + appID: 'com.example.ace.helloworld', + appName: 'HelloAce', + versionName: '1.0.0', + versionCode: 1, + minPlatformVersion: '1.0.1', + window: { + designWidth: 750, autoDesignWidth: false, + }, +}; + +export default function getManifest(entries, { staticConfig, nativeConfig }): IManifest { + const manifest: IManifest = { + pages: entries.map(({ entryName }) => `pages/${entryName}`), + window: staticConfig.window, + }; + + return merge(DEFAULT_MANIFEST, manifest, nativeConfig); +} diff --git a/packages/plugin-rax-harmony/src/utils/getPageName.ts b/packages/plugin-rax-harmony/src/utils/getPageName.ts new file mode 100644 index 000000000..6cfa34ec3 --- /dev/null +++ b/packages/plugin-rax-harmony/src/utils/getPageName.ts @@ -0,0 +1,3 @@ +export default function getPageName(filename: string) { + return filename.split('.')[0]; +} diff --git a/packages/plugin-rax-harmony/tsconfig.json b/packages/plugin-rax-harmony/tsconfig.json new file mode 100644 index 000000000..1ba6ca74d --- /dev/null +++ b/packages/plugin-rax-harmony/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.settings.json", + "compilerOptions": { + "baseUrl": "./", + "rootDir": "src", + "outDir": "lib" + }, +} diff --git a/packages/plugin-rax-kraken/src/index.js b/packages/plugin-rax-kraken/src/index.js index 06e785e0d..1cb67b098 100644 --- a/packages/plugin-rax-kraken/src/index.js +++ b/packages/plugin-rax-kraken/src/index.js @@ -17,7 +17,6 @@ module.exports = (api) => { }, }); chainConfig.name(target); - chainConfig.taskName = target; setEntry(chainConfig, context); diff --git a/packages/plugin-rax-miniapp/src/index.js b/packages/plugin-rax-miniapp/src/index.js index af5e5e1cc..d23f8e7b1 100644 --- a/packages/plugin-rax-miniapp/src/index.js +++ b/packages/plugin-rax-miniapp/src/index.js @@ -44,7 +44,6 @@ module.exports = (api) => { }, }); chainConfig.name(target); - chainConfig.taskName = target; // Register task registerTask(target, chainConfig); diff --git a/packages/plugin-rax-web/src/index.ts b/packages/plugin-rax-web/src/index.ts index 0f3de4220..8bc1c4f01 100644 --- a/packages/plugin-rax-web/src/index.ts +++ b/packages/plugin-rax-web/src/index.ts @@ -30,7 +30,6 @@ export default (api) => { }, }); chainConfig.name(target); - chainConfig.taskName = target; // Set Entry setEntry(chainConfig, context); diff --git a/packages/plugin-rax-weex/src/index.js b/packages/plugin-rax-weex/src/index.js index 4bfd0115d..7eb6f0fc2 100644 --- a/packages/plugin-rax-weex/src/index.js +++ b/packages/plugin-rax-weex/src/index.js @@ -33,7 +33,6 @@ module.exports = (api) => { // set mpa config if (weex.mpa) { setMPAConfig.default(api, config, { - context, targetDir: tempDir, type: 'weex', entries: getMpaEntries(api, { diff --git a/packages/rax-app-renderer/src/renderer.tsx b/packages/rax-app-renderer/src/renderer.tsx index 7b62909b8..f59709896 100644 --- a/packages/rax-app-renderer/src/renderer.tsx +++ b/packages/rax-app-renderer/src/renderer.tsx @@ -7,9 +7,12 @@ import { setInitialData } from './initialData'; import parseSearch from './parseSearch'; import type { RuntimeModule } from 'create-app-shared'; +//@ts-ignore +const isHarmony = typeof ace !== 'undefined'; + let driver = UniversalDriver; -async function raxAppRenderer(options, renderOptions) { +async function raxAppRenderer(options) { if (!options.appConfig) { options.appConfig = {}; } @@ -19,17 +22,19 @@ async function raxAppRenderer(options, renderOptions) { const context: IContext = {}; // ssr enabled and the server has returned data - if ((window as any)?.__INITIAL_DATA__) { - context.initialData = (window as any).__INITIAL_DATA__.initialData; - context.pageInitialProps = (window as any).__INITIAL_DATA__.pageInitialProps; - } else if (isWeb && appConfig?.app?.getInitialData) { - const { pathname, search } = window.location; - const query = parseSearch(search); - const initialContext = { - pathname, - query, - }; - context.initialData = await appConfig.app.getInitialData(initialContext); + if (isWeb) { + if ((window as any).__INITIAL_DATA__) { + context.initialData = (window as any).__INITIAL_DATA__.initialData; + context.pageInitialProps = (window as any).__INITIAL_DATA__.pageInitialProps; + } else if (appConfig?.app?.getInitialData) { + const { pathname, search } = window.location; + const query = parseSearch(search); + const initialContext = { + pathname, + query, + }; + context.initialData = await appConfig.app.getInitialData(initialContext); + } } setInitialData(context.initialData); @@ -72,7 +77,7 @@ function _render(runtime: RuntimeModule, context: IContext, options: RenderOptio } function _getAppMountNode(mountNode: HTMLElement, rootId: string) { - if (isWeex || isKraken) return null; + if (isWeex || isKraken || isHarmony) return null; return mountNode || document.getElementById(rootId) || document.getElementById('root'); } diff --git a/packages/rax-app/src/index.ts b/packages/rax-app/src/index.ts index 9597f76a1..8d9d4481d 100644 --- a/packages/rax-app/src/index.ts +++ b/packages/rax-app/src/index.ts @@ -48,6 +48,10 @@ const getBuiltInPlugins: IGetBuiltInPlugins = (userConfig: IRaxAppUserConfig) => builtInPlugins.push('build-plugin-rax-weex'); } + if (targets.includes('harmony')) { + builtInPlugins.push('build-plugin-rax-harmony'); + } + if (targets.includes('kraken')) { builtInPlugins.push('build-plugin-rax-kraken'); } diff --git a/packages/rax-webpack-config/src/setWebpackLoaders.ts b/packages/rax-webpack-config/src/setWebpackLoaders.ts index d1026263b..b2ec89d6f 100644 --- a/packages/rax-webpack-config/src/setWebpackLoaders.ts +++ b/packages/rax-webpack-config/src/setWebpackLoaders.ts @@ -131,10 +131,6 @@ export default (config, { rootDir, babelConfig }: IOptions) => { if (request.indexOf('@weex-module') !== -1) { return callback(null, `commonjs ${request}`); } - // compatible with @system for quickapp - if (request.indexOf('@system') !== -1) { - return callback(null, `commonjs ${request}`); - } // compatible with plugin with miniapp plugin if (/^plugin\:\/\//.test(request)) { return callback(null, `commonjs ${request}`); diff --git a/tsconfig.json b/tsconfig.json index 4c00f1035..8c751df10 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,6 +10,7 @@ { "path": "packages/rax-app-renderer" }, { "path": "packages/exports-field-webpack-plugin" }, { "path": "packages/plugin-rax-router" }, + { "path": "packages/plugin-rax-harmony" }, { "path": "packages/plugin-rax-app" }, { "path": "packages/plugin-rax-web" }, { "path": "packages/plugin-rax-miniapp" },