👻 Zero-configuration framework-agnostic static prerendering for SPAs

Overview

react-snap Build Status npm npm Twitter Follow

Pre-renders a web app into static HTML. Uses Headless Chrome to crawl all available links starting from the root. Heavily inspired by prep and react-snapshot, but written from scratch. Uses best practices to get the best loading performance.

😍 Features

  • Enables SEO (Google, DuckDuckGo...) and SMO (Twitter, Facebook...) for SPAs.
  • Works out-of-the-box with create-react-app - no code-changes required.
  • Uses a real browser behind the scenes, so there are no issues with unsupported HTML5 features, like WebGL or Blobs.
  • Does a lot of load performance optimization. Here are details, if you are curious.
  • Does not depend on React. The name is inspired by react-snapshot but works with any technology (e.g., Vue).
  • npm package does not have a compilation step, so you can fork it, change what you need, and install it with a GitHub URL.

Zero configuration is the main feature. You do not need to worry about how it works or how to configure it. But if you are curious, here are details.

Basic usage with create-react-app

Install:

yarn add --dev react-snap

Change package.json:

"scripts": {
  "postbuild": "react-snap"
}

Change src/index.js (for React 16+):

import { hydrate, render } from "react-dom";

const rootElement = document.getElementById("root");
if (rootElement.hasChildNodes()) {
  hydrate(<App />, rootElement);
} else {
  render(<App />, rootElement);
}

That's it!

Basic usage with Preact

To do hydration in Preact you need to use this trick:

const rootElement = document.getElementById("root");
if (rootElement.hasChildNodes()) {
  preact.render(<App />, rootElement, rootElement.firstElementChild);
} else {
  preact.render(<App />, rootElement);
}

Basic usage with Vue.js

Install:

yarn add --dev react-snap

Change package.json:

"scripts": {
  "postbuild": "react-snap"
},
"reactSnap": {
  "source": "dist",
  "minifyHtml": {
    "collapseWhitespace": false,
    "removeComments": false
  }
}

Or use preserveWhitespace: false in vue-loader.

source - output folder of webpack or any other bundler of your choice

Read more about minifyHtml caveats in #142.

Example: Switch from prerender-spa-plugin to react-snap

Caveats

Only works with routing strategies using the HTML5 history API. No hash(bang) URLs.

Vue uses the data-server-rendered attribute on the root element to mark SSR generated markup. When this attribute is present, the VDOM rehydrates instead of rendering everything from scratch, which can result in a flash.

This is a small hack to fix rehydration problem:

window.snapSaveState = () => {
  document.querySelector("#app").setAttribute("data-server-rendered", "true");
};

window.snapSaveState is a callback to save the state of the application at the end of rendering. It can be used for Redux or async components. In this example, it is repurposed to alter the DOM, this is why I call it a "hack." Maybe in future versions of react-snap, I will come up with better abstractions or automate this process.

Vue 1.x

Make sure to use replace: false for root components

Examples

⚙️ Customization

If you need to pass some options for react-snap, you can do this in your package.json like this:

"reactSnap": {
  "inlineCss": true
}

Not all options are documented yet, but you can check defaultOptions in index.js.

inlineCss

Experimental feature - requires improvements.

react-snap can inline critical CSS with the help of minimalcss and full CSS will be loaded in a non-blocking manner with the help of loadCss.

Use inlineCss: true to enable this feature.

TODO: as soon as this feature is stable, it should be enabled by default.

⚠️ Caveats

Async components

Also known as code splitting, dynamic import (TC39 proposal), "chunks" (which are loaded on demand), "layers", "rollups", or "fragments". See: Guide To JavaScript Async Components

An async component (in React) is a technique (typically implemented as a higher-order component) for loading components on demand with the dynamic import operator. There are a lot of solutions in this field. Here are some examples:

It is not a problem to render async components with react-snap, the tricky part happens when a prerendered React application boots and async components are not loaded yet, so React draws the "loading" state of a component, and later when the component is loaded, React draws the actual component. As a result, the user sees a flash:

100%                    /----|    |----
                       /     |    |
                      /      |    |
                     /       |    |
                    /        |____|
  visual progress  /
                  /
