Performance improvements (#458)

* Performance improvements

- Use font-display: swap
- Preload CSS links
- Compress all request payloads

* inline react spinner css

* remove @zeit/next-css, move custom themes to static

* update contributing docs

* spinner styles

* move spinner back to top level

* load codemirror synchronously
main
Michael Fix 6 years ago committed by GitHub
parent 0d2f2f4444
commit a9b25e05a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -17,4 +17,4 @@ We're happy to accept any PRs adding new themes and languages to Carbon! Current
1. If the [theme](https://codemirror.net/demo/theme.html) or [language](https://codemirror.net/mode/index.html) is supported in Codemirror, all you have to do is add a [constant](https://github.com/dawnlabs/carbon/blob/master/lib/constants.js) for it.
2. If it's not supported, you can add a Codemirror compliant [custom file](https://github.com/dawnlabs/carbon/tree/master/lib/custom) to implement it and add a constant like above.
2. If it's not supported, you can add a Codemirror compliant [custom theme](https://github.com/dawnlabs/carbon/tree/master/static/themes) or [custom mode](https://github.com/dawnlabs/carbon/tree/master/lib/custom/modes) to implement it and add a constant like above.

@ -4,7 +4,6 @@ import ResizeObserver from 'resize-observer-polyfill'
import debounce from 'lodash.debounce'
import ms from 'ms'
import { Controlled as CodeMirror } from 'react-codemirror2'
import Spinner from 'react-spinner'
import WindowControls from '../components/WindowControls'
import Watermark from '../components/svg/Watermark'
@ -29,7 +28,6 @@ class Carbon extends PureComponent {
super(props)
this.state = {
loading: true,
language: props.config.language
}
@ -40,7 +38,6 @@ class Carbon extends PureComponent {
}
componentDidMount() {
this.setState({ loading: false })
this.setState(handleLanguageChange(this.props.children, this.props))
const ro = new ResizeObserver(entries => {
@ -90,21 +87,7 @@ class Carbon extends PureComponent {
(this.props.config.backgroundImage && this.props.config.backgroundImageSelection) ||
this.props.config.backgroundImage
let content = (
<div>
<Spinner />
<style jsx>
{`
div {
height: 352px;
}
`}
</style>
</div>
)
if (this.state.loading === false) {
content = (
const content = (
<div id="container">
{config.windowControls ? (
<WindowControls
@ -243,7 +226,6 @@ class Carbon extends PureComponent {
</style>
</div>
)
}
return (
<div id="section">

@ -4,6 +4,7 @@ import HTML5Backend from 'react-dnd-html5-backend'
import { DragDropContext } from 'react-dnd'
import domtoimage from 'dom-to-image'
import ReadFileDropContainer, { DATA_URL, TEXT } from 'dropperx'
import Spinner from 'react-spinner'
// Ours
import Button from './Button'
@ -26,7 +27,8 @@ import {
COLORS,
EXPORT_SIZES_HASH,
DEFAULT_CODE,
DEFAULT_SETTINGS
DEFAULT_SETTINGS,
DEFAULT_LANGUAGE
} from '../lib/constants'
import { serializeState } from '../lib/routing'
import { getState } from '../lib/util'
@ -43,6 +45,7 @@ class Editor extends React.Component {
super(props)
this.state = {
...DEFAULT_SETTINGS,
loading: true,
uploading: false,
code: props.content,
online: true
@ -70,6 +73,7 @@ class Editor extends React.Component {
this.setState({
...getState(localStorage),
...this.props.initialState,
loading: false,
online: Boolean(window && window.navigator && window.navigator.onLine)
})
@ -213,6 +217,20 @@ class Editor extends React.Component {
}
render() {
if (this.state.loading) {
return (
<div>
<Spinner />
<style jsx>
{`
div {
height: 160px;
}
`}
</style>
</div>
)
}
return (
<React.Fragment>
<div id="editor">
@ -227,7 +245,7 @@ class Editor extends React.Component {
LANGUAGE_NAME_HASH[this.state.language] ||
LANGUAGE_MIME_HASH[this.state.language] ||
LANGUAGE_MODE_HASH[this.state.language] ||
'auto'
DEFAULT_LANGUAGE
}
list={LANGUAGES}
onChange={this.updateLanguage}

@ -4,12 +4,11 @@ import Reset from './style/Reset'
import Font from './style/Font'
import Typography from './style/Typography'
import '../static/react-crop.css'
import '../static/react-spinner.css'
import '../lib/custom/themes/one-dark.css'
import '../lib/custom/themes/verminal.css'
import '../lib/custom/themes/night-owl.css'
import '../lib/custom/themes/nord.css'
const LOCAL_STYLESHEETS = ['one-dark', 'verminal', 'night-owl', 'nord']
const CDN_STYLESHEETS = THEMES.filter(
t => t.hasStylesheet !== false && LOCAL_STYLESHEETS.indexOf(t.id) < 0
)
export default () => {
const onBrowser = typeof window !== 'undefined'
@ -38,24 +37,44 @@ export default () => {
<title>Carbon</title>
<link rel="manifest" href="/static/manifest.json" />
<link rel="shortcut icon" href="/static/favicon.ico" />
<link rel="stylesheet" href="/_next/static/style.css" />
<link
rel="preload"
as="style"
onLoad="this.onload=null;this.rel='stylesheet'"
href="/static/react-crop.css"
/>
<link
rel="stylesheet"
href="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.26.0/codemirror.min.css"
/>
<link
rel="stylesheet"
rel="preload"
as="style"
onLoad="this.onload=null;this.rel='stylesheet'"
href="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.30.0/theme/solarized.min.css"
/>
<link
rel="stylesheet"
rel="preload"
as="style"
onLoad="this.onload=null;this.rel='stylesheet'"
href="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.36.0/theme/seti.min.css"
/>
{LOCAL_STYLESHEETS.map(id => (
<link
key={id}
rel="preload"
as="style"
onLoad="this.onload=null;this.rel='stylesheet'"
href={`/static/themes/${id}.css`}
/>
))}
{onBrowser
? THEMES.filter(t => t.hasStylesheet !== false).map(theme => (
? CDN_STYLESHEETS.map(theme => (
<link
key={theme.id}
rel="stylesheet"
rel="preload"
as="style"
onLoad="this.onload=null;this.rel='stylesheet'"
href={
theme.link ||
`//cdnjs.cloudflare.com/ajax/libs/codemirror/5.36.0/theme/${theme.id}.min.css`

@ -1,8 +1,14 @@
/*
* See https://developers.google.com/web/updates/2016/02/font-display and
* https://css-tricks.com/font-display-masses/#article-header-id-2
* for `font-display` information
*/
export default () => (
<style jsx global>
{`
@font-face {
font-family: 'Iosevka';
font-display: swap;
src: url('//cdn.jsdelivr.net/npm/@typopro/web-iosevka@3.7.5/TypoPRO-iosevka-term-bold.woff')
format('woff');
font-weight: 400;
@ -11,6 +17,7 @@ export default () => (
@font-face {
font-family: 'Monoid';
font-display: swap;
src: url('//cdn.jsdelivr.net/npm/@typopro/web-monoid@3.7.5/TypoPRO-Monoid-Regular.woff')
format('woff2'),
url('//cdn.jsdelivr.net/npm/@typopro/web-monoid@3.7.5/TypoPRO-Monoid-Regular.woff')
@ -21,6 +28,7 @@ export default () => (
@font-face {
font-family: 'Fantasque Sans Mono';
font-display: swap;
src: url('//cdn.jsdelivr.net/npm/@typopro/web-fantasque-sans-mono@3.7.5/TypoPRO-FantasqueSansMono-Regular.woff')
format('woff2'),
url('//cdn.jsdelivr.net/npm/@typopro/web-fantasque-sans-mono@3.7.5/TypoPRO-FantasqueSansMono-Regular.woff')
@ -31,6 +39,7 @@ export default () => (
@font-face {
font-family: 'Hack';
font-display: swap;
src: url('//cdn.jsdelivr.net/font-hack/2.020/fonts/woff2/hack-regular-webfont.woff2?v=2.020')
format('woff2'),
url('//cdn.jsdelivr.net/font-hack/2.020/fonts/woff/hack-regular-webfont.woff?v=2.020')
@ -41,6 +50,7 @@ export default () => (
@font-face {
font-family: 'Fira Code';
font-display: swap;
src: url('//cdn.rawgit.com/tonsky/FiraCode/1.204/distr/woff2/FiraCode-Regular.woff2')
format('woff2'),
url('//cdn.rawgit.com/tonsky/FiraCode/1.204/distr/woff/FiraCode-Regular.woff')
@ -52,6 +62,7 @@ export default () => (
/* latin */
@font-face {
font-family: 'IBM Plex Mono';
font-display: swap;
font-style: italic;
font-weight: 500;
src: local('IBM Plex Mono Medium Italic'), local('IBMPlexMono-MediumItalic'),
@ -65,6 +76,7 @@ export default () => (
/* latin */
@font-face {
font-family: 'Anonymous Pro';
font-display: swap;
font-style: normal;
font-weight: 400;
src: local('Anonymous Pro Regular'), local('AnonymousPro-Regular'),
@ -77,6 +89,7 @@ export default () => (
/* latin */
@font-face {
font-family: 'Droid Sans Mono';
font-display: swap;
font-style: normal;
font-weight: 400;
src: local('Droid Sans Mono Regular'), local('DroidSansMono-Regular'),
@ -89,6 +102,7 @@ export default () => (
/* latin */
@font-face {
font-family: 'Inconsolata';
font-display: swap;
font-style: normal;
font-weight: 400;
src: local('Inconsolata Regular'), local('Inconsolata-Regular'),
@ -101,6 +115,7 @@ export default () => (
/* latin */
@font-face {
font-family: 'Source Code Pro';
font-display: swap;
font-style: normal;
font-weight: 400;
src: local('Source Code Pro'), local('SourceCodePro-Regular'),
@ -113,6 +128,7 @@ export default () => (
/* latin */
@font-face {
font-family: 'Ubuntu Mono';
font-display: swap;
font-style: normal;
font-weight: 400;
src: local('Ubuntu Mono'), local('UbuntuMono-Regular'),
@ -125,6 +141,7 @@ export default () => (
/* latin */
@font-face {
font-family: 'Space Mono';
font-display: swap;
font-style: normal;
font-weight: 400;
src: local('Space Mono'), local('SpaceMono-Regular'),

@ -191,6 +191,8 @@ export default () => (
color: ${COLORS.PRIMARY};
background: none;
}
.react-spinner{z-index: 999;position:relative;width:32px;height:32px;top:50%;left:50%}.react-spinner_bar{-webkit-animation:react-spinner_spin 1.2s linear infinite;-moz-animation:react-spinner_spin 1.2s linear infinite;animation:react-spinner_spin 1.2s linear infinite;border-radius:5px;background-color:#fff;position:absolute;width:20%;height:7.8%;top:-3.9%;left:-10%}@keyframes react-spinner_spin{0%{opacity:1}100%{opacity:.15}}@-moz-keyframes react-spinner_spin{0%{opacity:1}100%{opacity:.15}}@-webkit-keyframes react-spinner_spin{0%{opacity:1}100%{opacity:.15}}
`}
</style>
)

@ -15,7 +15,6 @@ export const FONTS = [
{ id: 'Ubuntu Mono', name: 'Ubuntu Mono' }
]
const hasStylesheet = false
export const THEMES = [
{
id: '3024-night',
@ -63,13 +62,11 @@ export const THEMES = [
},
{
id: 'night-owl',
name: 'Night Owl',
hasStylesheet
name: 'Night Owl'
},
{
id: 'nord',
name: 'Nord',
hasStylesheet
name: 'Nord'
},
{
id: 'oceanic-next',
@ -77,8 +74,7 @@ export const THEMES = [
},
{
id: 'one-dark',
name: 'One Dark',
hasStylesheet
name: 'One Dark'
},
{
id: 'panda-syntax',
@ -95,12 +91,12 @@ export const THEMES = [
{
id: 'solarized dark',
name: 'Solarized (Dark)',
hasStylesheet
hasStylesheet: false
},
{
id: 'solarized light',
name: 'Solarized (Light)',
hasStylesheet
hasStylesheet: false
},
{
id: 'tomorrow-night-bright',
@ -112,8 +108,7 @@ export const THEMES = [
},
{
id: 'verminal',
name: 'Verminal',
hasStylesheet
name: 'Verminal'
},
{
id: 'yeti',

@ -1,4 +1,3 @@
const withCSS = require('@zeit/next-css')
const withOffline = require('next-offline')
module.exports = withOffline(withCSS())
module.exports = withOffline()

@ -23,6 +23,7 @@
"codemirror": "^5.36.0",
"codemirror-graphql": "^0.6.12",
"codemirror-mode-elixir": "^1.1.1",
"compression": "^1.7.3",
"dom-to-image": "^2.5.2",
"downshift": "^2.0.0",
"dropperx": "0.2.1",
@ -57,7 +58,6 @@
"unsplash-js": "^4.8.0"
},
"devDependencies": {
"@zeit/next-css": "^0.2.0",
"all-contributors-cli": "^5.0.0",
"babel-eslint": "^8.2.3",
"cypress": "^3.0.0",

@ -1,5 +1,6 @@
const path = require('path')
const express = require('express')
const compression = require('compression')
const morgan = require('morgan')
const bodyParser = require('body-parser')
const next = require('next')
@ -46,6 +47,8 @@ app
server.use(morgan('tiny'))
}
server.use(compression())
const filePath = path.join(__dirname, '.next', 'service-worker.js')
server.get('/service-worker.js', (req, res) => app.serveStatic(req, res, filePath))
// api endpoints

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save