Tencent / hel

A module federation SDK which is unrelated to tool chain for module consumer. 工具链无关的运行时模块联邦sdk.
https://tencent.github.io/hel/
Other
967 stars 85 forks source link

已有的react vite项目怎么改造呢 #60

Open qiang-chen opened 1 year ago

fantasticsoul commented 1 year ago

已有vue项目参考这个示例: https://github.com/hel-eco/vue-admin-template-with-hel

fantasticsoul commented 1 year ago

react 参考这个

已有react项目接入hel

安装工具包

安装 hel-dev-utils

npm i hel-dev-utils

生成子应用描述对象

以执行弹射后的create-react-app项目模板为例,建议在config目录下创建一个subApp.js文件,copy如下内容

const helDevUtils = require('hel-dev-utils');
const pkg = require('../package.json');

const subApp = helDevUtils.createReactSubApp(pkg);

// 若是私服部署,可设定 homePage
// const subApp = helDevUtils.createReactSubApp(pkg, {homePage:'https://xxx.com/yy'});

module.exports = subApp;

替换publicUrlOrPath和buildPath

config目录下找到paths文件,替换掉里面的publicUrlOrPathbuildPath定义值

const subApp = require('./subApp');

const publicUrlOrPath = subApp.getPublicPathOrUrl();
const buildPath = subApp.distDir;

替换jsonpFunction

替换config/webpack.config.js文件里output.jsonpFunction(或output.chunkLoadingGlobal)对象下的内容(有则替换,无则新增)

{
  // 其他属性略...
  chunkLoadingGlobal: subApp.jsonpFnName, 
}

设置react为externals

推荐设置react为externals,避免react参与打包,同时也方便后续hel-micro-reactSDK使用其他的远程react模块

替换config/webpack.config.js文件里module.exports返回对象的externals值(有则合并,无则新增)