0%  -------------/

Usually a code splitting library provides an API to handle it during SSR, but as long as "real" SSR is not used in react-snap - the issue surfaces, and there is no simple way to fix it.

  1. Use react-prerendered-component. This library holds onto the prerendered HTML until the dynamically imported code is ready.
import loadable from "@loadable/component";
import { PrerenderedComponent } from "react-prerendered-component";

const prerenderedLoadable = dynamicImport => {
  const LoadableComponent = loadable(dynamicImport);
  return React.memo(props => (
    // you can use the `.preload()` method from react-loadable or react-imported-component`
    <PrerenderedComponent live={LoadableComponent.load()}>
      <LoadableComponent {...props} />
    </PrerenderedComponent>
  ));
};

const MyComponent = prerenderedLoadable(() => import("./MyComponent"));

MyComponent will use prerendered HTML to prevent the page content from flashing (it will find the required piece of HTML using an id attribute generated by PrerenderedComponent and inject it using dangerouslySetInnerHTML).

  1. The same approach will work with React.lazy, but React.lazy doesn't provide a prefetch method (load or preload), so you need to implement it yourself (this can be a fragile solution).
const prefetchMap = new WeakMap();
const prefetchLazy = LazyComponent => {
  if (!prefetchMap.has(LazyComponent)) {
    prefetchMap.set(LazyComponent, LazyComponent._ctor());
  }
  return prefetchMap.get(LazyComponent);
};

const prerenderedLazy = dynamicImport => {
  const LazyComponent = React.lazy(dynamicImport);
  return React.memo(props => (
    <PrerenderedComponent live={prefetchLazy(LazyComponent)}>
      <LazyComponent {...props} />
    </PrerenderedComponent>
  ));
};

const MyComponent = prerenderedLazy(() => import("./MyComponent"));
  1. use loadable-components 2.2.3 (current is >5). The old version of loadable-components can solve this issue for a "snapshot" setup:
import { loadComponents, getState } from "loadable-components";
window.snapSaveState = () => getState();

loadComponents()
  .then(() => hydrate(AppWithRouter, rootElement))
  .catch(() => render(AppWithRouter, rootElement));

If you don't use babel plugin, don't forget to provide modules:

const NotFoundPage = loadable(() => import("src/pages/NotFoundPage"), {
  modules: ["NotFoundPage"]
});

loadable-components were deprecated in favour of @loadable/component, but @loadable/component dropped getState. So if you want to use loadable-components you can use old version (2.2.3 latest version at the moment of writing) or you can wait until React will implement proper handling of this case with asynchronous rendering and React.lazy.

Redux

See: Redux Server Rendering Section

// Grab the state from a global variable injected into the server-generated HTML
const preloadedState = window.__PRELOADED_STATE__;

// Allow the passed state to be garbage-collected
delete window.__PRELOADED_STATE__;

// Create Redux store with initial state
const store = createStore(counterApp, preloadedState || initialState);

// Tell react-snap how to save Redux state
window.snapSaveState = () => ({
  __PRELOADED_STATE__: store.getState()
});

Caution: as of now, only basic "JSON" data types are supported: e.g. Date, Set, Map, and NaN won't be handled correctly (#54).

Third-party requests: Google Analytics, Mapbox, etc.

You can block all third-party requests with the following config:

"skipThirdPartyRequests": true

AJAX

react-snap can capture all AJAX requests. It will store json requests in the domain in window.snapStore[<path>], where <path> is the path of the request.

Use "cacheAjaxRequests": true to enable this feature.

This feature can conflict with the browser cache. See #197 for details. You may want to disable cache in this case: "puppeteer": { "cache": false }.

Service Workers

By default, create-react-app uses index.html as a fallback:

navigateFallback: publicUrl + '/index.html',

You need to change this to an un-prerendered version of index.html - 200.html, otherwise you will see index.html flash on other pages (if you have any). See Configure sw-precache without ejecting for more information.

Containers and other restricted environments

Puppeteer (Headless Chrome) may fail due to sandboxing issues. To get around this, you may use:

"puppeteerArgs": ["--no-sandbox", "--disable-setuid-sandbox"]

Read more about puppeteer troubleshooting.

"inlineCss": true sometimes causes problems in containers.

Docker + Alpine

To run react-snap inside docker with Alpine, you might want to use a custom Chromium executable. See #93 and #132.

Heroku

heroku buildpacks:add https://github.com/jontewks/puppeteer-heroku-buildpack.git
heroku buildpacks:add heroku/nodejs
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-static.git

See this PR. At the moment of writing, Heroku doesn't support HTTP/2.

Semantic UI

Semantic UI is defined over class substrings that contain spaces (e.g., "three column"). Sorting the class names, therefore, breaks the styling. To get around this, use the following configuration:

"minifyHtml": { "sortClassName": false }

From version 1.17.0, sortClassName is false by default.

JSS

Once JS on the client is loaded, components initialized and your JSS styles are regenerated, it's a good time to remove server-side generated style tag in order to avoid side-effects

https://github.com/cssinjs/jss/blob/master/docs/ssr.md

This basically means that JSS doesn't support rehydration. See #99 for a possible solutions.

react-router v3

See #135.

userAgent

You can use navigator.userAgent == "ReactSnap" to do some checks in the app code while snapping—for example, if you use an absolute path for your API AJAX request. While crawling, however, you should request a specific host.

Example code:

const BASE_URL =
  process.env.NODE_ENV == "production" && navigator.userAgent != "ReactSnap"
    ? "/"
    : "http://xxx.yy/rest-api";

Alternatives

See alternatives.

Who uses it

cloud.gov.au blacklane reformma

Contributing

Report a bug

Please provide a reproducible demo of a bug and steps to reproduce it. Thanks!

Share on the web

Tweet it, like it, share it, star it. Thank you.

Code

You can also contribute to minimalcss, which is a big part of react-snap. Also, give it some stars.

Comments
  • Should add link rel=

    Should add link rel="preload"

    On adding the option inlineCss: true the important styles are extracted, but the main style accessed by link still has a property rel="stylesheet" while it should be rel="preload"

    bug 
    opened by ryan-ds17 26
  • CRA2 compatibility

    CRA2 compatibility

    I was just trying out react-snap with my project. When I open the site I get a lot of these warnings:

    The resource http://localhost:8000/static/js/5.f6bab7d8.chunk.js was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it has an appropriateasvalue and it is preloaded intentionally.

    Are chunks not properly supported, or is this something else?

    Thanks!

    bug 
    opened by raRaRa 23
  • Way to prerender pages with some extra settings

    Way to prerender pages with some extra settings

    I need prerendered pages for three cases: unlogged user, unlogged user from mobile and logined user. Currently i can do this only by insert some hacks into app code, which is not very good at my opinion. So, can react-snap handle this cases in some way? Ability to set viewport or cookie for url will solve my problem.

    question 
    opened by Amareis 22
  • Error: EISDIR: illegal operation on a directory, open...

    Error: EISDIR: illegal operation on a directory, open...

    @stereobooster Would you tell me How to solve this error ?

    $ yarn build
    yarn run v1.10.1
    $ /Users/sensuikan1973/ReactApp/homepage/node_modules/.bin/react-snap
     ️️️💬  console.log at /: Content is cached for offline use.
     ️️️💬  console.log at /: This web app is being served cache-first by a service worker. To learn more, visit https://goo.gl/SC7cgQ
     ️️️💬  console.log at /: Failed to load resource: net::ERR_UNKNOWN_URL_SCHEME
    ✅  crawled 1 out of 6 (/)
     ️️️💬  console.log at /programming: Failed to load resource: net::ERR_UNKNOWN_URL_SCHEME
     ️️️💬  console.log at /404.html: Failed to load resource: net::ERR_UNKNOWN_URL_SCHEME
     ️️️💬  console.log at /othello: Failed to load resource: net::ERR_UNKNOWN_URL_SCHEME
     ️️️💬  console.log at /memo: Failed to load resource: net::ERR_UNKNOWN_URL_SCHEME
    💬  in browser redirect (/)
    ⚠️  warning: 404 page title does not contain "404" string
    💬  in browser redirect (/)
    ✅  crawled 2 out of 6 (/programming)
    ⚠️  warning: 404 page title does not contain "404" string
    🔥  error at /404.html { Error: EISDIR: illegal operation on a directory, open '/Users/sensuikan1973/ReactApp/homepage/build/'
        at Object.openSync (fs.js:443:3)
        at Object.writeFileSync (fs.js:1205:35)
        at saveAsHtml (/Users/sensuikan1973/ReactApp/homepage/node_modules/react-snap/index.js:484:8)
        at process.internalTickCallback (internal/process/next_tick.js:77:7)
      errno: -21,
      syscall: 'open',
      code: 'EISDIR',
      path: '/Users/sensuikan1973/ReactApp/homepage/build/' }
    💬  in browser redirect (/)
    ✅  crawled 4 out of 6 (/othello)
    💬  in browser redirect (/)
    ✅  crawled 5 out of 6 (/memo)
     ️️️💬  console.log at /profile: Failed to load resource: net::ERR_UNKNOWN_URL_SCHEME
    💬  in browser redirect (/)
    ✅  crawled 6 out of 6 (/profile)
    
    error Command failed with exit code 1.
    
    bug wait for more info 
    opened by sensuikan1973 17
  • Performance enhancements

    Performance enhancements

    I know that react-snap is primarily about creating static HTML snapshots, but there's a lot of opportunity to make performance tweaks to the built page. It would be awesome if these tweaks could be considered:

    • JS files are not required at all for the first render. So, there's no reason that scripts should contribute to holding back the window onload event. Until this event has fired, all browser indicators are firing to show that page load is in progress - things like the spinner in the tab and the message at the bottom of the window. Removing the usually large JS files from this critical page load process reduces the "apparent" page load time drastically. The solution is to use <link rel='preload' as='script' href='...' /> in the <head>. This (a) kicks off script download early, (b) makes the script load process async and (c) doesn't hold back the window.onload event. (While investigating/testing for this, I suggest using the 'Slow 3G' setting in chrome devtools to throttle the network.)
    • A side-effect of code-splitting is that the first JS payload (main.hash.js in CRA apps) has to be downloaded and executed first, which then issues requests for the chunks (which then issues requests for other chunks, etc.). Downloading of all the needed chunks is hence a sequential process. This makes the page load process very time consuming. We already know during the snapshot process that the page needs additional chunks. So, we could rel='preload' all of them upfront. This not only gets out of the way of the page load process, it actually significantly speeds up the time to initialise, since all the chunks are downloaded in parallel.
    • The downside of the approach above is that while <link rel='preload' ... downloads assets, it doesn't execute them, of course. I've handled this by injecting a "script loader" into the page, which inserts the main script file (main.hash.js) as a regular script tag after all the link-preloads have completed.
    • This one isn't important for me, since I use glamor in lieu of external CSS files, but it's an easy win, so why not. Stylesheets also block the page load process. Since critical CSS is inlined during the snapshot process, again, there's no reason to hold back the page load event for external stylesheets. The solution again is to <link rel='preload' as='style' href='...' /> the stylesheets, and inject a script that inserts this as a stylesheet after page load is complete. It's a very interesting trick too - in window.onload, simply change the rel='preload' to rel='stylesheet', and you're done. This one needs a fallback for users that have disabled JS in their browsers, so a <noscript> containing the regular <link rel='stylesheet' href='...' /> in the head is required. Pages will take longer to load for people who have JS disabled, but at least things won't be outright broken for them.

    Just to give you an idea of how much savings this gives, on a site I'm working on (~160kb in assets for a page, mostly JS files), when I use the 'Slow 3G' throttling, before these changes, I was getting to DOMContentLoaded in ~6 seconds and Load in ~20 seconds. With these tweaks in place, I get to DOMContentLoaded in <2 seconds, and Load in <6 seconds. So, the savings aren't minor at all.

    If you want to look at some example code, here I'm preloading scripts, and here I'm preloading stylesheets. I'm concatenating multiple script stubs together to inject into the page (so that there's only one script tag for easy CSP). Here's the stub to insert the script tag and here's the stub to insert the stylesheet. These stubs are combined and wrapped in a window.on('load', function() { ... }), so that it's only executed after page load is completed.

    If this enhancement is mainlined, and #76 and #74 are resolved, and once I figure out what's going wrong with my loadable-component, I can actually dump my repo and use react-snap instead. I created snapshotify because I felt like these changes are out of the scope of react-snap. However, if you think that these changes are not out of scope, then it doesn't make sense to split our efforts. I'll gladly contribute here instead. However, at the moment, it just felt like it'll be faster for me to create my own snapshot tool, and I'll probably stick to this decision for the immediate future. In the long term, it makes no sense to crowd the already crowded tooling space. :)

    Sorry for the long read, and thanks for entertaining the ramblings of a webperf nerd. Feel free to ask if you have questions. I may not be able to reply immediately, since I may have very spotty network coverage for the next few days.

    enhancement 
    opened by rakeshpai 17
  • Unable to deploy to Heroku with create-react-app-buildpack

    Unable to deploy to Heroku with create-react-app-buildpack

    When deploying I am getting this error, which actually seems to freeze the build process on Heroku:

    (node:629) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Failed to launch chrome!
    /tmp/build_2e66391b352738bb3c9a1b44c5632458/jesshmusic-living_music_database-ca09d15273a13f10f1a1a9e7ffd147503a55dc26/node_modules/react-snap/node_modules/puppeteer/.local-chromium/linux-499413/chrome-linux/chrome: error while loading shared libraries: libXss.so.1: cannot open shared object file: No such file or directory
    TROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md
    (node:629) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
    

    I have attempted to add the puppeteer build pack as described in the troubleshooting link above but it doesn't do any good. Does anyone have a solution to get this to deploy in Heroku? If it is something I missed in the docs kindly point me in that direction.

    question 
    opened by jesshmusic 17
  • 400 error on all 3rd-party requests

    400 error on all 3rd-party requests

    Why do I get 400 errors during running react snap on 3rd-party requests? When loading through browser, everything is fine. But during react-snap's process they are all logged as 400 errors and therefore the static pages are saved without them.

    question 
    opened by hesedel 16
  • How do you add or exclude routes?

    How do you add or exclude routes?

    1. Is it possible to define a list of routes? This is useful for routes which are not "linked" from any page - for example, landing pages for ad campaigns, etc.

    2. Is it possible to exclude certain routes? This is useful for routes which have a lot of dynamic or private content, such as user account pages.

    opened by whydna 14
  • Any guidance for React.lazy (or at least a solution for breaking changed @loadable/component)?

    Any guidance for React.lazy (or at least a solution for breaking changed @loadable/component)?

    Is there a way to use react-snap with React.lazy directly?

    loadable-component has evolved and focused on server side rendering.

    import { hydrate, render } from 'react-dom';
    import { loadableReady } from '@loadable/component';
    
    // ⚠️not more getState() in newer loadable-components so no more: window.snapSaveState = () => getState();
    
    if (bootstrapedElement.hasChildNodes()) {
        loadableReady().then(() => {
          return hydrate(<Application />, bootstrapedElement);
        });
      }
      return render(<Application />, bootstrapedElement);
    

    This does not work anymore!

    bug enhancement help wanted question 
    opened by MacKentoch 14
  • Documentation: Confusion over Apollo/Redux implementation

    Documentation: Confusion over Apollo/Redux implementation

    In the redux section it mentions this code:

    // Grab the state from a global variable injected into the server-generated HTML
    const preloadedState = window.__PRELOADED_STATE__;
    
    // Allow the passed state to be garbage-collected
    delete window.__PRELOADED_STATE__;
    
    // Create Redux store with initial state
    const store = createStore(counterApp, preloadedState || initialState);
    
    // Tell react-snap how to save Redux state
    window.snapSaveState = () => ({
      __PRELOADED_STATE__: store.getState()
    });
    

    However, I suppose the confusion is for me - where does this code actually go?

    opened by dottjt 14
  • weird element placement behavior

    weird element placement behavior

    after using react snap (there is no problem before), instead got this normal result: before

    with this normal structure before


    i got this weird result after

    with this weid structure after


    As you can see, the 'contact__item' is supposed inside 'contact' but instead I got it's inside 'jss20'. Its also got applied in 'home__desc'

    I'm using react-reveal for animate the component and at first I think its the cause, but the result still same even when I'm remove the animation.

    The fun part is, when I click the link to move to another route and back to home its become normal again. So i think the problem is with prerendered html

    Already tested in latest chrome and mozilla with hard reload.

    If you are curious with how i use css, and its same with another component code

    bug wait for more info 
    opened by iwgx 14
  • Add exclude option (no new dependency added)

    Add exclude option (no new dependency added)

    Description

    Main reason why I added this was because I was generating a static build for a simple site, but for some reason it crawls a url with a different domain (localhost with different port). I would try and investigate the localhost issue, but having an exclude option will cover future problems as well.

    • Adding some simple logic to exclude specific URLs from crawl queue.
    • Did not include exclude in the defaultOptions (not sure how to properly update the snapshot 🤷).
    • Unit test

    Feel free to close, but so far tests are good. I will use the forked version for my use case right now, but having it in the main repo would be nicer.

    Cheers!

    opened by joananespina 0
  • There is a phenomenon in which the build does not end in the GitHub Actions (Linux Latest) environment.

    There is a phenomenon in which the build does not end in the GitHub Actions (Linux Latest) environment.

    The README installed it as guided. At first, it worked normally, but from last week, there is a phenomenon in which the build continues to be loaded without success or failure. What kind of settings do I need to do?

    Screenshot 2022-12-15 at 12 05 50 PM

    opened by dnlwllms 6
  • Support Vite.JS

    Support Vite.JS

    Feature Request

    Is your feature request related to a problem? Please describe. Cannot use the react-snap with vite.js

    Describe the solution you'd like Would be great to have an implementation of react-snap for the react plugin of vite.js

    Describe alternatives you've considered I've considered using vite-plugin-ssr prerendering option, but my project is small and using this library requires a lot of changes, refactoring and useless boilerplate. I'd like to have a simple solution for vite and I think react-snap is a perfect fit.

    opened by johannbuscail 0
  • Update outdated LICENSE year

    Update outdated LICENSE year

    With this update, you won't care about any further license year updates

    Using present instead of the second year is a common pattern, here are some examples

    https://github.com/babel/babel/blob/4fb29a372b18e82ba72262db43b80b220a5cce01/LICENSE#L3 https://github.com/reduxjs/redux/blob/8ad084251a5b3e4617157fc52795b6284e68bc1e/LICENSE.md?plain=1#L3 https://github.com/pmndrs/react-spring/blob/e7d423cde197db9d53a00f96422c6d7f8ce12b29/LICENSE#L3 https://github.com/vercel/styled-jsx/blob/e8245813f9c3e633a9b2d2414fb11e6386b31216/license.md?plain=1#L3 https://github.com/styled-components/styled-components/blob/09929bd9bc05da085206c94679f07597b46212e4/LICENSE#L3

    opened by Serjobas 0
  • Disable Crawling External JS such as Adsense and Analytics

    Disable Crawling External JS such as Adsense and Analytics

    Bug Report

    Current Behavior this library downloading external js such as adsense and google analytics, it always throw failure 403. and adsense never allow downloading the adsbygoogle.js

    opened by dimaslanjaka 0
