Blog features are powered by the blog plugin. Simply add files to the blog directory. It supports tags as well!
Delete the whole directory if you don't want the blog features. As simple as that!
diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml deleted file mode 100644 index ab83886..0000000 --- a/.github/workflows/node.js.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Deploy to GitHub Pages - -on: - release: - types: [created] - -jobs: - deploy: - name: Deploy to GitHub Pages - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 - with: - node-version: 14.x - cache: yarn - - name: Build website - run: | - yarn install - yarn build - - # Popular action to deploy to GitHub Pages: - # Docs: https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus - - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GH_TOKEN }} - # Build output to publish to the `gh-pages` branch: - publish_dir: ./build - # Assign commit authorship to the official GH-Actions bot for deploys to `gh-pages` branch: - # https://github.com/actions/checkout/issues/13#issuecomment-724415212 - # The GH actions bot is used by default if you didn't specify the two fields. - # You can swap them out with your own user credentials. - user_name: vinodloha - user_email: vinodloha@gmail.com diff --git a/.gitignore b/.gitignore deleted file mode 100644 index b083ed4..0000000 --- a/.gitignore +++ /dev/null @@ -1,21 +0,0 @@ -# Dependencies -/node_modules - -# Production -/build - -# Generated files -.docusaurus -.cache-loader - -# Misc -.DS_Store -.env -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/static/.nojekyll b/.nojekyll similarity index 100% rename from static/.nojekyll rename to .nojekyll diff --git a/404.html b/404.html new file mode 100644 index 0000000..577bd32 --- /dev/null +++ b/404.html @@ -0,0 +1,18 @@ + + +
+ + + + +We could not find what you were looking for.
Please contact the owner of the site that linked you to the original URL and let them know their link is broken.
Your Docusaurus site did not load properly.
\nA very common reason is a wrong site baseUrl configuration.
\nCurrent configured baseUrl = '+e+" "+("/"===e?" (default value)":"")+'
\nWe suggest trying baseUrl =
\n\n'}(e)).replace(/0)&&(j.current.unobserve(e),j.current.disconnect(),null!=I&&window.docusaurus.prefetch(I))}))})),j.current.observe(e))},to:I},h&&{isActive:y,activeClassName:b}))}var h=o.forwardRef(m)},5999:function(e,t,n){"use strict";n.d(t,{Z:function(){return u},I:function(){return l}});var r=n(7294);function a(e,t){var n=e.split(/(\{\w+\})/).map((function(e,n){if(n%2==1){var r=null==t?void 0:t[e.slice(1,-1)];if(void 0!==r)return r}return e}));return n.some((function(e){return(0,r.isValidElement)(e)}))?n.map((function(e,t){return(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e})).filter((function(e){return""!==e})):n.join("")}var o=n(7529);function i(e){var t,n,r=e.id,a=e.message;if(void 0===r&&void 0===a)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return null!=(t=null!=(n=o[null!=r?r:a])?n:a)?t:r}function l(e,t){return a(i({message:e.message,id:e.id}),t)}function u(e){var t=e.children,n=e.id,o=e.values;if(t&&"string"!=typeof t)throw console.warn("Illegal.comment can become .namespace--comment) or replace them with your defined ones (like .editor__comment). You can even add new classes.",owner:"dvkndn",noCSS:!0},"file-highlight":{title:"File Highlight",description:"Fetch external files and highlight them with Prism. Used on the Prism website itself.",noCSS:!0},"show-language":{title:"Show Language",description:"Display the highlighted language in code blocks (inline code does not show the label).",owner:"nauzilus",noCSS:!0,require:"toolbar"},"jsonp-highlight":{title:"JSONP Highlight",description:"Fetch content with JSONP and highlight some interesting content (e.g. GitHub/Gists or Bitbucket API).",noCSS:!0,owner:"nauzilus"},"highlight-keywords":{title:"Highlight Keywords",description:"Adds special CSS classes for each keyword for fine-grained highlighting.",owner:"vkbansal",noCSS:!0},"remove-initial-line-feed":{title:"Remove initial line feed",description:"Removes the initial line feed in code blocks.",owner:"Golmote",noCSS:!0},"inline-color":{title:"Inline color",description:"Adds a small inline preview for colors in style sheets.",require:"css-extras",owner:"RunDevelopment"},previewers:{title:"Previewers",description:"Previewers for angles, colors, gradients, easing and time.",require:"css-extras",owner:"Golmote"},autoloader:{title:"Autoloader",description:"Automatically loads the needed languages to highlight the code blocks.",owner:"Golmote",noCSS:!0},"keep-markup":{title:"Keep Markup",description:"Prevents custom markup from being dropped out during highlighting.",owner:"Golmote",optional:"normalize-whitespace",noCSS:!0},"command-line":{title:"Command Line",description:"Display a command line with a prompt and, optionally, the output/response from the commands.",owner:"chriswells0"},"unescaped-markup":{title:"Unescaped Markup",description:"Write markup without having to escape anything."},"normalize-whitespace":{title:"Normalize Whitespace",description:"Supports multiple operations to normalize whitespace in code blocks.",owner:"zeitgeist87",optional:"unescaped-markup",noCSS:!0},"data-uri-highlight":{title:"Data-URI Highlight",description:"Highlights data-URI contents.",owner:"Golmote",noCSS:!0},toolbar:{title:"Toolbar",description:"Attach a toolbar for plugins to easily register buttons on the top of a code block.",owner:"mAAdhaTTah"},"copy-to-clipboard":{title:"Copy to Clipboard Button",description:"Add a button that copies the code block to the clipboard when clicked.",owner:"mAAdhaTTah",require:"toolbar",noCSS:!0},"download-button":{title:"Download Button",description:"A button in the toolbar of a code block adding a convenient way to download a code file.",owner:"Golmote",require:"toolbar",noCSS:!0},"match-braces":{title:"Match braces",description:"Highlights matching braces.",owner:"RunDevelopment"},"diff-highlight":{title:"Diff Highlight",description:"Highlights the code inside diff blocks.",owner:"RunDevelopment",require:"diff"},"filter-highlight-all":{title:"Filter highlightAll",description:"Filters the elements the highlightAll and highlightAllUnder methods actually highlight.",owner:"RunDevelopment",noCSS:!0},treeview:{title:"Treeview",description:"A language with special styles to highlight file system tree structures.",owner:"Golmote"}}})},2885:function(e,t,n){const r=n(9901),a=n(9642),o=new Set;function i(e){void 0===e?e=Object.keys(r.languages).filter((e=>"meta"!=e)):Array.isArray(e)||(e=[e]);const t=[...o,...Object.keys(Prism.languages)];a(r,e,t).load((e=>{if(!(e in r.languages))return void(i.silent||console.warn("Language does not exist: "+e));const t="./prism-"+e;delete n.c[n(6500).resolve(t)],delete Prism.languages[e],n(6500)(t),o.add(e)}))}i.silent=!1,e.exports=i},6726:function(e,t,n){var r={"./":2885};function a(e){var t=o(e);return n(t)}function o(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=o,e.exports=a,a.id=6726},6500:function(e,t,n){var r={"./":2885};function a(e){var t=o(e);return n(t)}function o(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=o,e.exports=a,a.id=6500},9642:function(e){"use strict";var t=function(){var e=function(){};function t(e,t){Array.isArray(e)?e.forEach(t):null!=e&&t(e,0)}function n(e){for(var t={},n=0,r=e.length;nArchive
blog directory. It supports tags as well!Delete the whole directory if you don't want the blog features. As simple as that!
]]>Blog features are powered by the blog plugin. Simply add files to the blog directory. It supports tags as well!
Delete the whole directory if you don't want the blog features. As simple as that!
blog directory. It supports tags as well!Delete the whole directory if you don't want the blog features. As simple as that!
]]>Blog features are powered by the blog plugin. Simply add files to the blog directory. It supports tags as well!
Delete the whole directory if you don't want the blog features. As simple as that!
Blog features are powered by the blog plugin. Simply add files to the blog directory. It supports tags as well!
Delete the whole directory if you don't want the blog features. As simple as that!
Blog features are powered by the blog plugin. Simply add files to the blog directory. It supports tags as well!
Delete the whole directory if you don't want the blog features. As simple as that!
Blog features are powered by the blog plugin. Simply add files to the blog directory. It supports tags as well!
Delete the whole directory if you don't want the blog features. As simple as that!
Universal React accelerator has taken several steps to ensure the Adoption Readiness of the tool.
Universal React accelerator can be adopted into your projects in multiple ways.
npx create-universal-reactto setup your project, if you are completely aligned with Technology choices. You can make necessary tweaks and adjust these choices post initial setup.We have a future road map to continuously evolve this tool and make it even better.
There are two ways of looking at potential effort saves:
It helps you save the most important time at the start of the project, by providing a dependable dev ecosystem. A rough estimate of time saved for off the self (npx create-universal-react) implementation is 2 Weeks. Since we have a lot of best practices and optional features baked-in. Owing to its evolving nature, it continues to add value throughout the project life cycle. Therefore actual effort saved is much more.
If you are looking to build a similar CLI generator for customized on-prem uses, adopting and publishing this tool into on-prem artifactory can save at least 2 months.
Universal React generator has Atomic Design Philosophy at its core. Apart from setting up Atomic scaffolding structure (Atoms, Molecules, Organism and Template) it brings along customizable npm packages @xt-pagesource/generate-plop to create components, services and hooks on the fly.
Atomic design is a mental modal, when applied correctly it can do wonders in developing applications with great speed, brings great design consistency and reusability. It pushes you to identify and capture repeatable patterns throughout the application in reusable components. These components in turn will help develop user journeys faster and consistently. Components should be created with Single Responsibility in mind to achieve maximum reusability.
basePath is the URL prefix for all API paths, relative to the host root. It must start with a leading slash /. If basePath is not specified, it defaults to /, that is, all paths start at the host root. basePath is set at the next.config.js file.
basePath: process.env.BASE_PATH || ''
Deep path is set in the package.json file.
"scripts": {
"env-var": "cross-env BASE_PATH=/universal-react"
}
This path can be modified by changing /universal-react.
There are many ways you can help contribute make Universal React better.
npx create-universal-react to setup you project. A consistent design system is integrated to the all of the app types by using nextui and theme.js file which can be generated by using the structure defined by nextui create theme docs and using nextui createTheme method.
nextui is a library that uses stitches internally to style components in the react ecosystem. It allows users to write styles in css within the js files. It also has components and provides customized theming. To know more about nextui visit nextui org docs.
nextui provides <NextUIProvider> which is a theme provider component which accepts a theme prop (created using createTheme nextui method and json) which overrides the nextui default theme.
<NextUIProvider> is kept at the highest level in the component chain. This allows all of the components within it to inherit the theme prop. In case of our Next.js app the <NextUIProvider> is added in src/pages/_app.js.nextui provides a default theme that can be used out of the box.createTheme nextui method and store it as src/themes/theme.js.nextui styled components, theme props is available to use as following:export const Button = styled('button', {
fontSize: '$3',
color: '$fontColor',
margin: '1em',
padding: '0.25em 1em',
border: '2px solid black',
borderRadius: '$1',
display: 'block',
length: '1'
});
The length property used in styled method is added temporarily for the issue of nextui styled method with typescript v4.6.2. Will not be required once the issue is resolved.
+Issue: https://github.com/modulz/stitches/issues/947
More about cutomizing theming can be found in nextui customize theme docs.
This accelerator is an highly opinionated collection of tools and best practices. It is possible that you have a different take on some of these choices. Feel free to enhance your project post initial setup or clone of this generator to suit your needs.
| Feature | Uses | Configurability | Optional |
|---|---|---|---|
| Monorepo development environment | Turborepo | No | No |
| SSR & SSG | Next.js | No | No |
| Micro Frontend | Module Federation | Yes | Yes |
| Component Scaffolding | Generate-Plop | Yes | Yes |
| State Management | Smart-Context | Yes | No |
| Remote Data | React Query | Yes | No |
| Unit Testing | Jest & React Testing Library | Yes | No |
| E2E Testing automation | Test Cafe | Yes | Yes |
| Theme & Styling | Stitches | Yes | No |
| Generic Component Library | Next UI | Yes | Yes |
| Component Dev | Storybook. | Yes | No |
| Git Hooks | Husky | Yes | No |
| PWA | Workbox | Yes | Yes |
| Authoring | Markdown-to-JSX | Yes | Yes |
| Scaffolding | Atomic Design | No | No |
| Typesafe | TypeScript. | Yes | No |
| Mocking | GraphQl & REST APIs | Yes | Yes |
| Localization and Logging | NA | Yes | No |
| Code quality and formatting | Eslint, StyleLint and Prettier | Yes | No |
| VS Code Extensions | Recommended Extensions and Config | Yes | Yes |
@xt-pagesource/generate-plop is a simple, extensible and scalable component generator. It can help you to scaffold components, templates, hooks and pages simply by running few cli commands. Automating the component creation process makes really easy for the team to maintain consistency and saves good time.
This tool will generate typescript files by default. However, we can generate +javascript files as well by passing --js in script command.

