前端框架选型是企业提升开发效率与用户体验的关键因素
862
2022-11-01
为“create-react-app”程序创建静态HTML快照,以改善初始页面加载时间
snapshotify
Creates a static HTML snapshot for your create-react-app app, to improve initial page load times. Makes for blazing fast load times, and improves SEO.
Work in progress: This module is under development. Many features that you'd need for production use aren't implemented yet. However, you are encouraged to give this module a try to get a sense of the OMG speed. Feedback and contributions welcome!
Inspired by react-snapshot and react-snap. This module obsesses over the performance of your built app.
Usage
Install using npm:
npm install snapshotify
Modify the scripts in your package.json to add a "postbuild" key:
{ ... "scripts": { ... "postbuild": "snapshotify" ... }}
Then, modify your index.js to wait before hydration:
import React from 'react';import { hydrate, render } from 'react-dom';import loadScripts from 'snapshotify';import App from './App';const rootElement = document.getElementById('root');if (rootElement.hasChildNodes()) { loadScripts().then(() => hydrate(
Build your app as usual:
npm run build
What it achieves
Blazing fast load speed for your app.Better SEO, at least for crawlers that don't execute JS.
What it does
Starts a temporary web server using express to serve your built create-react-app app.Uses puppeteer to launch a headless browser to render your app.Extracts the minimum CSS needed to render your app, using postcss to parse the CSS into an AST. Rejects CSS rules for DOM nodes that aren't in your page.Preserves rules like @font-face.Preserves pseudo-selectors like ::before or :hover for nodes that are on page.Preserves media queries, but again rejects rules for DOM nodes that aren't in the page.Only retains keyframe animations for animations you are using on the page. Minifies the resulting minimal CSS using CSSO. Embeds this into the markup of your HTML directly as an inline style tag.Identifies the minimal fonts needed for the first render of the page, and preloads them using .Removes all external script tags (typically your main.hash.js), and includes them instead as .Identifies the chunks needed for the render of the page, and preloads them too. This downloads all the needed scripts in parallel. (Usually, requests for chunks are only issued after the main script has loaded, which makes it sequential.)Adds an inline script loader to inject your main script file asynchronously and after page load, so that page load is not held up.Removes all external stylesheets, and adds them as instead. After page load, a CSS loader injected in the page adds the external CSS files. A fallback is also added, for browsers that don't support JS, so that styles don't appear broken for non-JS browsers.If the page contains a CSP meta tag , hashes are added to your script-src and style-src directives, to allow the added inline scripts and styles.Uses html-minifier to minify the whole resulting HTML, making several micro-optimisations.Recursively crawls any links you have (useful if you're using client-side routing like with react-router), and optimises those pages too.Writes all the built pre-rendered html files to your build folder, ready for mounting directly to a web-server like nginx.
As a result of the optimisations above, the page load time is drastically improved. Only the markup, fonts (if any), and images (if any) are actually needed for page load. External script files (typically your main.js) and external CSS files (index.css) are not injected into the page until after page load, so that they do not contribute to the page load time. Even so, the script files, all of the needed code-split chunks, external CSS files and fonts are donwloaded as soon as possible, and all in parallel, so that your page's startup time is as quick as possible, and your JS starts up faster than usual.
Configuration
Specifying a config file
When invoking snapshotify, you can pass an additional parameter to specify your config file:
snapshotify --config snapshot.json
If you don't specify a --config, it defaults to snapshot.json. If the config file can't be found, defaults as specified below are used.
snapshot.json
The config file can have any of the following properties:
inlineCSS: (boolean, default true) Extracts the minimal CSS required for the initial render of the page, and inlines it as a style tag. You may want to disable this if the minimal CSS is already in the DOM as a style tag, which might be the case if you're using a CSS-in-JS lib that uses style tags.preloadScripts: (boolean, default true) Preloads your script file(s) using , and injects an inline script loader to execute your code only after script preloading is complete. If your initial render depends on one or more dynamically imported components, all the code-split chunks as preloaded as well. The combination of the preloading and the script loader ensures that you get to the window-onload event as soon as possible.preloadFonts: (boolean, default true) Identifies the fonts needed for the initial render of the page, and preloads them using a . Only preloads a woff2 font, since all browsers that support preloading also support (and prefer) a woff2 font.addCSPHashes: (boolean, default true) If your page has a CSP tag, setting this flag adds style-src and script-src hashes to the CSP policy, to allow the inline style and script tags added during the snapshot process. If the CSP meta tag isn't present, this rule has no effect. If any of the directives has 'unsafe-inline' already present, hashes aren't added.cspAlgo: (string, default sha256) The algorithm to be used for calculating the CSP hash. Possible values are sha256, sha384 or sha512. This property is only used if addCSPHashes is true.
The following properties are mostly only useful for debugging:
dryRun: (boolean, default false) Does a dry run. Doesn't write any files to the build directory. Just generates a report after processing your app.printConsoleLogs: (boolean, default false) Prints console.log lines from your app, as reported by puppeteer, to stdout.
Detecting snapshot
Sometimes, it may be necessary to detect if you are running in the snapshot mode, so that you can serve up alternative content. To enable this, a global window.SNAPSHOT variable is set to true when taking the snapshot.
Notes
Works great with CSS-in-JS libs. I've tried glamor.When checking performance improvements, it's useful to use network throtting in Chrome devtools.Async modules loaded using dynamic import(...) (say through react-loadable) are handled automatically. These modules are added to the page as
TODO
Handling routes that can't be crawled (like stuff behind a login form). Does not make sense to snapshot these routes, but at least load the index.html correctly for the first request. This is a v1 blocker.Explore options to eliminate flicker with async components.Figure out how to play nicely with ServiceWorkers.
License: MIT
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~