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" },