複数のReactのプロジェクトとバージョンを扱う技術
サンプルのプロジェクトもあるので比較しながら説明できればと思います
ソース
動作確認ページ
どうしてこんなことしようとしたかというとReactのバージョンアップや次期バージョンの検証も同時にやらなきゃと思い始めたのと
いいかげんwebpackでもないものでも対応できるようなの考えておかないとと思ってみて手を進めてみたらいろいろ検討しがいあるものかけそうと思ったライブ感ですね
おおまかな構成
ページの読み込みの起点としては下記のようなライブラリ、ビルドファイル、DOM構成としています
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="react16-root"></div>
<div id="react18-root"></div>
<script src="./npm/react/16.14.0/umd.js"></script>
<script src="./npm/react/18.2.0/umd.js"></script>
<script src="./npm/react-dom/16.14.0/umd.js"></script>
<script src="./npm/react-dom/18.2.0/umd.js"></script>
<script src="./react16/umd.js"></script>
<script src="./react18/umd.js"></script>
</body>
</html>
図にするとこんな構成です
ここで packages/npm_manager
、packages/react[16, 18]
という独自プロジェクト概念が出てきたのでそれぞれ説明していきたいと思います
packages/npm_manager
複数のライブラリのバージョンやumdのファイル抽出した際にglobalの変数重複をさけるために作成したプロジェクトです
独自のCDNにnpmでバージョン管理しながら抽出させたいときとかも使えそうですよね
ライブラリの複数バージョンを取り扱う
https://github.com/igara/multiple_react_version_sample/blob/main/packages/npm_manager/package.json みたいに
"dependencies": {
"react_16_14_0": "npm:react@16.14.0",
"react_18_2_0": "npm:react@18.2.0",
"react-dom_16_14_0": "npm:react-dom@16.14.0",
"react-dom_18_2_0": "npm:react-dom@18.2.0",
"types_react_16_14_43": "npm:@types/react@16.14.43",
"types_react_18_0_37": "npm:@types/react@18.0.37",
"types_react-dom_16_9_19": "npm:@types/react-dom@16.9.19",
"types_react-dom_18_0_11": "npm:@types/react-dom@18.0.11"
},
同じライブラリでもimportする際のライブラリ名の変更と読み込みが分けて行うことが可能になります
ライブラリ名変更した際に型の読み込みがうまくいかないときとかは
https://github.com/igara/multiple_react_version_sample/blob/main/packages/react16/src/vite-env.d.ts みたいに
使用したいライブラリの型定義を後から付与することも可能です
umd展開するライブラリ変数名の変更
umdのJSをunpkgのを使用すればいいんじゃと思うかもしれませんが展開される変数がどのバージョンのReactでも window.React
として展開されるので異なるReactバージョンと同時に使用することができないため、独自のビルドで window.React
から window.React_X_X_X
とバージョン名を含めた変数名にしました
import React from "react_16_14_0/umd/react.production.min.js";
window.React_16_14_0 = React;
ビルドファイルの設定はこんな感じです
import { defineConfig } from 'vite';
import { terser } from 'rollup-plugin-terser'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [],
build: {
outDir: "dist/npm/react/16.14.0",
lib: {
entry: 'src/npm/react/16.14.0/index.ts',
name: 'React_16_14_0',
fileName: (format) => `${format}.js`,
formats: ['umd'],
},
rollupOptions: {
external: [],
plugins: [terser()],
output: {
globals: {
'react': 'React_16_14_0',
}
},
},
write: true,
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
},
});
rollupOptions.external
と rollupOptions.output.globals
はライブラリによって依存しているものを意識して設定するのがよさそうですね
packages/react[16, 18]
vite createによって生成されたReactのプロジェクトです
大きな変更点として
https://github.com/igara/multiple_react_version_sample/blob/main/packages/react16/vite.config.ts の
rollupOptions.external
と rollupOptions.output.globals
ぐらいで
rollupOptions: {
external: ['react', 'react-dom'],
plugins: [terser()],
output: {
globals: {
'react': 'React_16_14_0',
'react-dom': 'ReactDOM_16_14_0',
}
},
},
にしてあるぐらいです
この設定にすることによってこのビルドファイル自身にはReactのライブラリを含めず、ライブラリの参照は packages/npm_manager
になり、さらに複数のReactプロジェクトを読みこんだときにプロジェクトの数分Reactなどのライブラリのファイルサイズ削減にもなると思います
Discussion