GithubHelp home page GithubHelp logo

stereobooster / react-snap Goto Github PK

View Code? Open in Web Editor NEW
5.0K 22.0 388.0 1.44 MB

๐Ÿ‘ป Zero-configuration framework-agnostic static prerendering for SPAs

License: MIT License

JavaScript 92.04% HTML 7.58% CSS 0.38%
zero-configuration prerender ssr seo static-site-generator react vue server-side-rendering

react-snap's Introduction

Stand With Ukraine

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.

react-snap's People

Contributors

badsyntax avatar danielruf avatar danilobuerger avatar derappelt avatar diligiant avatar evenchange4 avatar f2acode avatar g-div avatar hugmanrique avatar justin808 avatar kjkta avatar lemmih avatar louisjc avatar mrpeker avatar nicolas-t avatar onionhammer avatar openjck avatar piotr-cz avatar pushred avatar renovate-bot avatar renovate[bot] avatar sjsyrek avatar stanko avatar stereobooster avatar strobox avatar tbroadley avatar thekashey avatar tmartin2089 avatar tsantef avatar yhuard avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-snap's Issues

error TS2304: Cannot find name 'Page'

yarn tsc
$ tsc -p .
index.js(65,19): error TS2304: Cannot find name 'Page'.
index.js(136,19): error TS2304: Cannot find name 'Page'.
index.js(207,54): error TS6133: 'route' is declared but its value is never read.
index.js(222,38): error TS6133: 'options' is declared but its value is never read.
src/puppeteer_utils.js(8,19): error TS2304: Cannot find name 'Page'.
src/puppeteer_utils.js(25,19): error TS2304: Cannot find name 'Page'.
src/puppeteer_utils.js(55,19): error TS2304: Cannot find name 'Page'.
src/puppeteer_utils.js(73,75): error TS2304: Cannot find name 'Page'.
src/puppeteer_utils.js(73,139): error TS2304: Cannot find name 'Page'.

related puppeteer/puppeteer#1170

[RFC] Some improvements and breaking changes

path/index.html vs path.html

  • done/not done

From the ticket #22. I do not see any sense to generate path.html for /path route instead of path/index.html. This convention was copied from react-snapshot.
After the change react-snap will generate path/index.html for both: /path and /path/

Preload resources

  • done/not done

As of now, this config does two things:

  • stores JSON in window.snapStore[<path>]
  • create preload instructions for images (<link rel="preload" as="image">)

Need to fix two things:

webpack 2+ code splitting hack

  • done/not done

There is a hack to make webpack code splitting work. Because we assume usage with c-r-a it should be enabled by default. But before enabling it by default need to fix it - use <link rel="preload" instead of script tags

404 page

  • auto 404
  • warnings for 404

As of now react-snap by default generates 404 page, which I consider a good practice, but it actually doesn't make sense to generate 404 if you do not use routing (like react-route or similar), I mean if you have only one page.

So I consider changing this behavior and generate 404 page if there is more than one page discovered by the crawler or listed in include.

Another thing that I was wondering is how to detect that 404.html is actually a "not found page". How to make sure programmer didn't forget to handle this case?
The only option I came up is: check if the title of the page contains the string "404". It can be in any position. Also, the nice benefit is that it will possible to track that no other page is "404".

Proper exit status for errors

  • done/not done
  • support errors in minimalcss moved to separate ticket

Check if target directory contains 200.html, and if it does fail with an error message and non-zero exit code.

Also, exit with non-zero exit code if any error occurred during generation and stop generation. As of now react-snap reports error in console, but continues to generate pages.

react-snap exits with status code 1 but no reason why

Reproducible example at https://github.com/govau/cloud.gov.au/tree/master/www/ui

Run yarn build && yarn build-2-TODO and you'll see the command fails but with no reason why:

$ yarn build && yarn build-2-TODO
yarn run v1.3.2
$ react-scripts-ts build
Creating an optimized production build...
No valid rules have been specified
ts-loader: Using [email protected] and /Users/Jonathan/go/src/github.com/govau/cloud.gov.au/www/ui/tsconfig.json
Compiled successfully.

