Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added new JSX entry points for the automatic runtime #1970

Merged
merged 28 commits into from
Oct 31, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
d1c9bc6
re-export react jsx-runtime to test project config
Aug 11, 2020
4967f9c
minimal react playground app
Aug 12, 2020
6eeb60a
demonstrate w/o import
Aug 12, 2020
8d3d88e
ignore react in scope rule
Aug 12, 2020
23c7074
custom pragma end to end w/ react/jsx-runtime pass thru
Aug 12, 2020
0750e8f
dupe jsx for future rewriting, at least get React's jsx fallback when…
Aug 12, 2020
bcd6918
copy the CRA code over
Aug 12, 2020
338a0e8
Remove the minimal-react playground
Andarist Oct 18, 2020
5dec9f1
Remove console.log
Andarist Oct 18, 2020
09b5a55
Rename jsx-runtime entrypoint to jsx-runtime.js
Andarist Oct 18, 2020
5b3250f
Add jsx-runtime.js to the publishable files
Andarist Oct 18, 2020
82b44ba
Move createElement export to the root entry of @emotion/core
Andarist Oct 18, 2020
c471b94
Move configuration of the umdName to the @emotion/core package.json
Andarist Oct 18, 2020
17680e7
Minor refactor in babel-preset-css-prop
Andarist Oct 18, 2020
70f0969
Align the import source value to use the convention used in the outpu…
Andarist Oct 18, 2020
6181943
Try to bump node version on CircleCI
Andarist Oct 18, 2020
45b28c3
Refactor jsx runtimes so they share the css prop-related implementati…
Andarist Oct 18, 2020
faac259
Fixed an issue with label extraction from the stack of the bundles files
Andarist Oct 18, 2020
5159b99
Merge branch 'master' into jsx-runtime
Andarist Oct 18, 2020
ed682ee
"fix" flow errors
emmatown Oct 18, 2020
a1cc40b
Add snapshot tests for the runtime option
Andarist Oct 19, 2020
341b5a6
Disable react/react-in-jsx-scope rule
Andarist Oct 19, 2020
733b6f7
Add basic runtime tests for new JSX runtimes
Andarist Oct 19, 2020
23e68d3
Add UMD builds back to @emotion/core
emmatown Oct 19, 2020
386b855
Remove .js suffix from our runtimes as per latest Babel revert
Andarist Oct 20, 2020
2798e54
Add changesets
Andarist Oct 30, 2020
ad892cb
Update .changeset/nine-waves-play.md
emmatown Oct 31, 2020
8f6271e
Merge branch 'master' into jsx-runtime
emmatown Oct 31, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ package-lock.json
.cache
public/
!playgrounds/cra/public
!playgrounds/minimal-react/public
.env
.vscode
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
"release": "yarn build && changeset publish"
},
"resolutions": {
"**/react": "16.8.1",
"**/react-dom": "16.8.1",
"**/react": "17.0.0-rc.0",
"**/react-dom": "17.0.0-rc.0",
"**/browserslist": "^3.2.8",
"**/graphql-type-json": "0.2.4"
},
Expand Down Expand Up @@ -121,7 +121,8 @@
"packages/*"
],
"globals": {
"react": "React"
"react": "React",
"@emotion/core": "emotionCore"
Andarist marked this conversation as resolved.
Show resolved Hide resolved
}
},
"bugs": {
Expand Down
2 changes: 1 addition & 1 deletion packages/babel-preset-css-prop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"license": "MIT",
"repository": "https://github.com/emotion-js/emotion/tree/master/packages/babel-preset-css-prop",
"dependencies": {
"@babel/plugin-transform-react-jsx": "^7.3.0",
"@babel/plugin-transform-react-jsx": "^7.10.4",
"@babel/runtime": "^7.5.5",
"@emotion/babel-plugin-jsx-pragmatic": "^0.1.5",
"babel-plugin-emotion": "^10.0.27"
Expand Down
11 changes: 8 additions & 3 deletions packages/babel-preset-css-prop/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,22 @@ export default (
api,
{ pragma, sourceMap, autoLabel, labelFormat, instances, ...options } = {}
) => {
const isAutomaticRuntime = options.runtime === 'automatic'
console.log({ isAutomaticRuntime })
const jsxOptions = isAutomaticRuntime
? { importSource: '@emotion/core' }
: { pragma: pragmaName, pragmaFrag: 'React.Fragment' }
Andarist marked this conversation as resolved.
Show resolved Hide resolved
return {
plugins: [
[
!isAutomaticRuntime && [
Andarist marked this conversation as resolved.
Show resolved Hide resolved
pragmatic,
{
export: 'jsx',
module: '@emotion/core',
import: pragmaName
}
],
[jsx, { pragma: pragmaName, pragmaFrag: 'React.Fragment', ...options }],
[jsx, { ...jsxOptions, ...options }],
[
emotion,
{
Expand All @@ -34,6 +39,6 @@ export default (
cssPropOptimization: true
}
]
]
].filter(Boolean)
}
}
11 changes: 11 additions & 0 deletions packages/core/jsx-runtime/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"main": "dist/core.cjs.js",
"module": "dist/core.esm.js",
"browser": {
"./dist/core.cjs.js": "./dist/core.browser.cjs.js",
"./dist/core.esm.js": "./dist/core.browser.esm.js"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's weird that these are named core, yeah? I tried to make it jsx-runtime but preconstruct overrode it. In any case, it works. We have:

@emotion/core/dist/core.esm.js
@emotion/core/jsx-runtime/dist/core.esm.js

and so on. The imports seem to work in the minimal-react so 🤷‍♀️ maybe it doesn't matter.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it doesnt matter - i agree the naming convention used for those files is confusing, we have already agreed in the past on making that change but I'm not sure when it will land

},
"preconstruct": {
"source": "../src/jsx-runtime"
}
}
11 changes: 7 additions & 4 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"@emotion/utils": "0.11.3"
},
"peerDependencies": {
"react": ">=16.3.0"
"react": "17.0.0-rc.0"
},
"devDependencies": {
"@emotion/styled": "^10.0.27",
Expand All @@ -37,15 +37,18 @@
"emotion-server": "^10.0.27",
"emotion-theming": "^10.0.27",
"html-tag-names": "^1.1.2",
"react": "^16.5.2",
"react": "17.0.0-rc.0",
"svg-tag-names": "^1.1.1"
},
"repository": "https://github.com/emotion-js/emotion/tree/master/packages/core",
"publishConfig": {
"access": "public"
},
"umd:main": "dist/core.umd.min.js",
"preconstruct": {
"umdName": "emotionCore"
"source": "src/index.js",
"entrypoints": [
Andarist marked this conversation as resolved.
Show resolved Hide resolved
".",
"jsx-runtime"
]
}
}
174 changes: 174 additions & 0 deletions packages/core/src/jsx-runtime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/* eslint-disable no-unused-vars */
Andarist marked this conversation as resolved.
Show resolved Hide resolved
import * as React from 'react'
import { withEmotionCache, ThemeContext } from './context'
import { getRegisteredStyles, insertStyles } from '@emotion/utils'
import { isBrowser } from './utils'
import { serializeStyles } from '@emotion/serialize'