Owner
Follow me at https://twitter.com/stereobooster
null
Mobile App Framework powered by React

TouchstoneJS Mobile App Framework powered by React. See the demo at touchstonejs.io. Follow @touchstonejs on Twitter for updates. See the touchstone-s

TouchstoneJS 3.3k Jan 5, 2023
Maple.js is a React webcomponents based framework mixing ES6 with Custom Elements, HTML Imports and Shadow DOM. It has in-built support for SASS and JSX, including a Gulp task for vulcanizing your project.

Heroku: http://maple-app.herokuapp.com/ npm: npm install maple.js Bower: bower install maple.js Maple is a seamless module that allows you to organise

Adam Timberlake 430 Dec 23, 2022
A completely customizable framework for building rich text editors. (Currently in beta.)

A completely customizable framework for building rich text editors. Why? · Principles · Demo · Examples · Documentation · Contributing! Slate lets you

Ian Storm Taylor 26.2k Jan 9, 2023
A React framework for building text editors.

Draft.js Draft.js is a JavaScript rich text editor framework, built for React and backed by an immutable model. Extensible and Customizable: We provid

Facebook 22.3k Dec 31, 2022
Demo app for refine.dev integration, a react-based framework for rapid building of internal tools.

Demo app for refine.dev integration, a react-based framework for rapid building of internal tools.

