EY-Office ブログ

複数Reactプロジェクトでコードを共有する(local npm package)

仕事でサンプルコードを書いていて、2つのReactアプリのプロジェクトでコードを共有したくなりました。

あれ、どうするのが良いのかな? と思いながらいろいろと試してみました。

npm DALL·Eで生成したlocal npm packageの画像

今回のコード

a-projectb-projectというReactアプリのプロジェクトが以下のようなディレクトリー構成で作られています(node_modules/ディレクトリーは省略しています)。

.
├── a-project
│   ├── package-lock.json
│   ├── package.json
│   ├── public
│   │   └── index.html
│   ├── src
│   │   ├── App.tsx
│   │   ├── message.ts
│   │   └── index.tsx
│   └── tsconfig.json
└── b-project
    ├── package-lock.json
    ├── package.json
    ├── public
    │   └── index.html
    ├── src
    │   ├── App.tsx
    │   └── index.tsx
    └── tsconfig.json

ソースコードは以下のようになっています。

  • a-project/src/App.tsx
import message from './message';

const App = () => {
  return (
    <h2>{message()}</h2>
  )
 }

export default App;
  • a-project/src/message.ts
const message = () => {
  return "Hello React!"
}

export default message;

import from ’../../a-project/src/message’ はエラー

さてb-projectApp.tsxでもa-project/src/message.tsを使いたいので、以下のように書いてみました。

  • a-project/src/App.tsx
import message from '../../a-project/src/message';

const App = () => {
  return (
    <h2>{message()}</h2>
  )
 }

export default App;

VS Code上でのエラーは検出されませんでしたが、npm startで実行すると黒い画面に以下のようなエラーが表示されました。😅

Compiled with problems:X

ERROR in ./src/App.tsx 4:0-50

Module not found: Error: You attempted to import ../../a-project/src/message which falls outside of the project src/ directory. Relative imports outside of src/ are not supported. You can either move it inside src/, or add a symlink to it from project’s node_modules/.

確かにsrc/ディレクトリー以外のファイルが参照されているのは怪しいですよね・・・・

シンボリック・リンクはWindowsでは危うい

それなら、シンボリック・リンクを使ってらどうでしょうか?

$ cd b-project
$ ls -l src/*
-rw-r--r--  1 yy  staff  118  2  6 11:11 src/App.tsx
-rw-r--r--  1 yy  staff  251  2  6 11:00 src/index.tsx
lrwxr-xr-x  1 yy  staff   30  2  6 11:12 src/message.ts -> ../../a-project/src/message.ts
-rw-r--r--  1 yy  staff   40  2  6 10:45 src/react-app-env.d.ts

これは動作しました! gitにもコミット出来ました。

しかし、調べてみるとWindowsではGit for Windowsでシンボリックリンクを扱えるようにするのような設定を行わないと、正しくシンボリックリンクが扱われないようです。

local npm package

少し調べたところ、npmパッケージ(npmライブラリー)をローカルに作り、それをnpm install <npmパッケージのディレクトリー>でプロジェクトにインストールする事ができるそうです。

1. 準備

さっそく、messageパッケージを作っていきましょう、もちろんTypeScriptで書きます。

$ mkdir message              ← messageパッケージ用ディレクトリーの作成
$ cd message
$ npm init -ynpm パッケージの作成
$ npm install typescript     ← TypeScriptをインストール
$ npx tsc --init             ← TypeScriptの設定ファイルを作成

2. ソースコード

このパッケージの主体であるmessage.ts ファイルを index.ts として移動

$ mv ../a-project/src/message.ts index.ts

3. packege.jsonを変更

以下の部分を変更しました。

-  "main": "index.js",
+  "main": "build/index.js",      // ← 作成されるJSファイルを指定 (変更)
+  "types": "build/index.d.ts",   // ← TypeScriptの定義ファイルを指定(追加)
   "scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1"
+    "build": "tsc"               // ← ビルドコマンドの定義
   },

4. tsconfig.jsonを変更

以下の部分を変更しました。

-    // "declaration": true,
+    "declaration": true,       // ← TypeScript用定義ファイルの作成

-    // "outDir": "./",
+    "outDir": "./build",       // ← コンパイルされたJavaScriptファイルの入るディレクトリー

5. ビルド

$ npm run build

> message@1.0.0 build
> tsc

$
  • 参照: ここでのディレクトリー構成(node_modules/ディレクトリーは省略しています)
.
├── a-project
│   ├── package-lock.json
│   ├── package.json
│   ├── public
│   │   └── index.html
│   ├── src
│   │   ├── App.tsx
│   │   └── index.tsx
│   └── tsconfig.json
├── b-project
│   ├── package-lock.json
│   ├── package.json
│   ├── public
│   │   └── index.html
│   ├── src
│   │   ├── App.tsx
│   │   └── index.tsx
│   └── tsconfig.json
└── message
    ├── build
    │   ├── index.d.ts
    │   └── index.js
    ├── index.ts
    ├── package-lock.json
    ├── package.json
    └── tsconfig.json

6. Reactプロジェクトの変更

Reactプロジェクトにmessageパッケージをインストールし、コードを少し変更しました。

$ cd ../b-project
$ npm install ../message/           ← messageパッケージのインストール
  • b-project/src/App.tsx
import message from 'message';      // ← node_modulesからの参照

const App = () => {
  return (
    <h2>{message()}</h2>
  )
 }

export default App;
  • 参考: package.jsonは以下のようになっていました
{
  "name": "b-project",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "@types/jest": "^27.5.2",
    "@types/node": "^16.18.12",
    "@types/react": "^18.0.27",
    "@types/react-dom": "^18.0.10",
    "message": "file:../message",            // ← ローカル・パッケージ
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "typescript": "^4.9.5",
    "web-vitals": "^2.1.4"
  },

  // ・・・ 省略 ・・・
}

まとめ

このように、簡単にlocal npm packageを使い別プロジェクト間でのコード共有が出来るようになります。

また、npm installコマンドはnpm install <git:// url>npm install <github username>/<github project> のように社内のGitリポジトリーやプライベートなGitHubからもインストールできるので、社内特有のReact(JavaScript)コード等を共有するのに役立つと思います。

1点注意してほしいのは、npm uninstall

$ npm uninstall ../message

上のようにパス名ではでなく、パッケージ名を指定しないと行けないことです。

$ npm uninstall message

パス名を指定してもエラーは表示されないので、ハマりました。😅

- about -

EY-Office代表取締役
・プログラマー
吉田裕美の
開発者向けブログ