You can generate the following components using generate-plop
You can use this generator in a single app repo as well as in a monorepo +(powered by turborepo). +generate-plop is intelligent enough to figure out if it being run in single app repo +or in the root directory of monorepo.
If it is a monorepo, you will be asked to choose the from the application in /apps
+annd /packages directories where you wish to create the component.
After the app selection workflow of monorepo is same as the workflow in single repo application. +The workflow is explaied below.
As of now, the Current version creates react-components only. You can create Functional +or Class components.
/src/{category}
+to be available./src directory.
+In the last step, you will need to provide the name of the componentt.Based on all details provided generate-tool will create follwoing files:
index.ts Export statement for the component.{name}.tsReact componenttests/{name}.test.ts Unit test basic structure for the component using React Test Library{name}.style.ts Style file for the component using Stitches Styling Library{name}.story.ts Storybook created for the component.You can create React custom hooks. You
+will need to provide name for the hook.
+The custom hook will be created in src/hooks directory. generate-tool
+will create the following files:
index.ts React custom hook.test.ts Unit test basic structure for the hook using React Test LibraryYou can create Next pages.
src/pages.index.ts Export statement for the template.{name}.tsIf Template doesn't exists, it will create a template in the dir src/components/templatessrc/routes/paths.ts file.You can create React context. Context created +is smart-context. It makes state management +simple. You will need to provide store name. Files created by the tool are:
index.ts Export statement for the store.contextProvider.ts Context will return the provider wrapped component.You can create services using react-query to fetch +cache ad create data. You have an option to create rest based services or graphql based +services.
packages/services directory.{name}.ts Service created using react-querytypes/common.ts Interface for default props used in the service (Only for Typescript)There are 2 Key Pillars of Universal React.
React developers can run npx create-universal-react generator for setting up Micro Frontend and/or SPA architecture with essential tooling instantly.
React developers can continuously improve their project by running npx create-universal-react generator again for adding optional features like mocking, end-to-end testing or even new projects to their evolving applications.
Using this generator you can setup and evolve a project into a combination of following architecture types.