Permify 7 Apr 28, 2022
A frontend framework for building admin SPAs on top of REST services, using React and Material Design.

admin-on-rest A frontend Framework for building admin applications running in the browser on top of REST services, using ES6, React and Material Desig

marmelab 399 Dec 21, 2022
Create and build modern JavaScript projects with zero initial configuration.

Create and build modern JavaScript applications with zero initial configuration Neutrino combines the power of webpack with the simplicity of presets.

Neutrino 3.9k Jan 6, 2023
Beautiful, Zero Configuration, Toast Messages for React. Only ~ 4kb gzip, with styles and icons

Cogo Toast Beautiful, Zero Configuration, Toast Messages for React ~4kb gzip (with styles and icons) https://cogoport.github.io/cogo-toast/ Install vi

Cogoport 669 Dec 29, 2022
Zero-Configuration Reactive forms for Svelte

Formula + Beaker Δ→ Reactive Forms for Svelte Documentation Changelog svelte-formula is a Library for use with Svelte that super-charges your ability

Tane Piper 119 Dec 27, 2022
Parcel is a zero configuration build tool for the web📦🚀

Parcel is a zero configuration build tool for the web. It combines a great out-of-the-box development experience with a scalable architecture that can take your project from just getting started to massive production application.

Parcel 41.8k Jan 9, 2023
Enjoy React, Redux, and React-Router, with zero build configuration.