File sizes after gzip:

  101 KB    build/static/js/0.1664397f.chunk.js
  73.24 KB  build/static/js/main.fb89c8e0.js
  1.2 KB    build/static/js/1.1f44138b.chunk.js
  291 B     build/static/js/3.c54b25e2.chunk.js
  288 B     build/static/js/2.a77791b7.chunk.js
  226 B     build/static/css/main.688a7215.css

The project was built assuming it is hosted at the server root.
To override this, specify the homepage in your package.json.
For example, add this to build it for GitHub Pages:

  "homepage" : "http://myname.github.io/myapp",

The build folder is ready to be deployed.
You may serve it with a static server:

  yarn global add serve
  serve -s build

โœจ  Done in 18.99s.
yarn run v1.3.2
$ react-snap
๐Ÿ•ธ  (1/4) /
๐Ÿ•ธ  (2/4) /404.html
๐Ÿ•ธ  (3/4) /about/
๐Ÿ•ธ  (4/4) /insights/
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Any ideas?

Inline-CSS option Error: Unable to querySelector

Using CRA if I add the following style link to my index.html in my public folder:
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.11/semantic.min.css" >

i also tried: <link rel="stylesheet" href="%PUBLIC_URL%/semantic.min.css">

And then I added the "inlineCss": true I get the error:

Error: Evaluation failed: Error: Unable to querySelector('.ui.labels a.active.label:ActiveHover:before') [SyntaxError: Failed to execute 'querySelector' on 'Document': '.ui.labels a.active.label:ActiveHover:before' is not a valid selector.]
    at objsCleaned.(anonymous function).selector (<anonymous>:153:21)
    at values.filter.selectorString (<anonymous>:75:30)
    at Array.filter (<anonymous>)
    at children.filter.child (<anonymous>:71:41)
    at Array.filter (<anonymous>)
    at clean (<anonymous>:68:27)
    at cleaner (<anonymous>:105:24)
    at links.filter.forEach.stylesheet (<anonymous>:129:42)
    at Array.forEach (<anonymous>)
    at stylesheetAstObjects (<anonymous>:124:10)

How to handle sourcemaps with puppeteer?