import { jsx as reactJsx, Fragment, createElement } from 'react/jsx-runtime'

const sanitizeIdentifier = identifier => identifier.replace(/\$/g, '-')

let typePropName = '__EMOTION_TYPE_PLEASE_DO_NOT_USE__'

let labelPropName = '__EMOTION_LABEL_PLEASE_DO_NOT_USE__'

let hasOwnProperty = Object.prototype.hasOwnProperty

let render = (cache, props, theme, ref) => {
let cssProp = theme === null ? props.css : props.css(theme)

// so that using `css` from `emotion` and passing the result to the css prop works
// not passing the registered cache to serializeStyles because it would
// make certain babel optimisations not possible
if (typeof cssProp === 'string' && cache.registered[cssProp] !== undefined) {
cssProp = cache.registered[cssProp]
}

let type = props[typePropName]
let registeredStyles = [cssProp]
let className = ''

if (typeof props.className === 'string') {
className = getRegisteredStyles(
cache.registered,
registeredStyles,
props.className
)
} else if (props.className != null) {
className = `${props.className} `
}

let serialized = serializeStyles(registeredStyles)

if (
process.env.NODE_ENV !== 'production' &&
serialized.name.indexOf('-') === -1
) {
let labelFromStack = props[labelPropName]
if (labelFromStack) {
serialized = serializeStyles([
serialized,
'label:' + labelFromStack + ';'
])
}
}
const rules = insertStyles(cache, serialized, typeof type === 'string')
className += `${cache.key}-${serialized.name}`

const newProps = {}
for (let key in props) {
if (
hasOwnProperty.call(props, key) &&
key !== 'css' &&
key !== typePropName &&
(process.env.NODE_ENV === 'production' || key !== labelPropName)
) {
newProps[key] = props[key]
}
}
newProps.ref = ref
newProps.className = className

const ele = jsx(type, newProps)
if (!isBrowser && rules !== undefined) {
let serializedNames = serialized.name
let next = serialized.next
while (next !== undefined) {
serializedNames += ' ' + next.name
next = next.next
}
return (
<React.Fragment>
<style
{...{
[`data-emotion-${cache.key}`]: serializedNames,
dangerouslySetInnerHTML: { __html: rules },
nonce: cache.sheet.nonce
}}
/>
{ele}
</React.Fragment>
)
}
return ele
}

