React コンポーネントがパッケージ化され、npm にリリースされます (create-react-app+ts+cesium)


最新の新しい要件は、コンポーネントを作成して npm で公開することです。このプロジェクトは React18 を使用し、create-react-app スキャフォールディングによって生成された反応フレームワークを使用します。プロジェクトには ts、セシウムなどが含まれます。
以前のプロジェクトは純粋な JS であったため、最初に変換する必要がありました。

反応フレームワークを構築する

スキャフォールディングにより反応フレームワークが生成される

ターミナルにコマンドを入力します。

npx create-react-app my-app --template typescript

設定ファイルを公開する

プロジェクト内には変更が必要な Webpack 構成が多数あるため、構成ファイルは直接公開されます。
ターミナルにコマンドを入力します:

npm run eject 
注:改动react框架中内容可能会造成无法eject,可先暴露文件然后再进行其他

エイリアスの構成

config フォルダーで webpack.config.js ファイルを探し、エイリアス (解決オブジェクトの下のエイリアス) を検索します。
コードを次のように変更します。

alias: {
    
    
        // Support React Native Web
        // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
        'react-native': 'react-native-web',
        // Allows for better profiling with ReactDevTools
        ...(isEnvProductionProfile && {
    
    
          'react-dom$': 'react-dom/profiling',
          'scheduler/tracing': 'scheduler/tracing-profiling',
        }),
        ...(modules.webpackAliases || {
    
    }),
        // 自定义的别名
        '@': path.resolve('src'),
},

このプロジェクトでは ts を使用するため、tsconfig.json ファイルを見つける必要があります。
コードを次のように変更します。

{
    
    
  "compilerOptions": {
    
    
    "target": "es5",// 转化成的目标语言
    "lib": [
      "dom",
      "dom.iterable",
      "esnext",
      "es2015"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": false,
    "jsx": "react-jsx",
    // 别名
    "paths": {
    
    
      "@/*": [
        "./src/*"
      ],
    },
  },
  "include": [
    "src",
  ],
  "exclude": ["node_modules", "build",]
}

プロジェクトを実行する

ターミナルにコマンドを入力します。

yarn start

この時点で、プロジェクトは正常に実行されます。

復興プロジェクト

このセクションが必要ない場合は、次のステップに進んでください。このセクションには、プロジェクトの変換中に発生した問題のみが記録されます。

SVGエラー

コンソールのエラー メッセージは次のとおりです。

Uncaught Error: Module build failed (from ./node_modules/@svgr/webpack/dist/index.js):
SyntaxError: unknown file: Namespace tags are not supported by default. React's JSX doesn't support namespace tags. You can set `throwIfNamespace: false` to bypass this warning. (at universalModuleDefinition:15:1)
Module build failed (from ./node_modules/@svgr/webpack/dist/index.js):
SyntaxError: unknown file: Namespace tags are not supported by default. React's JSX doesn't support namespace tags. You can set `throwIfNamespace: false` to bypass this warning.
   5 |   titleId,
   6 |   ...props
>  7 | }, ref) => <svg width={
    
    20} height={
    
    20} xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" ref={
    
    ref} aria-labelledby={
    
    titleId} {
    
    ...props}>{
    
    title ? <title id={
    
    titleId}>{
    
    title}</title> : null}<path fill="#aaa" d="m3,9l2,0l0,-4l4,0l0,-2l-6,0l0,6l0,0z" /><path fill="#aaa" d="m11,3l0,2l4,0l0,4l2,0l0,-6l-6,0l0,0z" /><path fill="#aaa" d="m15,15l-4,0l0,2l6,0l0,-6l-2,0l0,4l0,0z" /><path fill="#aaa" d="m5,11l-2,0l0,6l6,0l0,-2l-4,0l0,-4l0,0z" /></svg>;
     |                                                                           ^^^^^^^^^
   8 | const ForwardRef = forwardRef(SvgFullscreen);
   9 | export {
    
     ForwardRef as ReactComponent };
  10 | export default __webpack_public_path__ + "static/media/fullscreen.b7fda0177c8659d65ded39b4dd144ca8.svg";