There are 2 ways you can achieve Micro Frontend in this ecosystem.
Micro-App Loader: A small NPM package to load any React micro app or Web Component into a given container. Learn more here. +This approach is ideal when:
1. You are not loading too many Micro Apps on a stitching layer.
2. You don't want to change configurations of Micro App to support Module Federation.
Module Federation: Multiple separate builds should form a single application. These separate builds should not have dependencies between each other, so they can be developed and deployed individually. +This approach is ideal when:
1. You are loading too many Micro Apps on a stitching layer.
2. You want to minimize the JS footprint of common libraries between micro apps and stitching layer.
2. You have flexibility to change configurations of Micro App to support Module Federation.
Learn more here.
An accelerator for setting-up scalable frontend architecture with React and Next.js.
This accelerator is a command line tool for generating SSR, SSG & Micro-App type of applications. This enables you to setup a full-fledged Micro Frontend development ecosystem with essential tooling for great dev experience and delivery quality.
This will help project teams in building applications with great quality, by giving them more time to focus on business problems rather than web development chores.
npx create-universal-react
This will run the universal-react CLI, then you can simply interact with command-prompt to generate 3 different kind of applications in a Monorepo structure.
Following flow chart explains the workings of generator.

This project exists thanks to all the people who contribute.
Loader is a react component, mainly used to load the other micro react micro apps using manifest files, solve the problems of cross-team collaboration and reduce the build dependency.
To compose multiple independently delivered front-end applications into a whole, and to decompose front-end applications into some smaller and simpler applications that can be "independently developed", "independently tested" and "independently deployed", while still appearing to users as cohesive individual products.
<Loader url='http://localhost:5000/manifest.json' loading={<h3>loading ...</h3>} appdata= {{"count":count}} namespace='headerApp' selector='headercontainer'/>
<Loader url='http://localhost:5002/manifest.json' loading={<h3>loading ...</h3>} namespace='webComponent' selector='webcomponentcount'>
<web-component name-attribute={count}>\</web-component>
</Loader>
appdata contains data you want to pass to your micro app as object. +namespace name under which your exporting the app(Required). +selector id given to the div on which app is loaded(Required). +loading element to show while loading. +url url of the mainfest.json file(Required). +deferloading it is boolean to load script async or non-async,true by default.
This logger collect logs based on different levels and structures them
{
appName,
logLevel,
logInfo: {
component,
subComponent
},
browser: {
location,
host,
userAgent
},
event: {
name,
attributes
},
error: {
name,
attributes
},
service = {
url,
body
},
userInfo,
localTimestamp
};
This logger module provides a logger initializer:
createLogger: A utility logger init function that returns a logger which follows the above structure along with some auto-logging features:landingLogs: takes a boolean value that sets wheather landing logs to be automatically logged or not on url change. Adds an event listener to actively check for url changes.handleExceptions: takes a boolean value that sets wheather unhandled syntax/runtime errors/exceptions to be automatically logged or not. Adds an event listener to actively check for such errors. createLogger:
import createLogger from '../utils/Logger';
const loggerConfig = {
appName: 'application name to be shown in the logs',
level: 'info', // lowest allowed level of log
parseUserAgent: true, // return device, browser and os details if true; returns user-agent string if false
remoteDataAgregatorUrl: 'http://localhost:4000' // remote API end-point to post the logs
}
const user = {
name: 'John Doe',
id: '101'
}
const Logger = createLogger({
loggerConfig,
user,
landingLogs: true,
handleExceptions: true
});
Logger.error({
logInfo: {
component: 'Home',
subComponent: 'UserCard'
}
error: {
name: 'failed to fetch',
attributes: {
code: '400',
operationName: 'getUserInfo'
}
},
event: {
name: 'click',
attributes: {
targetElement: 'Button',
innerText: 'Show More'
}
}
service: {
url: '/get-user-info/'
},
});
You can write JSX and use React components within your Markdown thanks to MDX.
Docusaurus green and Facebook blue are my favorite colors.I can write Markdown alongside my JSX!
Add the following ModuleFederation Plugin configurations to expose code that needs to be shared with other applications
const deps = require("./package.json").dependencies;
module.exports = {
reactStrictMode: true,
webpack: (config, options) => {
const { ModuleFederationPlugin } = options.webpack.container;
config.plugins.push(
new ModuleFederationPlugin({
name: "providerApp",
filename: "remoteEntry.js",
exposes: {
"./Button": "./src/Button",
}
shared: { ...deps,react: { singleton: true, requiredVersion: deps.react, }, 'react-dom': { singleton: true, requiredVersion: deps["react-dom"]} },
},
})
);
return config;
},
}
In this example we are running it on server 5000. +Remote identifies host with it's specified name, here i.e providerApp.The Button componant is exposed and libraries are shared
Add the following ModuleFederation Plugin configurations to consume code that is being shared
module.exports = {
reactStrictMode: true,
webpack: (config, options) => {
const { ModuleFederationPlugin } = options.webpack.container;
config.plugins.push(
new ModuleFederationPlugin({
remotes: {
providerApp: "providerApp@http://localhost:5000/remoteEntry.js",
},
})
);
return config;
},
}
In the above configurations at remotes add the provider url
import dynamic from "next/dynamic";
const SharedButton = dynamic(
async () => {
return await import("providerApp/Button");
},
{
ssr: false,
}
)
export default function MyPage() {
return <SharedButton />
}
Monorepos are incredible for productivity, especially on the frontend, but the tooling can be a nightmare. Turborepo makes it easy.
Learn more here, on why use Turborepo?
Read this for a comparison of NX vs Turborepo

