1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

NetSuite上にReactアプリをデプロイしてみた

Last updated at Posted at 2024-12-13

はじめに

NetSuiteではSuiteScriptを使ってカスタマイズが可能ですが、外部ライブラリを使用した開発もやりようによっては可能です。
今回はVite+Reactで作ったアプリをNetSuiteで動作させてみたので、その手順をご紹介します。

手順概要と結論

  1. Reactアプリを作る
  2. webpackで1ファイルにまとめる
  3. [2]を読み込むSuiteletを作る
  4. [2]と[3]をNetSuiteにデプロイする
  5. Suiteletにアクセスする
  6. Reactアプリが動作する!

ちなみにですが、Next.jsのようなフレームワークを使用した開発は多分無理です。よりモダンな開発を行いたい場合は、Next.js等のフレームワークで作成したアプリは外部にデプロイし、NetSuiteのAPIを使用してデータをフェッチするのがいいと思います。

実装手順

0. 前提/環境

  1. 開発環境
    • VS Code/Cursor
    • SuiteCloud Extension for Visual Studio Code
    • Node.js 18.20.4
    • npm 10.7.0
  2. NetSuite環境と機能の有効化
    • 2024.2
    • クライアントSuiteScript
    • サーバーSuiteScript
    • SuiteCloud開発フレームワーク

1. SDFプロジェクトの作成

まずはSDFプロジェクトを作成してください。もしも既存のプロジェクトがある場合は、そのプロジェクトを使用しても大丈夫です。
また、SDFプロジェクト内のディレクトリ構造は任意で定義していただいて大丈夫ですが、この記事では以下のようなディレクトリ構造を想定しています。雰囲気で感じ取ってください。

.
└── New SuiteScript Project/
    └── src/
        └── FileCabinet/
            └── SuiteScripts/
                ├── 0001/
                │   ├── react_app_sl.js
                │   └── netsuite_react_app/
                │       ├── src/
                │       │   ├── App.jsx
                │       │   ├── App.css
                │       │   ├── main.jsx
                │       │   ├── index.css
                │       │   └── ...
                │       ├── ...
                │       ├── webpack.config.js
                │       └── dist/
                │           └── bundle.js
                ├── 0002/
                │   └── ...
                └── ...

ポイントは、プロジェクト内のSuiteScriptsディレクトリに、各カスタマイゼーション用のディレクトリを配置し、その中に今回のReactアプリを配置することです。

2. Reactプロジェクトの作成

まずは新規Reactプロジェクトを作成します。今回はviteを使います。

npm create vite@latest
# プロジェクト名を入力: netsuite-react-app
# フレームワークとしてReactを選択
# バリアントとしてJavaScriptを選択

cd netsuite-react-app
npm install

また、svgファイル等は不要なので、publicディレクトリとApp.jsx内のsvgファイルのインポートは削除しておきます(というか、svgファイルをNetSuite上で正常に参照できませんでした)。

SuiteScripts\0001\netsuite-react-app\src\App.jsx
import { useState } from 'react'
import './App.css'

function App() {
  const [count, setCount] = useState(0)
  return (
    <>
      <h1>Vite + React on NetSuite</h1>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
      </div>
    </>
  )
}
export default App

一旦ここでnpm run devを実行して、Reactアプリが動作することを確認いただいても大丈夫です。

3. 必要な依存関係のインストール

webpackでバンドルするために必要なパッケージをインストールします:

npm install --save-dev webpack webpack-cli babel-loader @babel/core @babel/preset-env @babel/preset-react style-loader css-loader

4. webpack設定ファイルの作成

プロジェクトのルートディレクトリ(今回の場合はSuiteScripts\0001\netsuite-react-app\)にwebpack.config.jsを作成します:

SuiteScripts\0001\netsuite-react-app\webpack.config.js
import path from 'path';
import webpack from 'webpack';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

export default {
    entry: './src/main.jsx',
    plugins: [
        new webpack.ProvidePlugin({
            React: 'react',
            ReactDOM: 'react-dom',
        }),
    ],
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist'),
        libraryTarget: 'var',
        library: 'MyApp',
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env', '@babel/preset-react'],
                    },
                },
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            },
            {
                test: /\.(png|svg|jpg|jpeg|gif)$/i,
                type: 'asset/resource',
            }
        ],
    },
    resolve: {
        extensions: ['.js', '.jsx'],
    },
    externals: {
        'react': 'React',
        'react-dom': 'ReactDOM'
    },
    mode: 'production'
};

5. package.jsonの更新

package.jsonのビルドスクリプトを編集します:

SuiteScripts\0001\netsuite-react-app\package.json
{
    "scripts": {
        "build": "webpack --config webpack.config.js"
    }
}

5. Suiteletスクリプトの作成

NetSuiteでReactアプリを表示するためのSuiteletスクリプトを作成します:

SuiteScripts\0001\react_app_sl.js
/**
    * @NApiVersion 2.1
    * @NScriptType Suitelet
    * @NModuleScope SameAccount
    *
    */
define(["N/ui/serverWidget", 'N/file', 'N/url'],
    /**
     * 
     * @param {serverWidget} serverWidget 
     * @param {file} file 
     * @param {url} url 
     */
    (serverWidget,file,url) => {
        const onRequest = async ({ request, response }) => {
        const action = request.parameters.action;
        switch (request.method) {
            case "GET":
                switch (action) {
                    default:
                    const suiteletUI = await createUI(request, response);
                    response.writePage(suiteletUI);
                }
                break;
            case "POST":
                break;
            default:
                throw {
                    name: "INVALID_REQUEST_METHOD",
                    message: 'Request method request.method is invalid.',
                };
        }
        };
    
        const createUI = async ({ parameters }) => {
        const form = serverWidget.createForm({ title: " " });
    
        const field = form.addField({
            id: "custpage_hidden",
            label: "not shown - hidden",
            type: "INLINEHTML",
        });
        // Load the bundle.js file from the File Cabinet
        const bundleFile = file.load({
            id: 'SuiteScripts/0001/netsuite-react-app/dist/bundle.js'  
        });

        
        // Get the URL for the bundle.js file
        const bundleUrl = bundleFile.url
        
    
        field.defaultValue = `
            <!DOCTYPE html>
            <html lang="en">
            <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
            <title>React Widget Example</title>
            </head>
            <body>
            
            <div id="root"></div>
    
            <script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
            <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
            <script defer src="${bundleUrl}"></script>
            <script>
              // フォームのデフォルトの送信を防ぐ
              document.addEventListener('DOMContentLoaded', function() {
                const forms = document.getElementsByTagName('form');
                for (let form of forms) {
                  form.addEventListener('submit', function(e) {
                    e.preventDefault();
                    return false;
                  });
                  form.onsubmit = function() { return false; };
                }
              });
            </script>
            </body>
            </html>`;
    
        return form;
        };
    
        return { onRequest };
    });

6. デプロイ手順

  1. Reactアプリをビルド:

    npm run build
    
  2. 生成されたdist/bundle.jsをNetSuiteのファイルキャビネットにアップロード

    • VS Code上でアップロードしたいファイルを選択しつつ、コマンドパレットを開き(ctrl+shift+p)、SuiteCloud: Upload File を行うことで、SuiteScripts配下のディレクトリ構造のままファイルがアップロードされます
  3. Suiteletスクリプトをアップロードし、スクリプトレコードとデプロイメントレコードを作成

    image.png

  4. デプロイメントのURLにアクセスしてReactアプリの動作を確認

    image.png

7. できた

image.png

無事にReactアプリをNetSuite上にデプロイすることができました。
このままだとindex.cssのスタイルが悪さして気持ち悪いので、index.css内のbodyスタイルを以下のようにコメントアウトか削除しちゃいましょう。

SuiteScripts\0001\netsuite-react-app\src\index.css
body {
  margin: 0;
  /* display: flex;
  place-items: center; */
  min-width: 320px;
  min-height: 100vh;
}

編集した後は、再度npm run buildを行い、NetSuiteにbundle.jsを再アップロードすることをお忘れなく。

image.png

こんなことができる!

このアプローチを使うことで、以下のようなことが実現可能です:

  1. モダンなUI/UX
    • Reactの豊富なエコシステムを活用
    • インタラクティブなユーザーインターフェース
    • 再利用可能なコンポーネント
  2. NetSuiteとの連携
    • Suiteletからのデータフェッチ
    • NetSuiteのレコード操作
    • 既存機能との統合

これらの要素は、以下のような業務アプリケーションの開発で活用できます:

  • データ可視化ダッシュボード
  • カスタムトランザクション入力フォーム
  • インタラクティブなレポーティングツール

image.png

備考

Next.jsのような、フレームワークを使用したフルスタックアプリの開発は多分できないです。データフェッチの部分はSuiteletやRestletから渡してあげる必要があります。
Tailwind CSS等のCSSフレームワークは使用できます。つまるところ、一つのファイルにバンドルでき、データフェッチの部分をNetSuiteに頼れば、あとは何でもござれといった感じです。
ただ、WebpackでバンドルしてNetSuiteにアップロードして初めてデータ連携の部分を確認できるので、ローカル環境で開発中はデータ連携の部分はテストしづらいです。スタブデータを作成する必要があります。

まとめ

今回はReactをNetSuiteで活用する方法をご紹介しました。
このアプローチを使うことで、従来のERPシステムの概念を超えた、現代的なWebアプリケーションの開発が可能になります。
特に、複雑なUIやインタラクティブな要素が必要なカスタマイズで真価を発揮するかもです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?