図に示すように:
ここに画像の説明を挿入します
解決策:
Webpack 設定を変更し、ルート ディレクトリで config フォルダを見つけます。webpack.config を見つけます。 .js ファイル。
webpack.config.js ファイルでモジュール オブジェクトを見つけ、ルール配列を見つけます。
以下に示すようにルールを変更します。
ここに画像の説明を挿入します
コードは次のとおりです。

{
    
    
              test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/, /\.svg$/], //添加, /\.svg$/解决打包和报错问题
              type: "asset",
              parser: {
    
    
                dataUrlCondition: {
    
    
                  maxSize: imageInlineSizeLimit,
                },
              },
            },

この設定を変更すると、パッケージ化後に他のプロジェクトで参照したときに svg パスが見つからないという問題も解決されます。

セシウム関連の構成

このプロジェクトで使用されているセシウムのバージョンは 1.110.0 です。
プラグインをダウンロードする必要があります:

  • セシウム
  • コピー-webpack-プラグイン
  • ノード-ポリフィル-webpack-プラグイン

バージョンは次のとおりです。

"cesium": "^1.110.0",
"copy-webpack-plugin": "^11.0.0",
"node-polyfill-webpack-plugin": "^2.0.1",

ダウンロードコマンドは以下の通りです。

yarn add cesium -D
yarn add copy-webpack-plugin -D
yarn add node-polyfill-webpack-plugin -D

ルート ディレクトリで config フォルダを見つけます>webpack.config.js ファイルを見つけます
次のコードを webpack.config.js ファイルに追加します。

/* cesium */
const CopyWebpackPlugin = require("copy-webpack-plugin");
const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");
const cesiumSource = "node_modules/cesium/Source";
const cesiumWorkers = "../Build/Cesium/Workers";

//下面代码需要添加到plugins数组中
new CopyWebpackPlugin({
    
    
	patterns: [
		{
    
     from: path.join(cesiumSource, cesiumWorkers), to: "Workers" },
        {
    
     from: path.join(cesiumSource, "Assets"), to: "Assets" },
        {
    
     from: path.join(cesiumSource, "Widgets"), to: "Widgets" },
	],
}),
new NodePolyfillPlugin(),
new webpack.DefinePlugin({
    
    
	// env.stringified,
	CESIUM_BASE_URL: JSON.stringify(""),
}),

構成は次の図に示すとおりです。
ここに画像の説明を挿入します

ここに画像の説明を挿入します
セシウムコードをインスタンス化します。

let viewer = new Cesium.Viewer(mapContainer, {
    
    
      animation: false, //是否创建动画小器件,左下角仪表
      baseLayerPicker: false, //是否显示图层选择器
      fullscreenButton: false, //是否显示全屏按钮
      geocoder: false, //是否显示geocoder小器件,右上角查询按钮
      homeButton: false, //是否显示Home按钮
      infoBox: false, //是否显示信息框
      sceneModePicker: false, //是否显示3D/2D选择器,与scene3DOnly不能同时为true
      selectionIndicator: false, //是否显示选取指示器组件
      timeline: false, //是否显示时间轴
      navigationHelpButton: false, //是否显示右上角的帮助按钮
      scene3DOnly: false, //如果设置为true,则所有几何图形以3D模式绘制以节约GPU资源
      // terrainProvider: Cesium.createWorldTerrain(),
      orderIndependentTranslucency: false,
      contextOptions: {
    
    
        //cesium状态下允许canvas转图片convertToImage
        webgl: {
    
    
          alpha: true,
          depth: false,
          stencil: true,
          antialias: true,
          premultipliedAlpha: true,
          preserveDrawingBuffer: true,
          failIfMajorPerformanceCaveat: true,
        },
        allowTextureFilterAnisotropic: true,
      },
      // baseLayer: ,
});

viewer.imageryLayers.addImageryProvider(
      new Cesium.UrlTemplateImageryProvider({
    
    
        url: "地址xxxxxxxxxx",
        maximumLevel: 18,
      })
);
viewer.scene.sun.show = false;
viewer.scene.moon.show = false;
viewer.scene.skyBox.show = true;
viewer.scene.backgroundColor = new Cesium.Color(0.0, 0.0, 0.0, 0.0);

コードミラー構成

バージョンは次のとおりです。