Config packages to unify code linting and typescript configuration and rules across projects. No need to install those packages anymore in your each project and maintain them all separately, thanks to monorepo structure.

Use simple JavaScript to write E2E tests and automate functional testing of your application with TestCafe.
There are many additional capabilities we are looking forward to add. Some of those are listed here in order of priority. We are open to take additional feature requests from our community through issus page.
React state management made easy. Inspired by Redux. Powered by Context.
Here is the working demo with src link
v2 updates
Highlights
npm
npm install smart-context
yarn
yarn add smart-context
v2 introduces new API and features. Refer v1 docs and example.
initContext is removed. Use WithContextProvider HOCWithContextConsumer HOCReact context acts as global store. It contains state object and actions that trigger state updates. All components that consume the state will be updated on every action dispatch.
actionsConfig, initialState, displayNameApp component in WithContextProvider HOCdisplayName anywhere inside the App.Decide a top level component to initialize and plug-in smart-context
// app.jsx
import React from "react";
import { WithContextProvider } from "smart-context";
const initialState = { name: "default", age: 0 };
// Two types of action definitions
const actionsConfig = {
setName: ["name"],
setAge: (age) => (state) => ({ ...state, age }),
};
const displayName = "myContext";
/** Config */
const config = {
initialState,
actionsConfig,
displayName,
debug: true,
};
const App = () => (
<div id="app-container">
All children will have access to state and actions via context
</div>
);
// Apply multiple contexts using list of config objects
export default WithContextProvider(App, [config]);
// myAwesomeComponent.jsx
import React, { useContext } from "react";
import { getContext } from "smart-context";
const MyAwesomeComponent = () => {
// context name is required to access context
const {
state: { name, age },
actions: { setName, setAge, reset },
} = useContext(getContext("myContext"));
const clickHandlerDefault = () => {
// default action handler (pass object with exact key names declared in action config)
setName({ name: "ABCD" });
};
const clickHandlerCustom = () => {
// custom handler
setAge(25);
};
const resetHandler = () => {
// reset action is auto-generated (if not provided) that restores initial state
reset();
};
return (
<>
<div>
`Name: {name} Age: {age}`
</div>
<button onClick={clickHandlerDefault}>Set Name</button>
<button onClick={clickHandlerCustom}>Set Age</button>
<button onClick={resetHandler}>Reset</button>
</>
);
};
export default MyAwesomeComponent;
import React from "react";
import { WithContextConsumer } from "smart-context";
class DemoComp extends React.Component {
constructor(props) {
super(props);
}
render() {
const { state } = props.myContext
<div>{state.name}</div>;
}
}
// Wrap component in context consumer HOC. Access multiple contexts using displayName list
export default WithContextConsumer(DemoComp, ["myContext"]);
Following methods are available from this package:
| Method | Param | Return | Description |
|---|---|---|---|
| WithContextProvider | React Component | React Component | Provider HOC. Accepts list of config objects |
| WithContextConsumer | React Component | React Component | Consumer HOC. Accepts list of displayName |
| getContext | string | React Context | Access context (state and actions) |
displayName: string (mandatory)
displayName in react dev toolsdebug: boolean
initialState: object (not mandatory but recommended)
actionsConfig: object
{ actionName: [string] | function }actionNamereset is auto-generated that restores initialStateProvide list of state keys for update. Action call expects an object with same keys. Any other key provided during action dispatch will be ignored. These actions use ES6 spread operator for state updates.
actionName: ["key1", "key2"];
Provide a function that returns state transformation function
actionName: async (payload) => {
// Async API call here
const data = await AsyncAPICall()
// State transform function
return (state) => {...state, ...data}
};
A reset action is auto-generated if not provided in config. This action uses flat ES6 spread operator to copy initialState. It is recommended to use a custom function in action config, if initialState is a deeply nested object
In a component driven development ecosystem such as React, a tool like Storybook is essential. It allows developers to build, test component in isolation. This is perfect way to build reusable components. Ideally 80% of development should happen via Storybook this way teams are never blocked because of test data or env issues.
Storybook setup is equipped with important add-ons to test for A11Y as well.
yarn storybookyarn build-storybookStorybook is configured with great addons for setting up an ideal dev ecosystem.
Developers can add global test features,enviroment,mocks in the file config\jest\jest.setup.js
Mocks for files such as jpg, jpeg, png, gif, eot, otf, webp, svg, ttf, woff, woff2, mp4, webm, wav, mp3, m4a, aac, oga and stylesheets are configured
pre-push testing is added in husky
| Test Util Functions | Description |
|---|---|
| assertByTestId(renderComp,testId,isTruthy) | assert whether testId is present |
| assertByTextContent(getByText,textContent) | assert whether given textContent is present |
| assertProperty(obj,key,val) | assert value of the property in an object |
| renderWithContext({Comp,ContextProviderRef,state,props}) | renders the component with given context |
| assertMockFunctionArg ({mockFunction,funCallIndex,argIndex,argument}) | asserts the mth Argument of Mock Function for n number of function calls |
| Parameter | Description |
|---|---|
| renderComp | Rendered Component |
| testId | TestId which has to be checked |
| isTruthy | if truthy, test passes if the testId is present; if falsy, test passes if the testId is not present |
| getByText | The getByText property reference of rendered |
| textContent | Text String that needs to be asserted |
| obj | object reference |
| key | property |
| val | expected value of the key |
| Comp | Component |
| ContextProviderRef | context provider (ex: contextProviderRef=SomeContext.Provider) |
| state | state of context that has to be assigned |
| props | props that needs to be assigned to the given Component ie.Comp |
| mockFunction | Mock Function |
| funCallIndex | Index of nth function call (note:Indexing starts from 0,Index of function for the first call is 0) |
| argIndex | Index of the argument (Indexing starts from 0) |
| argument | expected argument |
With Reuse, Replicate and Reduce philosophy at its core Universal React is an accelerator to generate SSR, SSG or Micro-Apps with essential tooling to enable great dev experience and solution quality.
| Create React App | Create Next App | Universal React App | |
|---|---|---|---|
| SSR, SSG | No | Yes | Yes |
| MicroApp | Yes | No | Yes |
| Customization | Low | High | Very High |
| Monorepo setup | No | No | Yes, with Turborepo |
| Typescript | Yes | Yes | Yes |
| Unit Testing setup | Yes | Yes | Yes |
| Inbuilt Storybook | No | No | Yes |
| Design system | No | No | Yes |
| Micro App Loader | No | No | Yes |
| State Management Solution | No | No | Yes, with Smart Context |
| Browser & Server logger | No | No | Yes |
| Component generator | No | No | Yes, with Generate Plop |
| Module Federation | No | No | Yes |
| Quality control config | No | No | Yes |
| E2E automation | No | No | Yes, with Test Cafe |
| PWA | No | No | Yes, with Workbox |
| VS Code Config | No | No | Yes, extensions recommendations and config |
Not only Universal React saves 100s of initial setup hours, it brings in efficiency by reducing the effort to explore solutions, tool and best practices.
Lets take an example: If you
An accelerator for great developer experience.
CLI tool for generating SSR, SSG & Micro-App type of applications.
Lets you focus on business problems rather than web development chores.
Run npx create-universal-react This will run the create-universal-react CLI.
{description}
-{siteConfig.tagline}
-