react-redux-starter-kit This is yet another single page web application template using React. However, this project attempts to balance simplicity wit

cloudmu 352 Nov 29, 2022
Zero configuration Preact widgets renderer in any host DOM

Preact Habitat A 900 Bytes module for that will make plugging in Preact components and widgets in any CMS or website as fun as lego! Demos Login Widge

Zouhir ⚡️ 496 Dec 5, 2022
A template to create a React Library. Zero configuration, just use!

React lib template ?? A simple React lib template based on Parcel and Jest. Usage use this template for your next React lib, modify it and run npm run

Raí Siqueira 15 Aug 22, 2022
Framework-agnostic CSS-in-JS with support for server-side rendering, browser prefixing, and minimum CSS generation

Aphrodite Framework-agnostic CSS-in-JS with support for server-side rendering, browser prefixing, and minimum CSS generation. Support for colocating y

Khan Academy 5.3k Jan 1, 2023
Framework-agnostic CSS-in-JS with support for server-side rendering, browser prefixing, and minimum CSS generation

Aphrodite Framework-agnostic CSS-in-JS with support for server-side rendering, browser prefixing, and minimum CSS generation. Support for colocating y

Khan Academy 5.3k Jan 1, 2023
Easy to use horizontal percentage bar framework-agnostic web component

ui-percentage-bar A lightweight, simple-to-use horizontal bar graph web component. Pass in the data array, with the value number and color of your cho

Nille 0 Dec 19, 2021
A framework-agnostic page transition lib for react. Tested with CRA, Next.js, Gatsby.js

A framework-agnostic page transition lib for react. Tested with CRA, Next.js, Gatsby.js

14islands 4 Sep 16, 2022
Because your state management code should be domain-agnostic.

Because your state management code should be domain-agnostic.

Zachary DeRose 12 Nov 19, 2022
A dApp, blockchain and crypto agnostic React UI toolkit

A dApp, blockchain and crypto agnostic React UI kit ?? ⚠️ Wet paint, you shall not use adoption on production for now. ?? Painter? Please consider joi

Paul Fasola 11 Jan 8, 2023
A purpose-agnostic step sequencer implementation

generic-step-sequencer A purpose-agnostic step sequencer implementation Installation $ yarn add generic-step-sequencer Usage see https://github.com/y

youpy 8 Jul 30, 2022