"@codemirror/lang-javascript": "^6.2.1",
"@types/codemirror": "^5.60.12",
"codemirror": "5.38.0",

バージョンが異なればインスタンス化方法も異なるため、スタイル テーマを有効にするには導入する必要があります。
コードは次のとおりです。

import CodeMirror from "codemirror";
import {
    
     javascript } from "@codemirror/lang-javascript";
import "codemirror/lib/codemirror.css";
import "codemirror/theme/monokai.css"; //主题样式文件
import "codemirror/mode/javascript/javascript"; //javascript模式
import "codemirror/addon/hint/show-hint.css";
import "codemirror/addon/hint/show-hint";

// var codemirror = new EditorView({
    
    
//   extensions: [basicSetup, javascript()],
//   parent: container.dom!,
// });
var codemirror = CodeMirror(container.dom, {
    
    
    value: "",
    lineNumbers: true,
    lineWrapping: true,
    matchBrackets: true,
    indentWithTabs: true,
    tabSize: 4,
    indentUnit: 4,
    mode: "javascript",
  });
codemirror.setOption("theme", "monokai");
codemirror.on("change", function () {
    
    
    if (codemirror.state.focused === false) return;
    clearTimeout(delay);
    delay = setTimeout(function () {
    
    
      if (errorLine) {
    
    
        codemirror.removeLineClass(errorLine, "CodeMirror-errorLine");
        errorLine = null;
      }

      if (currentScript !== null) {
    
    
        currentScript.source = codemirror.getValue();

        editor.signals.scriptChanged.dispatch();
      } else if (currentEffect !== null) {
    
    
        var error;
        var currentSource = currentEffect.source;

        editor.timeline.reset();

        try {
    
    
          currentEffect.source = codemirror.getValue();
          editor.compileEffect(currentEffect);
        } catch (e) {
    
    
          error = e.name + " : " + e.message; // e.stack, e.columnNumber, e.lineNumber

          if (/Chrome/i.test(navigator.userAgent)) {
    
    
            var result = /<anonymous>:([0-9]+):([0-9+])/g.exec(e.stack);
            if (result !== null) errorLine = parseInt(result[1]) - 3;
          } else if (/Firefox/i.test(navigator.userAgent)) {
    
    
            var result = /Function:([0-9]+):([0-9+])/g.exec(e.stack);
            if (result !== null) errorLine = parseInt(result[1]) - 1;
          }

          if (errorLine !== null) {
    
    
            codemirror.addLineClass(
              errorLine,
              "errorLine",
              "CodeMirror-errorLine"
            );
          }
        }

        editor.timeline.update(editor.player.currentTime);

        if (error !== undefined) {
    
    
          errorDiv.setDisplay("");
          errorText.setValue("⌦ " + error);

          currentEffect.source = currentSource;
        } else {
    
    
          errorDiv.setDisplay("none");
        }
      }
    }, 1000);
});

React での src ファイルの外部のコンテンツの参照

create-react-app スキャフォールディングによって生成されたフレームワークは src ディレクトリの外部からの参照を禁止しているため、webpack 構成を変更する必要があります。

webpack.config.js ファイルの変更コードは次のとおりです。
解決オブジェクト プラグイン配列を見つけます

plugins: [
        // Prevents users from importing files from outside of src/ (or node_modules/).
        // This often causes confusion because we only process files within src/ with babel.
        // To fix this, we prevent you from importing files out of src/ -- if you'd like to,
        // please link the files into your node_modules/ and let module-resolution kick in.
        // Make sure your source files are compiled, as they will not be processed in any way.
        new ModuleScopePlugin(paths.appRoot, [
          paths.appPackageJson,
          reactRefreshRuntimeEntry,
          reactRefreshWebpackPluginRuntimeEntry,
          babelRuntimeEntry,
          babelRuntimeEntryHelpers,
          babelRuntimeRegenerator,
        ]),
],

config で paths.js ファイルを見つけます。
上記でインポートしたパスを paths.js ファイルに入力します。
コードは次のとおりです。< /span>