module.exports = function (webpackEnv) { return { // 其他属性略... externals: {...yourExternals, ...subApp.externals}, }; }


- 无externals
```js
const subApp = require('./subApp');

module.exports = function (webpackEnv) {
  return {
    // 其他属性略...
    externals: subApp.externals,
  };
}

public/index.html里引入cdn react运行时

暴露共享模块

当前项目有共享给其他项目使用的模块时,可接入此步骤

安装工具包

执行以下npm命令,安装相关包体

npm i hel-lib-proxy
npm i typescript@4.8 rollup@2 rollup-plugin-typescript rollup-plugin-terser shx replace-absolute-path -D

下沉入口文件

将原来的 src/index.js 内容复制到 src/loadApp.js 里,类似此文件,原入口文件index.js内容改动稍后步骤会提到

新增模块组名描述文件

package.json里的appGroupName写上模块组名

新增 src/configs/subApp.ts(如是js工程,此处创建为subApp.js),内容如下,确保LIB_NAMEpackage.json里的appGroupName保持一致

/*
|--------------------------------------------------------------------------
|
| 对应 package.json appGroupName
|
|--------------------------------------------------------------------------
*/
export const LIB_NAME = 'remote-react-comps-tpl';

新增模块暴露目录

新增 src/entrance 目录作为统一暴露模块的出口目录(可参考此文件

目录下新建两个文件libProperties.ts(如是js工程,此处创建为libProperties.js)和libTypes.ts(注意此文件一定是ts文件)

libProperties.ts用于暴露共享模块

// 导出模块可按项目实际情况调整,这里仅做示例
import * as comps from 'components';

export default comps;

libTypes.ts用于导出共享模块类型,并作为rollup打包入口,方便有静态导入和类型提示需求的用户使用npm包来完成此目的,内容如下

import libProperties from './libProperties';
import { exposeLib } from 'hel-lib-proxy';
import { LIB_NAME } from 'configs/subApp';

export type Lib = typeof libProperties;

export const lib = exposeLib<Lib>(LIB_NAME);

/** 如想使用方可在import语句里直接解构出具体的模块,可写为
可参考:https://github.com/hel-eco/hel-tdesign-react/blob/main/src/entrance/libTypes.ts

export cont XX = lib.XX;
export cont YY = lib.YY;

*/

export default lib;

改造入口文件

改造入口文件,做分流控制(可参考此文件

// import { preFetchLib } from 'hel-micro';
import { libReady, isSubApp } from 'hel-lib-proxy';
import { LIB_NAME } from './configs/subApp';

async function main() {
  // 如有其他包依赖,且需要在逻辑里静态导入,可在此处执行预抓取
  // await helMicro.preFetchLib('other-lib');
  const libProperties = await import('./entrance/libProperties');
  // 表示模块已准备就绪,注意此处传递的是 default
  libReady(LIB_NAME, libProperties.default);

  // 非子应用时(即不是被别的模块触发载入的情况),自己挂载渲染节点,方便本地调试
  if (!isSubApp()) {
    await import('./loadApp');
  }
}
main().catch(console.error);
// avoid isolatedModules warning
export default 'Hel Module Index file';

接入npm构建相关辅助脚本

项目根目录下新建scripts目录,新增以下脚本meta.jscheck.jsreplaceToRelativePath.js(可参考此处

meta.js用于辅助私有部署时提取hel-meta.json数据,内容如下:

/*
* 生成 hel-meta.json
*/
const path = require('path');
const process = require('process');
const helDevUtils = require('hel-dev-utils');
const packageJson = require('../package.json');
const subApp = require('../config/subApp');

helDevUtils.extractHelMetaJson({
  appHomePage: subApp.getPublicPathOrUrl(),
  buildDirFullPath: path.join(__dirname, '../hel_dist'),
  packageJson,
  platform: subApp.platform,
}).catch((err) => {
  console.error(err);
  process.exit(-1);
});

check.js用于校验组名是否一致,内容如下:

const path = require('path');
const helDevUtils = require('hel-dev-utils');
const pkg = require('../package.json');
const fileFullPath = path.join(__dirname, '../src/configs/subApp');
helDevUtils.check(pkg, { fileFullPath, checkEnv: process.env.CHECK_ENV !== '0' });

replaceToRelativePath.js用于将整个项目的绝对路径替换为相对路径,辅助rollup打包,内容如下

const path = require('path');
const replacePath = require('replace-absolute-path');

(async function () {
  const srcDir = process.env.BUNDLE === 'true' ? path.resolve(__dirname, '../lib-js') : path.resolve(__dirname, '../src');
  const libDir = process.env.BUNDLE === 'true' ? path.resolve(__dirname, '../lib-js') : path.resolve(__dirname, '../lib');
  replacePath({
    inputDir: srcDir,
    outputDir: libDir,
    // includeExts: DEFAULT_EXTS.concat(['.md']),
    afterReplaced: () => {
      console.log('----------------------------------------------------------------------------------');
      console.log(`| all files import statements been transformed to relative path for ${libDir} ^_^ |`);
      console.log('----------------------------------------------------------------------------------');
    },
  });
})().catch((err) => {
  console.error(err);
  process.exit(-1);
});

引入rollup配置文件

根目录下新增rollup.config.js文件,内容如下:

:::tip 此步骤为可选项 不需要发包到npm时(即使用方不需要静态导入和类型提示功能时),可以跳过此步骤 :::

import typescript from 'rollup-plugin-typescript';
import { terser } from 'rollup-plugin-terser';
import { cst } from 'hel-dev-utils';
import pkg from './package.json';
const env = process.env.BUILD_ENV || 'umd';
const plugins = [
  typescript({
    exclude: 'node_modules/**',
    typescript: require('typescript'),
  }),
];
const env2outputConf = {
  es: {
    format: 'es',
    name: pkg.appGroupName,
    file: `${cst.HEL_PROXY_DIR}_es/entry.js`,
  },
  umd: {
    format: 'umd',
    name: pkg.appGroupName,
    file: `${cst.HEL_PROXY_DIR}/entry.js`,
  },
};
const outputObj = env2outputConf[env];
if (process.env.MIN === 'true') {
  plugins.push(terser());
  const [dirName] = outputObj.file.split('/');
  outputObj.file = `${dirName}/entry.min.js`;
}
module.exports = {
  input: 'src/entrance/libTypes.ts',
  plugins,
  output: [
    outputObj,
  ],
};

新增相关构建命令

package.jsonscripts节点下引入相关构建命令

"scripts": {
    "check": "node ./scripts/check.js",
    "build": "npm run build_dist",
    "build_dist": "node scripts/build.js",
    "build_proxy": "npm run build_proxy_umd && npm run build_proxy_es",
    "build_proxy_umd": "tsc & node ./scripts/replaceToRelativePath.js & rollup -c",
    "build_proxy_es": "tsc & node ./scripts/replaceToRelativePath.js & cross-env BUILD_ENV=es rollup -c",
    "build_meta": "node scripts/meta.js",
    "set_home_page": "cross-env-shell HEL_APP_HOME_PAGE=http://127.0.0.1:8080",
    "build_cust": "npm run set_home_page \"npm run build_dist && npm run build_meta\"",
    "check_name": "node ./scripts/check.js",
    "build_priv": "cross-env-shell CHECK_ENV=0 \"npm run check_name && npm run build_dist && npm run build_meta && npm run build_proxy\"",
    "build_priv:hint": "work for custom deploy",
    "build_helpack": "cross-env-shell CHECK_ENV=0 HEL_APP_HOME_PAGE=http://tnfe.cdn/hel/xxx-name_202202021212 \"npm run check_name && npm run build_dist && npm run build_meta && npm run build_proxy\"",
    "build_helpack:hint": "just mock helpack build process to see hel-meta.json result"
  }

:::tip build_dist命令 build_dist命令你原来的webpack构建命令即可,相关命令命名可以自行调整 :::

构建与发布npm

执行以下命令

npm run build 
npm publish

:::tip npm只发布了源码 npm只发布了源码,运行时代码需要自己发布到相关cdn,如已接入helpack则helpack会自动做相关事宜 :::

HUGY1 commented 1 year ago

这个是要求webpack5的吧? webpack4就搞死人了

fantasticsoul commented 1 year ago

这个是要求webpack5的吧? webpack4就搞死人了

不需要webpack 5

betawen commented 6 months ago

有封装的cli命令吗