Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
react-snapshot
Advanced tools
A zero-configuration static pre-renderer for React apps, built for Create React App (because it's great)
A zero-configuration static pre-renderer for React apps, built for Create React App (because it's great)
Server-side rendering is a big feature of React, but for most apps it can be more trouble than its worth. You have to choose between serving your users a blank page until the JS loads, or set up the infrastructure required to generate HTML on a server—suddenly your application code needs to be aware that some of the time browser APIs will be available and other times it's NodeJS & you need to start describing more precisely which routes load which data. Either you optimise for Developer Experience (DX) or User Experience (UX), which is a bad tradeoff to be making.
Thankfully, the same mechanics that make React work as a static HTML page rendered by a server lets us do something much simpler—rather than rendering HTML dynamically on a server, render it ahead of time during the build & deployment phase. Then, take these static HTML snapshots and host them anywhere, no server required.
This is a project to do that. Automatically, without any configuration, and only a few tiny changes to your application code.
The snapshots still have the normal JS bundle included, so once that downloads the site will function exactly as before (i.e. instantaneous page transitions), but you serve real, functional HTML & CSS as soon as possible. It's good for SEO (yes Google crawls SPAs now but they still reward perf and this perfs like a banshee), it's good if your JS is broken or something render-blocking has a network fail, it's good for accessibility, it's good for Slackbot or Facebook to read your opengraph tags, it's just good.
npm i -D react-snapshot@next
(for v2)"scripts"
from- "build": "react-scripts build"
+ "build": "react-scripts build && react-snapshot"
react-dom
:- import ReactDOM from 'react-dom';
+ import { render } from 'react-snapshot';
- ReactDOM.render(
+ render(
<App/>,
document.getElementById('root')
);
For a static site, that's it! During build
, react-snapshot will load up your site using JSDOM, crawl it to find all the pages, render each, calculate the React checksum to minimise work on the client, and save the files out to be served by something like surge.sh.
If a route has to fetch data from somewhere, you need to tell react-snapshot about it. But thankfully, that's as easy as:
+ import { snapshot } from 'react-snapshot'
class Home extends React.Component {
state = { quotes: null }
componentWillMount() {
+ snapshot(() => (
fetch('/api/quotes')
.then(response => response.json())
+ ))
.then(quotes => {
this.setState({ quotes })
})
}
render() {
return this.state
return (
<div className="Quotes">
{
quotes && quotes.map((quote, i) => <Quote key={i} quote={quote}/>)
}
</div>
)
}
}
Wrap any async process you want to track in a snapshot
call and it'll be tracked. During deployment, the fetch is performed, the return value is stored & sent as JSON in the HTML snapshot. When the app gets booted on the client, that same snapshot method short-circuits, immediately calling the .then and the state gets populated before the render method is called. This means there's no flash, the checksum matches, and everything is JUST GREAT™.
*Note: you have to use componentWillMount
instead of componentDidMount
, since the latter runs after the render method, and you'll get a flash.
Since this pattern is quite common, there's also the Snapshot
higher-order component that lets you treat async dependencies as props:
const Home = ({ quotes }) => (
<div className="Quotes">
{
quotes && quotes.map((quote, i) => <Quote key={i} quote={quote}/>)
}
</div>
)
export default Snapshot({
quotes: () => fetch('/api/quotes').then(resp => resp.json())
}).rendering(Home)
You can specify additional paths as entry points for crawling that would otherwise not be found. It's also possible to exclude particular paths from crawling. Simply add a section called "reactSnapshot"
to your package.json.
"reactSnapshot": {
"include": [
"/other-path",
"/another/nested-path"
],
"exclude": [
"/signup",
"/other-path/exclude-me/**"
],
"snapshotDelay": 300
}
Note that exclude can be passed a glob, but include cannot.
The default snapshot delay is 50ms, and this can be changed to suit your app's requirements.
Check out create-react-app-snapshot.surge.sh for a live version or geelen/create-react-app-snapshot for how it was built, starting from create-react-app's awesome baseline. No ejecting necessary, either.
The diff from the original create-react-app code might be enlightening to you as well.
This should work for simple cases. For less simple cases, go with:
MIT
FAQs
A zero-configuration static pre-renderer for React apps. Starting by targeting Create React App (because it's great)
We found that react-snapshot demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.