module.exports = {
    
    
  dotenv: resolveApp('.env'),
  appPath: resolveApp('.'),
  appBuild: resolveApp(buildPath),
  appPublic: resolveApp('public'),
  appHtml: resolveApp('public/index.html'),
  appIndexJs: resolveModule(resolveApp, 'src/index'),
  buildEntry: resolveModule(resolveApp, 'src/gis'),
  appPackageJson: resolveApp('package.json'),
  appSrc: resolveApp('src'),
  appTsConfig: resolveApp('tsconfig.json'),
  appJsConfig: resolveApp('jsconfig.json'),
  yarnLockFile: resolveApp('yarn.lock'),
  testsSetup: resolveModule(resolveApp, 'src/setupTests'),
  proxySetup: resolveApp('src/setupProxy.js'),
  appNodeModules: resolveApp('node_modules'),
  appWebpackCache: resolveApp('node_modules/.cache'),
  appTsBuildInfoFile: resolveApp('node_modules/.cache/tsconfig.tsbuildinfo'),
  swSrc: resolveModule(resolveApp, 'src/service-worker'),
  publicUrlOrPath,
  appRoot: resolveApp(''),
};

パック

パッケージの入口と出口の構成

プロジェクトの最終エクスポートが js に変更されるため、パッケージ化された js ファイルの名前とパスが変更されます。
webpack.config.js ファイルで、出力オブジェクトを見つけます。
コードを次のように変更します。

output: {
    
    
      // The build folder.
      path: paths.appBuild,
      // Add /* filename */ comments to generated require()s in the output.
      pathinfo: isEnvDevelopment,
      // There will be one main bundle, and one file per asynchronous chunk.
      // In development, it does not produce real files.
      // filename: isEnvProduction
      //   ? 'static/js/[name].[contenthash:8].js'
      //   : isEnvDevelopment && 'static/js/bundle.js',
      filename: "index.js",//出口js文件路径及其名称
      library: {
    
    
        name: "library", //库输出变量名
        type: "umd", //库类型
        export: "Gis", //导出变量名
        auxiliaryComment: "test component",
      },
      // There are also additional JS chunk files if you use code splitting.
      chunkFilename: isEnvProduction
        ? "static/js/[name].[contenthash:8].chunk.js"
        : isEnvDevelopment && "static/js/[name].chunk.js",
      assetModuleFilename: "static/media/[name].[hash][ext]",
      // webpack uses `publicPath` to determine where the app is being served from.
      // It requires a trailing slash, or the file assets will get an incorrect path.
      // We inferred the "public path" (such as / or /my-project) from homepage.
      publicPath: paths.publicUrlOrPath,
      // Point sourcemap entries to original disk location (format as URL on Windows)
      devtoolModuleFilenameTemplate: isEnvProduction
        ? (info) =>
          path
            .relative(paths.appSrc, info.absoluteResourcePath)
            .replace(/\\/g, "/")
        : isEnvDevelopment &&
        ((info) =>
          path.resolve(info.absoluteResourcePath).replace(/\\/g, "/")),
    },

プロジェクト構造に従ってts宣言ファイルをパッケージ化して出力する

create-react-app スキャフォールドで生成された Webpack は、ts-loader の代わりに babel-loader を使用して ts をコンパイルするため、ts-loader の依存関係を追加する必要があります。

ts-loader のバージョンは次のとおりです。

"ts-loader": "^9.5.0"

webpack.config.js を変更します。

//改代码为修改之前的代码
{
    
    
              test: /\.(js|mjs|jsx|ts|tsx)$/,
              include: paths.appSrc,
              loader: require.resolve('babel-loader'),
              options: {
    
    
                customize: require.resolve(
                  'babel-preset-react-app/webpack-overrides'
                ),
                presets: [
                  [
                    require.resolve('babel-preset-react-app'),
                    {
    
    
                      runtime: hasJsxRuntime ? 'automatic' : 'classic',
                    },
                  ],
                ],

                plugins: [
                  isEnvDevelopment &&
                  shouldUseReactRefresh &&
                  require.resolve('react-refresh/babel'),
                ].filter(Boolean),
                // This is a feature of `babel-loader` for webpack (not Babel itself).
                // It enables caching results in ./node_modules/.cache/babel-loader/
                // directory for faster rebuilds.
                cacheDirectory: true,
                // See #6846 for context on why cacheCompression is disabled
                cacheCompression: false,
                compact: isEnvProduction,
              },
            },

