React components are packaged and released to npm (create-react-app + ts + cesium) and continuously updated~
- Build react framework
-
- Scaffolding generates react framework
- Expose configuration file
- Configure alias
- Run the project
- Reconstruction project
-
- svg error
- cesium related configuration
- codemirror configuration
- Reference content outside the src file in react
- Pack
-
- Package entry and exit configuration
- Package and output the ts declaration file according to the project structure
- Package and introduce another project for testing
- npm release process
-
- Login npm
- release
The latest new requirement is to make a component and publish it on npm. This project uses React18 and uses the react framework generated by the create-react-app scaffolding. The project includes ts, cesium, etc.
The previous project was pure js and needed to be transformed first.
Build a react framework
Scaffolding generates react framework
Enter the command in the terminal:
npx create-react-app my-app --template typescript
Exposed configuration file
Because there are many webpack configurations that need to be changed in the project, the configuration files are directly exposed.
Enter the command in the terminal:
npm run eject Note: Changing the content in the react framework may cause eject to fail. You can expose the file first and then perform other operations.
Configure alias
Find the webpack.config.js file in the config folder and search for alias (alias under the resolve object)
Modify the code as follows:
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 & amp; & amp; {<!-- --> 'react-dom$': 'react-dom/profiling', 'scheduler/tracing': 'scheduler/tracing-profiling', }), ...(modules.webpackAliases || {<!-- -->}), // Custom alias '@': path.resolve('src'), },
Because the project uses ts, you need to find the tsconfig.json file
Modify the code as follows:
{<!-- --> "compilerOptions": {<!-- --> "target": "es5",//The target language converted into "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", // alias "paths": {<!-- --> "@/*": [ "./src/*" ], }, }, "include": [ "src", ], "exclude": ["node_modules", "build",] }
Run the project
Enter the command in the terminal:
yarn start
At this point the project runs successfully!
Renovation project
If this section is not needed, you can proceed to the next step. This section only records the problems encountered during the project transformation.
svg error
The console error message is as follows:
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";
As shown in the picture:
Solution:
Modify the webpack configuration and find the config folder in the root directory > find the webpack.config.js file.
Find the module object in the webpack.config.js file and find the rules array.
Modify the rules as shown below:
code show as below:
{<!-- --> test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/, /\.svg$/], //Add, /\.svg$/Solve packaging and error reporting issues type: "asset", parser: {<!-- --> dataUrlCondition: {<!-- --> maxSize: imageInlineSizeLimit, }, }, },
Modifying this configuration will also solve the problem that the svg path cannot be found when referenced in other projects after packaging.
cesium related configuration
The version of cesium used in this project is 1.110.0.
Need to download plug-in:
- cesium
- copy-webpack-plugin
- node-polyfill-webpack-plugin
The versions are as follows:
"cesium": "^1.110.0", "copy-webpack-plugin": "^11.0.0", "node-polyfill-webpack-plugin": "^2.0.1",
The download command is as follows:
yarn add cesium -D yarn add copy-webpack-plugin -D yarn add node-polyfill-webpack-plugin -D
Find the config folder in the root directory > find the webpack.config.js file
Add the following code to the webpack.config.js file:
/* 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"; //The following code needs to be added to the plugins array 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(""), }),
The configuration is as shown in the figure:
Instantiate cesium code:
let viewer = new Cesium.Viewer(mapContainer, {<!-- --> animation: false, //Whether to create an animated widget, instrument in the lower left corner baseLayerPicker: false, //Whether to display the layer selector fullscreenButton: false, //Whether to display the full screen button geocoder: false, //Whether to display the geocoder widget, query button in the upper right corner homeButton: false, //Whether to display the Home button infoBox: false, //Whether to display the information box sceneModePicker: false, //Whether to display the 3D/2D selector, and scene3DOnly cannot be true at the same time selectionIndicator: false, //Whether to display the selection indicator component timeline: false, //Whether to display the timeline navigationHelpButton: false, //Whether to display the help button in the upper right corner scene3DOnly: false, //If set to true, all geometries are drawn in 3D mode to save GPU resources // terrainProvider: Cesium.createWorldTerrain(), orderIndependentTranslucency: false, contextOptions: {<!-- --> //Allow canvas to convert image convertToImage in cesium state 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: "address 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 configuration
The versions are as follows:
"@codemirror/lang-javascript": "^6.2.1", "@types/codemirror": "^5.60.12", "codemirror": "5.38.0",
Different versions have different instantiation methods, and a style theme needs to be introduced to take effect.
code show as below:
import CodeMirror from "codemirror"; import {<!-- --> javascript } from "@codemirror/lang-javascript"; import "codemirror/lib/codemirror.css"; import "codemirror/theme/monokai.css"; //theme style file import "codemirror/mode/javascript/javascript"; //javascript mode 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 refers to content outside the src file
Because the framework generated by the create-react-app scaffolding prohibits references from outside the src directory, the webpack configuration needs to be modified.
The webpack.config.js file modification code is as follows:
Find the resolve object-plugins array
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, ]), ],
Find the paths.js file under config
Fill in the above imported path in the paths.js file
code show as below:
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(''), };
Packaging
Packaging entrance and exit configuration
Because the final export of the project is changed to js, the name and path of the packaged js file are modified.
webpack.config.js file, find the output object
Modify the code as follows:
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 & amp; & amp; 'static/js/bundle.js', filename: "index.js",//Export js file path and name library: {<!-- --> name: "library", //Library output variable name type: "umd", //Library type export: "Gis", //Export variable name 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 & amp; & amp; "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 & amp; & amp; ((info) => path.resolve(info.absoluteResourcePath).replace(/\/g, "/")), },
Package and output ts declaration files according to the project structure
The webpack generated in the create-react-app scaffold uses babel-loader instead of ts-loader to compile ts, so you need to add the ts-loader dependency.
The ts-loader version is as follows:
"ts-loader": "^9.5.0"
Modify webpack.config.js:
//Change the code to the code before modification {<!-- --> 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 & amp; & amp; shouldUseReactRefresh & amp; & amp; 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, }, }, //The modified code is as follows {<!-- --> 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 & amp; & amp; shouldUseReactRefresh & amp; & amp; 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, }, },
In fact, the idea is to write the compiled ts rules separately from other ones, and use ts-loader for ts.
Package and introduce another project for testing
We need to export this component because the packaged export is the index in the src directory, so change the name of index.tsx and add a reference to the exported component.
Add index.ts file:
import Gis from "./views/gis/Gis"; export {<!-- --> Gis };
Run the packaging command:
yarn build
As a digression here, start and build can run without adding run.
Copy the packaged file to another empty project, and introduce the plug-in in the empty project.
code show as below:
import React from 'react'; import './App.css'; import Gis from "../build/index.js" function App() {<!-- --> return ( <div className="App"> <Gis /> </div> ); } export default App;
At this point the operation is successful.
To be continued~~
If there is an error report, just solve the problem according to the relevant error report.
npm release process
Log in to npm
Enter the command in the terminal:
npm login
Enter your username, password, and email in sequence
Some will also enter the verification code of their email address
Some will report an error as shown below:
The error message is as follows:
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, ornpmERR! 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![Please add image description](https:/ /img-blog.csdnimg.cn/b540f3eca1d3407ba8dc1734f3bddd69.jpeg)
The reason for the error is because of the npm mirror source. Just switch the mirror source.
Enter the command in the terminal:
npm config set registry https://registry.npmjs.org/
Just log in again.
Publish
Enter the command in the terminal:
npm publish
If you encounter the following error:
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.
It’s because the package name conflicts with npm. Just modify the package name and re-publish it.
The successful release is as shown below: