mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Incorporate styled-jsx (#420)
* integrate styled-jsx * define styles of pages with styled-jsx * bump styled-jsx * bump styled-jsx * error-debug: fix style * bump styled-jsx * fix examples to use styled-jsx * bump styled-jsx
This commit is contained in:
parent
26c485a22f
commit
a87ef1a7af
|
@ -1,21 +0,0 @@
|
|||
import React, { Component } from 'react'
|
||||
import { style } from 'next/css'
|
||||
|
||||
export default class CrazyCSS extends Component {
|
||||
spans () {
|
||||
const out = []
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
out.push(<span key={i} class={spanStyles[`padding-${i}`]}>This is ${i}</span>)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
render () {
|
||||
return <div>{this.spans()}</div>
|
||||
}
|
||||
}
|
||||
|
||||
const spanStyles = {}
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
spanStyles[`padding-${i}`] = style({ padding: i })
|
||||
}
|
|
@ -1,19 +1,19 @@
|
|||
import React from 'react'
|
||||
import style from 'next/css'
|
||||
|
||||
export default () => (
|
||||
<div className={styles}>
|
||||
<div className='hello'>
|
||||
<p>Hello World</p>
|
||||
<style jsx>{`
|
||||
.hello {
|
||||
font: 15px Helvetica, Arial, sans-serif;
|
||||
background: #eee;
|
||||
padding: 100px;
|
||||
text-align: center;
|
||||
transition: 100ms ease-in background;
|
||||
}
|
||||
.hello:hover {
|
||||
background: #ccc;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
||||
|
||||
const styles = style({
|
||||
font: '15px Helvetica, Arial, sans-serif',
|
||||
background: '#eee',
|
||||
padding: '100px',
|
||||
textAlign: 'center',
|
||||
transition: '100ms ease-in background',
|
||||
':hover': {
|
||||
background: '#ccc'
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import React from 'react'
|
||||
import style from 'next/css'
|
||||
|
||||
export default ({ children }) => (
|
||||
<p className={styles}>{children}</p>
|
||||
<p>
|
||||
{children}
|
||||
<style jsx>{`
|
||||
p {
|
||||
font: 13px Helvetica, Arial;
|
||||
margin: 10px 0;
|
||||
}
|
||||
`}</style>
|
||||
</p>
|
||||
)
|
||||
|
||||
const styles = style({
|
||||
font: '13px Helvetica, Arial',
|
||||
margin: '10px 0'
|
||||
})
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import React from 'react'
|
||||
import style from 'next/css'
|
||||
|
||||
export default ({ title, children }) => (
|
||||
<div className={mainStyle}>
|
||||
<h1 className={titleStyle}>{ title }</h1>
|
||||
<div className='main'>
|
||||
<h1>{ title }</h1>
|
||||
{ children }
|
||||
<style jsx>{`
|
||||
.main {
|
||||
font: 15px Helvetica, Arial;
|
||||
border: 1px solid #eee;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin: 10px 0;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
||||
|
||||
const mainStyle = style({
|
||||
font: '15px Helvetica, Arial',
|
||||
border: '1px solid #eee',
|
||||
padding: '0 10px'
|
||||
})
|
||||
|
||||
const titleStyle = style({
|
||||
fontSize: '16px',
|
||||
fontWeight: 'bold',
|
||||
margin: '10px 0'
|
||||
})
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
import React from 'react'
|
||||
import P from '../components/paragraph'
|
||||
import Post from '../components/post'
|
||||
import style from 'next/css'
|
||||
|
||||
export default () => (
|
||||
<div className={styles.main}>
|
||||
<div className='main'>
|
||||
<Post title='My first blog post'>
|
||||
<P>Hello there</P>
|
||||
<P>This is an example of a componentized blog post</P>
|
||||
</Post>
|
||||
|
||||
<Hr />
|
||||
<hr />
|
||||
|
||||
<Post title='My second blog post'>
|
||||
<P>Hello there</P>
|
||||
|
@ -18,31 +17,30 @@ export default () => (
|
|||
<P>Wa-hoo!</P>
|
||||
</Post>
|
||||
|
||||
<Hr />
|
||||
<hr />
|
||||
|
||||
<Post title='The final blog post'>
|
||||
<P>C'est fin</P>
|
||||
</Post>
|
||||
|
||||
<style jsx>{`
|
||||
.main {
|
||||
margin: auto;
|
||||
max-width: 420px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
hr {
|
||||
width: 100px;
|
||||
border-width: 0;
|
||||
margin: 20px auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
hr::before {
|
||||
content: "***";
|
||||
color: #ccc;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
||||
|
||||
const Hr = () => <hr className={styles.hr} />
|
||||
|
||||
const styles = {
|
||||
main: style({
|
||||
margin: 'auto',
|
||||
maxWidth: '420px',
|
||||
padding: '10px'
|
||||
}),
|
||||
|
||||
hr: style({
|
||||
width: '100px',
|
||||
borderWidth: 0,
|
||||
margin: '20px auto',
|
||||
textAlign: 'center',
|
||||
'::before': {
|
||||
content: '"***"',
|
||||
color: '#ccc'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
"send": "0.14.1",
|
||||
"source-map-support": "0.4.6",
|
||||
"strip-ansi": "3.0.1",
|
||||
"styled-jsx": "0.2.1",
|
||||
"url": "0.11.0",
|
||||
"webpack": "1.14.0",
|
||||
"webpack-dev-middleware": "1.9.0",
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import React from 'react'
|
||||
import ansiHTML from 'ansi-html'
|
||||
import Head from 'next/head'
|
||||
import style from 'next/css'
|
||||
|
||||
export default class ErrorDebug extends React.Component {
|
||||
static getInitialProps ({ err }) {
|
||||
|
@ -12,21 +10,47 @@ export default class ErrorDebug extends React.Component {
|
|||
render () {
|
||||
const { name, message, stack, path } = this.props
|
||||
|
||||
return <div className={styles.errorDebug}>
|
||||
<Head>
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
body {
|
||||
background: #a6004c;
|
||||
margin: 0;
|
||||
}
|
||||
`}} />
|
||||
</Head>
|
||||
{path ? <div className={styles.heading}>Error in {path}</div> : null}
|
||||
return <div className='errorDebug'>
|
||||
{path ? <div className='heading'>Error in {path}</div> : null}
|
||||
{
|
||||
name === 'ModuleBuildError'
|
||||
? <pre className={styles.message} dangerouslySetInnerHTML={{ __html: ansiHTML(encodeHtml(message)) }} />
|
||||
: <pre className={styles.message}>{stack}</pre>
|
||||
? <pre className='message' dangerouslySetInnerHTML={{ __html: ansiHTML(encodeHtml(message)) }} />
|
||||
: <pre className='message'>{stack}</pre>
|
||||
}
|
||||
<style jsx global>{`
|
||||
body {
|
||||
background: #a6004c;
|
||||
margin: 0;
|
||||
}
|
||||
`}</style>
|
||||
<style jsx>{`
|
||||
.errorDebug {
|
||||
height: 100vh;
|
||||
padding: 16px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.message {
|
||||
font-family: "SF Mono", "Roboto Mono", "Fira Mono", menlo-regular, monospace;
|
||||
font-size: 10px;
|
||||
color: #fbe7f1;
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.heading {
|
||||
font-family: -apple-system, BlinkMacSystemFont, Roboto, "Segoe UI", "Fira Sans", Avenir, "Helvetica Neue", "Lucida Grande", sans-serif;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
color: #ff84bf;
|
||||
margin-bottom: 20pxl
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
@ -35,40 +59,6 @@ const encodeHtml = str => {
|
|||
return str.replace(/</g, '<').replace(/>/g, '>')
|
||||
}
|
||||
|
||||
const styles = {
|
||||
body: style({
|
||||
background: '#a6004c',
|
||||
margin: 0
|
||||
}),
|
||||
|
||||
errorDebug: style({
|
||||
height: '100vh',
|
||||
padding: '16px',
|
||||
boxSizing: 'border-box',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}),
|
||||
|
||||
message: style({
|
||||
fontFamily: '"SF Mono", "Roboto Mono", "Fira Mono", menlo-regular, monospace',
|
||||
fontSize: '10px',
|
||||
color: '#fbe7f1',
|
||||
margin: 0,
|
||||
whiteSpace: 'pre-wrap',
|
||||
wordWrap: 'break-word'
|
||||
}),
|
||||
|
||||
heading: style({
|
||||
fontFamily: '-apple-system, BlinkMacSystemFont, Roboto, "Segoe UI", "Fira Sans", Avenir, "Helvetica Neue", "Lucida Grande", sans-serif',
|
||||
fontSize: '13px',
|
||||
fontWeight: 'bold',
|
||||
color: '#ff84bf',
|
||||
marginBottom: '20px'
|
||||
})
|
||||
}
|
||||
|
||||
// see color definitions of babel-code-frame:
|
||||
// https://github.com/babel/babel/blob/master/packages/babel-code-frame/src/index.js
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react'
|
||||
import style from 'next/css'
|
||||
|
||||
export default class Error extends React.Component {
|
||||
static getInitialProps ({ res, xhr }) {
|
||||
|
@ -13,54 +12,53 @@ export default class Error extends React.Component {
|
|||
? 'This page could not be found'
|
||||
: (statusCode ? 'Internal Server Error' : 'An unexpected error has occurred')
|
||||
|
||||
return <div className={styles.error}>
|
||||
<div className={styles.text}>
|
||||
{statusCode ? <h1 className={styles.h1}>{statusCode}</h1> : null}
|
||||
<div className={styles.desc}>
|
||||
<h2 className={styles.h2}>{title}.</h2>
|
||||
return <div className='error'>
|
||||
<div>
|
||||
{statusCode ? <h1>{statusCode}</h1> : null}
|
||||
<div className='desc'>
|
||||
<h2>{title}.</h2>
|
||||
</div>
|
||||
</div>
|
||||
<style jsx>{`
|
||||
.error {
|
||||
color: #000;
|
||||
background: #fff;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
font-family: -apple-system, BlinkMacSystemFont, Roboto, "Segoe UI", "Fira Sans", Avenir, "Helvetica Neue", "Lucida Grande", sans-serif;
|
||||
text-align: center;
|
||||
padding-top: 20%;
|
||||
}
|
||||
|
||||
.desc {
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
line-height: 49px;
|
||||
height: 49px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
h1 {
|
||||
display: inline-block;
|
||||
border-right: 1px solid rgba(0, 0, 0,.3);
|
||||
margin: 0;
|
||||
margin-right: 20px;
|
||||
padding: 10px 23px;
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
const styles = {
|
||||
error: style({
|
||||
color: '#000',
|
||||
background: '#fff',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
position: 'absolute',
|
||||
fontFamily: '-apple-system, BlinkMacSystemFont, Roboto, "Segoe UI", "Fira Sans", Avenir, "Helvetica Neue", "Lucida Grande", sans-serif',
|
||||
textAlign: 'center',
|
||||
paddingTop: '20%'
|
||||
}),
|
||||
|
||||
desc: style({
|
||||
display: 'inline-block',
|
||||
textAlign: 'left',
|
||||
lineHeight: '49px',
|
||||
height: '49px',
|
||||
verticalAlign: 'middle'
|
||||
}),
|
||||
|
||||
h1: style({
|
||||
display: 'inline-block',
|
||||
borderRight: '1px solid rgba(0, 0, 0,.3)',
|
||||
margin: 0,
|
||||
marginRight: '20px',
|
||||
padding: '10px 23px',
|
||||
fontSize: '24px',
|
||||
fontWeight: 500,
|
||||
verticalAlign: 'top'
|
||||
}),
|
||||
|
||||
h2: style({
|
||||
fontSize: '14px',
|
||||
fontWeight: 'normal',
|
||||
margin: 0,
|
||||
padding: 0
|
||||
})
|
||||
}
|
||||
|
|
|
@ -120,7 +120,8 @@ export default async function createCompiler (dir, { dev = false } = {}) {
|
|||
require.resolve('babel-plugin-module-resolver'),
|
||||
{
|
||||
alias: {
|
||||
'ansi-html': require.resolve('ansi-html')
|
||||
'ansi-html': require.resolve('ansi-html'),
|
||||
'styled-jsx/style': require.resolve('styled-jsx/style')
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -143,6 +144,7 @@ export default async function createCompiler (dir, { dev = false } = {}) {
|
|||
require.resolve('babel-plugin-transform-object-rest-spread'),
|
||||
require.resolve('babel-plugin-transform-class-properties'),
|
||||
require.resolve('babel-plugin-transform-runtime'),
|
||||
require.resolve('styled-jsx/babel'),
|
||||
[
|
||||
require.resolve('babel-plugin-module-resolver'),
|
||||
{
|
||||
|
@ -154,7 +156,8 @@ export default async function createCompiler (dir, { dev = false } = {}) {
|
|||
'next/prefetch': require.resolve('../../lib/prefetch'),
|
||||
'next/css': require.resolve('../../lib/css'),
|
||||
'next/head': require.resolve('../../lib/head'),
|
||||
'next/document': require.resolve('../../server/document')
|
||||
'next/document': require.resolve('../../server/document'),
|
||||
'styled-jsx/style': require.resolve('styled-jsx/style')
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { Component, PropTypes } from 'react'
|
||||
import htmlescape from 'htmlescape'
|
||||
import { renderStatic } from 'glamor/server'
|
||||
import flush from 'styled-jsx/server'
|
||||
|
||||
export default class Document extends Component {
|
||||
static getInitialProps ({ renderPage }) {
|
||||
|
@ -10,7 +11,8 @@ export default class Document extends Component {
|
|||
head = page.head
|
||||
return page.html
|
||||
})
|
||||
const nextCSS = { css, ids }
|
||||
const styles = flush()
|
||||
const nextCSS = { css, ids, styles }
|
||||
return { html, head, nextCSS }
|
||||
}
|
||||
|
||||
|
@ -48,7 +50,8 @@ export class Head extends Component {
|
|||
const { head, nextCSS } = this.context._documentProps
|
||||
return <head>
|
||||
{(head || []).map((h, i) => React.cloneElement(h, { key: i }))}
|
||||
{nextCSS ? <style dangerouslySetInnerHTML={{ __html: nextCSS.css }} /> : null}
|
||||
{nextCSS && nextCSS.css ? <style dangerouslySetInnerHTML={{ __html: nextCSS.css }} /> : null}
|
||||
{nextCSS && nextCSS.styles ? nextCSS.styles : null}
|
||||
{this.props.children}
|
||||
</head>
|
||||
}
|
||||
|
|
6
test/fixtures/basic/pages/styled-jsx.js
vendored
Normal file
6
test/fixtures/basic/pages/styled-jsx.js
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
export default () => (
|
||||
<div>
|
||||
<p>This is blue</p>
|
||||
<style jsx>{`p { color: blue }`}</style>
|
||||
</div>
|
||||
)
|
|
@ -45,6 +45,12 @@ describe('integration tests', () => {
|
|||
expect(/<div class="css-\w+">This is red<\/div>/.test(html)).toBeTruthy()
|
||||
})
|
||||
|
||||
test('renders styled jsx', async () => {
|
||||
const html = await render('/styled-jsx')
|
||||
expect(html).toMatch(/<style id="__jsx-style-1401785258">p\[data-jsx="1401785258"] {color: blue }[^]+<\/style>/)
|
||||
expect(html.includes('<div data-jsx="1401785258"><p data-jsx="1401785258">This is blue</p></div>')).toBeTruthy()
|
||||
})
|
||||
|
||||
test('renders properties populated asynchronously', async () => {
|
||||
const html = await render('/async-props')
|
||||
expect(html.includes('<p>Diego Milito</p>')).toBeTruthy()
|
||||
|
@ -62,8 +68,8 @@ describe('integration tests', () => {
|
|||
|
||||
test('error 404', async () => {
|
||||
const html = await render('/non-existent')
|
||||
expect(html).toMatch(/<h1 class=".+">404<\/h1>/)
|
||||
expect(html).toMatch(/<h2 class=".+">This page could not be found\.<\/h2>/)
|
||||
expect(html).toMatch(/<h1 data-jsx=".+">404<\/h1>/)
|
||||
expect(html).toMatch(/<h2 data-jsx=".+">This page could not be found\.<\/h2>/)
|
||||
})
|
||||
|
||||
test('finishes response', async () => {
|
||||
|
|
Loading…
Reference in a new issue