//修改之后的代码如下
{
    
    
              test: /\.(ts|tsx)$/,
              loader: require.resolve("ts-loader"),
              options: {
    
    
                transpileOnly: false,
              },
            },
            {
    
    
              test: /\.(js|mjs|jsx)$/,
              include: paths.appSrc,
              loader: require.resolve("babel-loader"),
              options: {
    
    
                customize: require.resolve(
                  "babel-preset-react-app/webpack-overrides"
                ),
                presets: [
                  [
                    require.resolve("babel-preset-react-app"),
                    {
    
    
                      runtime: hasJsxRuntime ? "automatic" : "classic",
                    },
                  ],
                ],

                plugins: [
                  isEnvDevelopment &&
                  shouldUseReactRefresh &&
                  require.resolve("react-refresh/babel"),
                ].filter(Boolean),
                // This is a feature of `babel-loader` for webpack (not Babel itself).
                // It enables caching results in ./node_modules/.cache/babel-loader/
                // directory for faster rebuilds.
                cacheDirectory: true,
                // See #6846 for context on why cacheCompression is disabled
                cacheCompression: false,
                compact: isEnvProduction,
              },
            },

実際、このアイデアは、コンパイルされた ts ルールを他のルールとは別に記述し、ts には ts-loader を使用するというものです。

テスト用に別のプロジェクトをパッケージ化して導入する

パッケージ化されたエクスポートは src ディレクトリ内のインデックスであるため、このコンポーネントをエクスポートする必要があります。そのため、index.tsx の名前を変更し、エクスポートされたコンポーネントへの参照を追加します。
追加Index.ts ファイル:

import Gis from "./views/gis/Gis";
export {
    
     Gis };

パッケージ化コマンドを実行します。

yarn build

余談ですが、run を追加しなくても start と build を実行できます。
パッケージ化されたファイルを別の空のプロジェクトにコピーし、空のプロジェクトにプラグインを導入します。
コードは次のとおりです。

import React from 'react';
import './App.css';
import Gis from "../build/index.js"
function App() {
    
    
  return (
    <div className="App">
      <Gis />
    </div>
  );
}

export default App;

現時点では操作は成功しています。
続く~~
エラーレポートがある場合は、該当するエラーレポートに従って問題を解決してください。

npmリリースプロセス

ログインnpm

ターミナルにコマンドを入力します。

npm login

ユーザー名、パスワード、メール アドレスを順番に入力します。
メール アドレスの確認コードも入力する場合もあります。
次のようなエラーが報告される場合もあります。以下に示す:
ここに画像の説明を挿入します

エラーメッセージは次のとおりです。

code F403
npm ERR!
npm ERR!403 403 Forbidden - PU https://registry.npmirror. con/-/user/org. couchdb.user:csiyu - [FORBIDDEN] Public registration is not allowetnpm ERR!403 In most cases, you or one of your dependencies are requestingnpmERr!403 a package version that is forbidden by your security policy, ornpm ERR! 403 on a server you do not have access to.
npmERR! A complete log of this run can be found in:npmERR!/Users/chensiyu/.npm/_ logs/2023-10 27T07 10 40 630Z-debug -0.log![请添加图片描述](https://img-blog.csdnimg.cn/b540f3eca1d3407ba8dc1734f3bddd69.jpeg)

エラーの理由は npm ミラー ソースにあります。ミラー ソースを切り替えてください。
ターミナルにコマンドを入力してください:

npm config set registry https://registry.npmjs.org/

もう一度ログインしてください。

リリース

ターミナルにコマンドを入力します。

npm publish

次のエラーが発生した場合:

npm ERR! code E403
npm ERR! 403 403 Forbidden - PUT https://registry.npmjs.org/test-xxx - You do not have permission to publish “test-xxx”. Are you logged in as the correct user?
npm ERR! 403 In most cases, you or one of your dependencies are requesting
npm ERR! 403 a package version that is forbidden by your security policy, or
npm ERR! 403 on a server you do not have access to.

パッケージ名がnpmと競合しているためです。パッケージ名を変更して再公開してください。

成功したリリースは次のようになります。
ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/iYNing/article/details/134071448