{"id":20495320,"url":"https://github.com/jualoppaz/single-spa-react-app","last_synced_at":"2025-04-13T17:43:31.117Z","repository":{"id":46826434,"uuid":"239291653","full_name":"jualoppaz/single-spa-react-app","owner":"jualoppaz","description":"React application with two example pages for be included in a single-spa application as registered app.","archived":false,"fork":false,"pushed_at":"2023-05-07T23:42:26.000Z","size":3434,"stargazers_count":10,"open_issues_count":5,"forks_count":10,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-04-14T12:42:42.077Z","etag":null,"topics":["bootstrap","react","single-spa","single-spa-demo","single-spa-react","webpack"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jualoppaz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-02-09T11:17:46.000Z","updated_at":"2024-04-12T05:44:11.000Z","dependencies_parsed_at":"2024-11-15T05:15:25.460Z","dependency_job_id":null,"html_url":"https://github.com/jualoppaz/single-spa-react-app","commit_stats":{"total_commits":40,"total_committers":2,"mean_commits":20.0,"dds":0.125,"last_synced_commit":"cb0a47c4145635e5af380641b8b9ade3db69dd91"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jualoppaz%2Fsingle-spa-react-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jualoppaz%2Fsingle-spa-react-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jualoppaz%2Fsingle-spa-react-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jualoppaz%2Fsingle-spa-react-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jualoppaz","download_url":"https://codeload.github.com/jualoppaz/single-spa-react-app/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248756402,"owners_count":21156762,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bootstrap","react","single-spa","single-spa-demo","single-spa-react","webpack"],"created_at":"2024-11-15T17:45:27.014Z","updated_at":"2025-04-13T17:43:31.090Z","avatar_url":"https://github.com/jualoppaz.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp float=\"left\"\u003e\n  \u003cimg src=\"https://single-spa.js.org/img/logo-white-bgblue.svg\" width=\"50\" height=\"50\"\u003e\n  \u003cimg src=\"https://cdn.auth0.com/blog/react-js/react.png\" width=\"50\" height=\"50\"\u003e\n\u003c/p\u003e\n\n[![npm version](https://img.shields.io/npm/v/single-spa-react-app.svg?style=flat-square)](https://www.npmjs.org/package/single-spa-react-app)\n\n# single-spa-react-app\n\nThis is a React application example used as NPM package in [single-spa-login-example-with-npm-packages](https://github.com/jualoppaz/single-spa-login-example-with-npm-packages) in order to register an application. See the installation instructions there.\n\n## ✍🏻 Motivation\n\nThis is a React application which contains two routed pages for embbed the app inside a root single-spa application.\n\n## How it works ❓\n\nThere are several files for the right working of this application and they are:\n\n- src/index.js\n- src/singleSpaEntry.js\n- package.json\n- webpack.config.js\n\n### src/index.js\n\n```javascript\nimport React from 'react';\nimport './index.css';\nimport { BrowserRouter } from 'react-router-dom';\n\nimport App from './App';\nimport * as serviceWorker from './serviceWorker';\n\n\nexport default class Root extends React.Component {\n  render() {\n    return (\n      \u003cBrowserRouter basename=\"/react\"\u003e\n        \u003cApp /\u003e\n      \u003c/BrowserRouter\u003e\n    );\n  }\n}\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: https://bit.ly/CRA-PWA\nserviceWorker.unregister();\n```\n\nAs this application will be mounted when browser url starts with **/react**, we need to set **basename** attribute with **/react** value in our router component. In this case the used router compononent is **BrowserRouter**.\n\n### src/singleSpaEntry.js\n\n```javascript\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport singleSpaReact from 'single-spa-react';\n\nimport rootComponent from './index';\n\nconst reactLifecycles = singleSpaReact({\n  React,\n  ReactDOM,\n  rootComponent,\n  domElementGetter: () =\u003e document.getElementById('react-app'),\n});\nexport const { bootstrap } = reactLifecycles;\nexport const { mount } = reactLifecycles;\nexport const { unmount } = reactLifecycles;\n```\n\nThe **reactLifecycles** object contains all **single-spa-react** methods for the **single-spa** lifecycle of this app. All used config is default one but the custom config of the **domElementGetter** option. It's assumed that an element with **react-app** id is defined in the **index.html** where this application will be mounted.\n\n### package.json\n\n```json\n{\n  \"name\": \"single-spa-react-app\",\n  \"version\": \"0.1.4\",\n  \"description\": \"React application with two example pages for be included in a single-spa application as registered app.\",\n  \"main\": \"dist/single-spa-react-app.js\",\n  \"dependencies\": {\n    \"react\": \"16.12.0\",\n    \"react-dom\": \"16.12.0\",\n    \"react-router-dom\": \"5.1.2\",\n    \"react-scripts\": \"4.0.0\",\n    \"single-spa-react\": \"2.11.0\"\n  },\n  \"scripts\": {\n    \"build\": \"webpack --config webpack.config.js -p\",\n    \"lint\": \"eslint . --ext .js --fix\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/jualoppaz/single-spa-react-app.git\"\n  },\n  \"author\": \"Juan Manuel López Pazos\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/jualoppaz/single-spa-react-app/issues\"\n  },\n  \"homepage\": \"https://github.com/jualoppaz/single-spa-react-app#readme\",\n  \"browserslist\": {\n    \"production\": [\n      \"\u003e0.2%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"7.8.4\",\n    \"@babel/preset-react\": \"7.8.3\",\n    \"@testing-library/jest-dom\": \"4.2.4\",\n    \"@testing-library/react\": \"9.4.0\",\n    \"@testing-library/user-event\": \"7.2.1\",\n    \"babel-eslint\": \"10.0.3\",\n    \"babel-loader\": \"8.0.6\",\n    \"clean-webpack-plugin\": \"3.0.0\",\n    \"css-loader\": \"3.4.2\",\n    \"eslint\": \"6.8.0\",\n    \"eslint-config-airbnb-base\": \"14.0.0\",\n    \"eslint-loader\": \"4.0.2\",\n    \"eslint-plugin-flowtype\": \"4.6.0\",\n    \"eslint-plugin-import\": \"2.20.1\",\n    \"eslint-plugin-react\": \"7.18.3\",\n    \"html-loader\": \"0.5.5\",\n    \"node-sass\": \"4.14.1\",\n    \"path\": \"0.12.7\",\n    \"sass-loader\": \"8.0.2\",\n    \"style-loader\": \"1.1.3\",\n    \"typescript\": \"3.7.5\",\n    \"webpack\": \"4.41.5\",\n    \"webpack-cli\": \"3.3.10\"\n  },\n  \"keywords\": [\n    \"single-spa\",\n    \"react\",\n    \"react-router-dom\",\n    \"npm\",\n    \"webpack\"\n  ]\n}\n```\n\nThere are only two scripts in this project:\n\n- **build**: for compile the application and build it as a **libray** in **umd** format\n- **lint**: for run **eslint** in all project\n\n### webpack.config.js\n\n```javascript\nconst path = require('path');\nconst webpack = require('webpack');\nconst { CleanWebpackPlugin } = require('clean-webpack-plugin');\n\nmodule.exports = {\n  entry: ['src/singleSpaEntry.js'],\n  output: {\n    library: 'single-spa-react-app',\n    libraryTarget: 'umd',\n    filename: 'single-spa-react-app.js',\n    path: path.resolve(__dirname, 'dist'),\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.js?$/,\n        exclude: [path.resolve(__dirname, 'node_modules')],\n        loader: ['babel-loader', 'eslint-loader'],\n      },\n      {\n        test: /\\.html$/i,\n        loader: 'html-loader',\n      },\n      {\n        test: /\\.css|\\.scss$/,\n        use: ['style-loader', 'css-loader', 'sass-loader'],\n      },\n    ],\n  },\n  node: {\n    fs: 'empty',\n  },\n  resolve: {\n    modules: [__dirname, 'node_modules'],\n  },\n  plugins: [\n    new CleanWebpackPlugin({\n      cleanAfterEveryBuildPatterns: ['dist'],\n    }),\n    new webpack.optimize.LimitChunkCountPlugin({\n      maxChunks: 1,\n    }),\n  ],\n  devtool: 'source-map',\n  externals: [],\n  devServer: {\n    historyApiFallback: true,\n    writeToDisk: true,\n  },\n};\n```\n\nThe needed options for the right build of the application as library are defined in the **output** field.\\\nThe **LimitChunkCountPlugin** is used for disable chunks for build process. It's not necessary but I prefer keep whole application in one chunk as it will be embedded in another one.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjualoppaz%2Fsingle-spa-react-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjualoppaz%2Fsingle-spa-react-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjualoppaz%2Fsingle-spa-react-app/lists"}