let Emotion = /* #__PURE__ */ withEmotionCache((props, cache, ref) => {
// use Context.read for the theme when it's stable
if (typeof props.css === 'function') {
return (
<ThemeContext.Consumer>
{theme => render(cache, props, theme, ref)}
</ThemeContext.Consumer>
)
}
return render(cache, props, null, ref)
})

if (process.env.NODE_ENV !== 'production') {
Emotion.displayName = 'EmotionCssPropInternal'
}

const jsx = (type, props, maybeKey) => {
Andarist marked this conversation as resolved.
Show resolved Hide resolved
let args = arguments

if (props == null || !hasOwnProperty.call(props, 'css')) {
return reactJsx(type, props, maybeKey)
}

if (
process.env.NODE_ENV !== 'production' &&
typeof props.css === 'string' &&
// check if there is a css declaration
props.css.indexOf(':') !== -1
) {
throw new Error(
`Strings are not allowed as css prop values, please wrap it in a css template literal from '@emotion/css' like this: css\`${
props.css
}\``
)
}

let argsLength = args.length

let createElementArgArray = new Array(argsLength)

createElementArgArray[0] = Emotion
let newProps = {}

for (let key in props) {
if (hasOwnProperty.call(props, key)) {
newProps[key] = props[key]
}
}
newProps[typePropName] = type
if (process.env.NODE_ENV !== 'production') {
let error = new Error()
if (error.stack) {
// chrome
let match = error.stack.match(
/at (?:Object\.|Module\.|)jsx.*\n\s+at ([A-Z][A-Za-z$]+) /
)
if (!match) {
// safari and firefox
match = error.stack.match(/.*\n([A-Z][A-Za-z$]+)@/)
}
if (match) {
newProps[labelPropName] = sanitizeIdentifier(match[1])
}
}
}

createElementArgArray[1] = newProps

for (let i = 2; i < argsLength; i++) {
createElementArgArray[i] = args[i]
}
// $FlowFixMe
return reactJsx.apply(null, createElementArgArray)
}

const jsxs = jsx
Andarist marked this conversation as resolved.
Show resolved Hide resolved

export { jsx, jsxs, Fragment, createElement }
Andarist marked this conversation as resolved.
Show resolved Hide resolved
47 changes: 47 additions & 0 deletions playgrounds/minimal-react/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "minimal-react",
"version": "1.0.0",
"main": "index.js",
"private": true,
"license": "private",
"scripts": {
"start": "webpack-dev-server"
},
"dependencies": {
"@babel/core": "^7.11.1",
"@babel/preset-env": "^7.11.0",
"@babel/preset-react": "^7.10.4",
"@emotion/babel-preset-css-prop": "^10.0.27",
"@emotion/core": "^10.0.34",
"react": "17.0.0-rc.0",
"react-dom": "17.0.0-rc.0"
},
"devDependencies": {
"babel-loader": "^8.1.0",
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0"
},
"eslintConfig": {
"rules": {
"react/react-in-jsx-scope": "off"
}
},
"babel": {
"presets": [
"@babel/preset-env",
[
"@babel/preset-react",
{
"runtime": "automatic"
Andarist marked this conversation as resolved.
Show resolved Hide resolved
}
],
[
"@emotion/babel-preset-css-prop",
{
"runtime": "automatic"
}
]
]
}
}
14 changes: 14 additions & 0 deletions playgrounds/minimal-react/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>Minimal React</title>
</head>

<body>
<div id="root"></div>
<script src="bundle.js"></script>
</body>

</html>
34 changes: 34 additions & 0 deletions playgrounds/minimal-react/src/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Global, keyframes } from '@emotion/core'

let animation = keyframes({
'from,to': {
transform: 'scale(1)'
},
'50%': {
transform: 'scale(0.5)'
}
})

const App = () => (
<>
<Global
styles={{
body: {
padding: 0,
margin: 0,
fontFamily: 'sans-serif'
}
}}
/>
<h1
css={{
color: 'hotpink',
animation: `${animation} 1s infinite`
}}
>
wow, some hotpink text!!
Andarist marked this conversation as resolved.
Show resolved Hide resolved
</h1>
</>
)

export default App
10 changes: 10 additions & 0 deletions playgrounds/minimal-react/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { render } from 'react-dom'
import App from './App'

let root = document.getElementById('root')

if (!root) {
throw new Error('could not find root element')
}

render(<App />, root)
Loading