JS error looks like:

 Error: TypeError: Cannot read property 'resize' of undefined
    at e.resize (http://localhost:45678/static/js/main.91ecf917.js:1:478812)
    at new e (http://localhost:45678/static/js/main.91ecf917.js:1:476478)
    at n.componentDidMount (http://localhost:45678/static/js/main.91ecf917.js:1:734681)
    at commitLifeCycles (http://localhost:45678/static/js/main.91ecf917.js:1:832876)
    at n (http://localhost:45678/static/js/main.91ecf917.js:1:836981)
    at u (http://localhost:45678/static/js/main.91ecf917.js:1:838648)
    at c (http://localhost:45678/static/js/main.91ecf917.js:1:839091)
    at m (http://localhost:45678/static/js/main.91ecf917.js:1:841114)
    at d (http://localhost:45678/static/js/main.91ecf917.js:1:840623)
    at Object.updateContainer (http://localhost:45678/static/js/main.91ecf917.js:1:907103)

Options:

Related:

Showcase

If you use project and especially experimental features, like inlineCss or preloadResources. Drop by to say how it goes. It would be nice if you show webpagetest.org report before and after.

Add flag to Chromium command

Hiya,

The server environment I'm deploying to has security restrictions on running Chromium, so in order for react-snap to run correctly I'll need to add the --no-sandbox flag to Chromium when it runs. How would I go a bout doing that? Cheers.

using it with redux-persist

I was using React-snapshot was I am unable to use it with redux-persist because the following code which renders main app only after the redux store has been re-hydrated using redux-persist:

import {render as snapshotRender} from 'react-snapshot'
import {ConnectedRouter} from 'react-router-redux'

async function init() {
const store = await configureStore()
snapshotRender(
  <Provider store={store}>
    {/* ConnectedRouter will use the store from Provider automatically */}
    <ConnectedRouter history={history}>
      <App />
    </ConnectedRouter>
  </Provider>,
  document.getElementById('root')
)
}

registerServiceWorker()
init()

I get the error that react-snapshot render was never called. Will this lib work within async function like above ?

saveAs option should accept empty string

For now, option "saveAs" only accept some file extension, but for dynamic router, only file without extension will work.

I have to manually remove extension like this:

for file in *.html; do mv $file ${file%.html}; done

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"

Generate HTTP2 push manifest

When headless chrome generates page, it can track order of load of resources and generate http2 hints to do http2 push.

Example (waterfall diagram):

index.html
  main.css
  main.js
    data.json

So we can instruct server to do http2 push for main.css, main.js and data.json

Static hosting that does not support custom headers:

CDN providers that support headers:

See also:

How to handle images(question)

this is not a bug, rather a question.
I am using some img tags with images with image loading like so:
import four from 'media/images/landingPage/four.png'

but in the static html the images seem broken. even my placeholder src is not rendering in the static page.

SO my question is how do I handle images with the lib?

Properly handle errors in minimalcss

Example:

๐Ÿ”ฅ  /shell.html pageerror: Error: DOMException: Failed to execute 'createElement' on 'Document': The tag name provided ('[object Object]') is not a valid name.
    at createElement (../node_modules/preact/dist/preact.esm.js:183:0)
    at createNode (../node_modules/preact/dist/preact.esm.js:364:0)
    at idiff (../node_modules/preact/dist/preact.esm.js:306:0)
    at diff (../node_modules/preact/dist/preact.esm.js:949:0)
    at vnode (../node_modules/preact-compat/dist/preact-compat.es.js:149:0)
    at __WEBPACK_IMPORTED_MODULE_0_react__ (index.js:30:7)
    at call (../webpack/bootstrap 3d46b713f8f74ea5ecff:49:0)
    at __webpack_require__ (../static/js/main.6fe07f11.js:3020:17)
    at call (../webpack/bootstrap 3d46b713f8f74ea5ecff:49:0)
    at http://localhost:45678/static/js/main.6fe07f11.js:1:1387
(node:17059) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: DOMException: Failed to execute 'createElement' on 'Document': The tag name provided ('[object Object]') is not a valid name.
    at p (http://localhost:45678/static/js/main.6fe07f11.js:1:54860)
    at g (http://localhost:45678/static/js/main.6fe07f11.js:1:56858)
    at b (http://localhost:45678/static/js/main.6fe07f11.js:1:56327)
    at L (http://localhost:45678/static/js/main.6fe07f11.js:1:61366)
    at a (http://localhost:45678/static/js/main.6fe07f11.js:1:2078)
    at Object.<anonymous> (http://localhost:45678/static/js/main.6fe07f11.js:1:50384)
    at e (http://localhost:45678/static/js/main.6fe07f11.js:1:101)
    at Object.<anonymous> (http://localhost:45678/static/js/main.6fe07f11.js:1:39516)
    at e (http://localhost:45678/static/js/main.6fe07f11.js:1:101)
    at http://localhost:45678/static/js/main.6fe07f11.js:1:1387
(node:17059) [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.
๐Ÿ•ธ  (1/1) /shell.html
error Command failed with exit code 1.

๐Ÿ”ฅ /shell.html... - this is page error handled by react-snap
(node:17059) UnhandledPromiseRejectionWarning:.. this is the same error unhandled from minimalcss

Extracted from #36

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.

pageerror: Error: SyntaxError: Unexpected token <

Hi, i always get this error, no matter how i change html or the homepage field in the package.json. Thank you in advance for your help

๐Ÿ”ฅ / pageerror: Error: SyntaxError: Unexpected token < at Page._handleException (/Users/Chevalier/projects/lola-client-landing-react/node_modules/puppeteer/lib/Page.js:295:38) at Session.Page.client.on.exception (/Users/Chevalier/projects/lola-client-landing-react/node_modules/puppeteer/lib/Page.js:86:60) at emitOne (events.js:115:13) at Session.emit (events.js:210:7) at Session._onMessage (/Users/Chevalier/projects/lola-client-landing-react/node_modules/puppeteer/lib/Connection.js:199:12) at Connection._onMessage (/Users/Chevalier/projects/lola-client-landing-react/node_modules/puppeteer/lib/Connection.js:98:19) at emitOne (events.js:115:13) at WebSocket.emit (events.js:210:7) at Receiver._receiver.onmessage (/Users/Chevalier/projects/lola-client-landing-react/node_modules/ws/lib/WebSocket.js:143:47) at Receiver.dataMessage (/Users/Chevalier/projects/lola-client-landing-react/node_modules/ws/lib/Receiver.js:389:14) ๐Ÿ•ธ (1/1) /

index.html

html2

package.json
json

Build error with css link tag

I am usinginlineCss: true option

and and in my index.html i have a link tag:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.12/semantic.min.css">
I keep getting this error at build:

Error: Evaluation failed: Error: https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.12/semantic.min.css
not in stylesheetAstObjects!
 at links.filter.forEach.stylesheet (<anonymous>:126:21)
 at Array.forEach (<anonymous>)
 at <anonymous>:124:12

Question about react-native-web

Hello!

I don't really want to file a bug or anything, I was just wondering if you have tested this with react-native-web.

I've been working on a project where we have some universal components that we created using react-native-web, so in order to render the application I have to do something like:

const ComponentInst = (
  <RootAppComponent
    store={store}
    persistor={persistor}
    history={history}
  />
);

if (rootEl.hasChildNodes()) {
  ReactNative.hydrate(ComponentInst, rootEl);
} else {
  ReactNative.render(ComponentInst, rootEl);
}

At the beginning of the project we set up the configuration and everything seemed good, the development workflow and the building were working as expected, although we didn't have much content to test it on. The whole time while in development we haven't had any problems with the whole setup, we've been using react-native-web and styled-components.

Now we have deployed an early version of the app and when we built the application we noticed that some stuff wasn't being rendered correctly. I can't really find differences in the generated css, but for some elements the computed styles in the inspector are just different. For example some container elements lost their height.

I know in the react-native-web documentation they use the react-native to do the server side rendering, so maybe what I'm trying to do is not reasonable.

I could get rid of react-snap to "fix" this and maybe later on just do traditional server side rendering as per their docs but it would be really convenient to fix this keeping this approach because we also want to deploy using S3 and CloudFront.

So maybe is there a way to integrate this? Could you point me in the right direction or just tell me if it's not possible, it would save me some time.

Thanks for reading this!

[css-in-js] Google fonts broken

Hey, awesome library here. Excited to see someone improve upon react-snapshot! Moving off of JSDOM, working w/ react-loadable, adding critical css... all awesome! Thanks for your work on this.

Anyways, I appear to have an issue:

I have the following lines in my index.html file to use a google font.

<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600,700" rel="stylesheet">

After running through react-snap, I'm getting:

<style data-href="https://fonts.googleapis.com/css?family=Open+Sans:400,600,700" media="@media{a{top:0}}">@font-face{font-family:'Open Sans';font-style:normal;font-weight:400;src:local('Open Sans Regular'),local('OpenSans-Regular'),url(https://fonts.gstatic.com/s/opensans/v15/cJZKeOuBrn4kERxqtaUH3aCWcynf_cDxXwCLxiixG1c.ttf) format('truetype')}@font-face{font-family:'Open Sans';font-style:normal;font-weight:600;src:local('Open Sans SemiBold'),local('OpenSans-SemiBold'),url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNSonF5uFdDttMLvmWuJdhhgs.ttf) format('truetype')}@font-face{font-family:'Open Sans';font-style:normal;font-weight:700;src:local('Open Sans Bold'),local('OpenSans-Bold'),url(https://fonts.gstatic.com/s/opensans/v15/k3k702ZOKiLJc3WVjuplzInF5uFdDttMLvmWuJdhhgs.ttf) format('truetype')}</style>

The generated media="@media{a{top:0}}" prevents the font from applying to anything. Removing the media tag manually resolves the issue.

Any idea on how to resolve this? Is there config that can be done?

Error when building with create-react-app

Hello,

I've cloned the example repository which was created with create-react-app: https://github.com/badsyntax/react-snap-example.
I installed react-snap using npm install react-snap --save-dev.
In the package.json, I also changed "build": "react-scripts build" to "build": "react-scripts build && react-snap",. In my command line I ran npm run build, and got the following error:

/Users/Ludo/Documents/sites/react/react-snap-example/node_modules/react-snap/index.js:45
    ...defaultOptions,
    ^^^
SyntaxError: Unexpected token ...
    at createScript (vm.js:56:10)
    at Object.runInThisContext (vm.js:97:10)
    at Module._compile (module.js:542:28)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:393:7)
    at startup (bootstrap_node.js:150:9)

npm ERR! Darwin 15.6.0
npm ERR! argv "/usr/local/bin/node" "/usr/local/bin/npm" "run" "build"
npm ERR! node v6.10.2
npm ERR! npm  v3.10.10
npm ERR! code ELIFECYCLE
npm ERR! [email protected] build: `react-scripts build && node ./node_modules/react-snap`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] build script 'react-scripts build && node ./node_modules/react-snap'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the react-snap-example package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     react-scripts build && node ./node_modules/react-snap
npm ERR! You can get information on how to open an issue for this project with:
npm ERR!     npm bugs react-snap-example
npm ERR! Or if that isn't available, you can get their info via:
npm ERR!     npm owner ls react-snap-example
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     /Users/Ludo/Documents/sites/react/react-snap-example/npm-debug.log

npm ERR! Darwin 15.6.0
npm ERR! argv "/usr/local/bin/node" "/usr/local/bin/npm" "run" "snap"
npm ERR! node v6.10.2
npm ERR! npm  v3.10.10
npm ERR! code ELIFECYCLE
npm ERR! [email protected] snap: `npm run build && node ./node_modules/react-snap`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] snap script 'npm run build && node ./node_modules/react-snap'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the react-snap-example package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     npm run build && node ./node_modules/react-snap
npm ERR! You can get information on how to open an issue for this project with:
npm ERR!     npm bugs react-snap-example
npm ERR! Or if that isn't available, you can get their info via:
npm ERR!     npm owner ls react-snap-example
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     /Users/Ludo/Documents/sites/react/react-snap-example/npm-debug.log

when I changed "build": "react-scripts build && react-snap" to "build": "react-scripts build && node ./node_modules/react-snap", I got the same error, and when I ran npm run snap like in the tutorial aswell.

Am I doing something wrong?

Ludo

Idea: create diagnostic tool

create diagnostic tool which will give recommendations based on package.json. For example, if package.json contains loadable-components recommend config to prevent flash etc. Basically check everything from caveats section.

Like brew doctor

code splitting messes up the snapshots

I tried react-snap on a code-splitted create-react-app project (using react-loadable but that's not the issue). Once deployed, the browser started to complain as it didn't know what to do with

<link type="text/css" rel="stylesheet" href="blob:http://localhost:45678/fd887ea6-961a-4721-8a91-a7a08223b642">

The explanation is just above style-loader#useable : If sourcemaps are not turned off (which gaearon usually advices against style-loader fetches the splitted styles this way.

Sitemap

I would like to know if is there any option to include a sitemap or a list of path for include?

Implement `noscript` fallback for loadCss trick

// TODO: this doesn't work
var wrap = document.createElement('div');
wrap.appendChild(link.cloneNode(false));
var noscriptTag = document.createElement('noscript');
noscriptTag.innerHTML = wrap.innerHTML;
document.head.appendChild(noscriptTag);

screenshots / ignores source directory and uses the destination directory as source directory

screenshots.js:

#!/usr/bin/env node
const { run } = require("react-snap");

run({
  source: "build",
  destination: "build/screenshots",
  saveAs: "png"
});

Error:

$ yarn screenshots
yarn run v1.2.1
$ scripts/screenshots.js
events.js:182
      throw er; // Unhandled 'error' event
      ^

Error: ENOENT: no such file or directory, open '/TST/react16/build/screenshots/index.html'
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

index.html exists in /TST/react16/build/ and there is no problem if destination is set to destination: "build"

Don't cache file#hash.html

Caching both file#hash1.html and file#hash2.html doesn't seem to make sense. Shouldn't it only cache file.html in that case?

pre-renderer root page

It looks like react-snap it pre-rendering everything but the root page. Can we opt-in to pre-render it?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.