-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
React rewrite of Babel REPL #1297
Changes from all commits
09d855a
9842aa1
67455a5
28b2154
aa6f6dc
a1ae25f
0647578
da257a3
a8a3b67
615bad7
e04ac19
9bf84d2
c10d2e9
70c6f04
8882f57
7296873
65f6f1b
1aeed3b
03eef6a
4f9087b
e450ce8
cef32db
d7e2ac8
e5f24a2
654396b
8030294
85af5fa
feaea87
b93786d
fc8fd62
8f6a9ba
ee8c944
4951d6f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
[ignore] | ||
|
||
[include] | ||
|
||
[libs] | ||
|
||
[lints] | ||
|
||
[options] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Babel REPL | ||
|
||
## Development | ||
|
||
```sh | ||
yarn install | ||
yarn start | ||
``` | ||
|
||
Dev site is accessible at [localhost:3000](http://localhost:3000/). | ||
|
||
## Production build | ||
```sh | ||
yarn build | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"name": "babel-repl", | ||
"version": "0.0.1", | ||
"private": true, | ||
"dependencies": { | ||
"flow-bin": "^0.52.0", | ||
"glamor": "^2.20.39", | ||
"lodash.camelcase": "^4.3.0", | ||
"lz-string": "^1.4.4", | ||
"prettier": "^1.5.3", | ||
"react": "^16.0.0-beta.3", | ||
"react-dom": "^16.0.0-beta.3", | ||
"react-scripts": "1.0.10" | ||
}, | ||
"scripts": { | ||
"build": "react-scripts build", | ||
"eject": "react-scripts eject", | ||
"flow": "flow", | ||
"postbuild": "cp -r ./build ../../_site/repl2", | ||
"prettier": "prettier --single-quote --write 'src/**/*.{js,jsx}'", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likewise this would be good for the entire site. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likewise, this would be good to have for the entire site, not just for the REPL. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (I don't know why this comment appears twice) |
||
"start": "react-scripts start", | ||
"test": "react-scripts test --env=jsdom" | ||
}, | ||
"devDependencies": {} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
<!doctype html> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that ideally this should use the Babel site styling rather than being a totally separate HTML page. We probably want the Babel top bar at least, for consistency. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed! This is just detritus from my demo site. I haven't yet looked into how to share HTML with the main babel site. 😄 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @bvaughn - Should be pretty straightforward. You just need to make a HTML file with "YAML front matter" so that Jekyll processes it. See how the old REPL does it: https://github.com/babel/babel.github.io/blob/master/repl.html There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting. So the only tricky part is making it work nicely with dev workflow. (Adding front matter would break the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In theory, the JS can be rebuilt entirely separately from the Jekyll build, if you can configure it to build it directly into the Yeah, Jekyll is slow... Maybe we should transition the site to something like Hugo, it's a lot faster. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's what the PR currently does (via
I've been waiting for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wow, it shouldn't take that long... I think it normally takes ~5-10 seconds for me (which is slow, but bearable). I wonder if it's hung on something. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems likely, although I There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Running
This is true on Edit 1A fresh clone also fails, but in a different way: git clone git@github.com:babel/babel.github.io.git ./babel-new
cd babel-new
bundle install
npm i
npm start Fails with: > babel.github.io@1.0.0 start /Users/bvaughn/Documents/git/babel-new
> make serve
bundle check || bundle install; \
bundle exec jekyll serve
The Gemfile's dependencies are satisfied
Configuration file: /Users/bvaughn/Documents/git/babel-new/_config.yml
Configuration file: /Users/bvaughn/Documents/git/babel-new/_config.yml
Source: /Users/bvaughn/Documents/git/babel-new
Destination: /Users/bvaughn/Documents/git/babel-new/_site
Incremental build: disabled. Enable with --incremental
Generating...
Liquid Exception: Could not locate the included file 'readmes/babel-core.md' in any of ["/Users/bvaughn/Documents/git/babel-new/_includes"]. Ensure it exists in one of those directories and, if it is a symlink, does not point outside your site source. in docs/usage/api.md
jekyll 3.4.3 | Error: Could not locate the included file 'readmes/babel-core.md' in any of ["/Users/bvaughn/Documents/git/babel-new/_includes"]. Ensure it exists in one of those directories and, if it is a symlink, does not point outside your site source.
make: *** [serve] Error 1
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! babel.github.io@1.0.0 start: `make serve`
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the babel.github.io@1.0.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/bvaughn/.npm/_logs/2017-08-08T00_07_53_930Z-debug.log Edit 2As far as the fresh checkout goes- looks like I needed to run Edit 3Checking out my branch in the new repo and I'm not particularly passionate about learning how Jekyll works to connect these dots. I'd rather spend energy adding more features to the REPL. 😁 I think I'd be more effective at that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'l just make a |
||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | ||
<meta name="theme-color" content="#000000"> | ||
<!-- | ||
manifest.json provides metadata used when your web app is added to the | ||
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/ | ||
--> | ||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"> | ||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess we'll remove this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, this HTML will be replaced by one with Jekyll frontmatter by whoever does that integration. |
||
|
||
<!-- | ||
Load shared resources from CDN to maximize on caching. | ||
This enables us to share assets with other REPLs (eg Prettier). | ||
--> | ||
<script src="https://unpkg.com/babel-standalone@^6"></script> | ||
<script src="https://unpkg.com/codemirror@5/lib/codemirror.js"></script> | ||
<script src="https://unpkg.com/codemirror@5/mode/javascript/javascript.js"></script> | ||
<script src="https://unpkg.com/codemirror@5/mode/xml/xml.js"></script> | ||
<script src="https://unpkg.com/codemirror@5/mode/jsx/jsx.js"></script> | ||
<script src="https://unpkg.com/codemirror@5/keymap/sublime.js"></script> | ||
<script src="https://unpkg.com/codemirror@5/addon/display/placeholder.js"></script> | ||
<script src="https://unpkg.com/codemirror@5/addon/selection/active-line.js"></script> | ||
<link rel="stylesheet" href="https://unpkg.com/codemirror@5//lib/codemirror.css"> | ||
|
||
<!-- | ||
Notice the use of %PUBLIC_URL% in the tags above. | ||
It will be replaced with the URL of the `public` folder during the build. | ||
Only files inside the `public` folder can be referenced from the HTML. | ||
|
||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will | ||
work correctly both with client-side routing and a non-root public URL. | ||
Learn how to configure a non-root public URL by running `npm run build`. | ||
--> | ||
<title>Babel REPL</title> | ||
</head> | ||
<body> | ||
<noscript> | ||
You need to enable JavaScript to run this app. | ||
</noscript> | ||
<div id="root"></div> | ||
<!-- | ||
This HTML file is a template. | ||
If you open it directly in the browser, you will see an empty page. | ||
|
||
You can add webfonts, meta tags, or analytics to this file. | ||
The build step will place the bundled scripts into the <body> tag. | ||
|
||
To begin the development, run `npm start` or `yarn start`. | ||
To create a production bundle, use `npm run build` or `yarn build`. | ||
--> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"short_name": "Babel REPL", | ||
"name": "Babel REPL", | ||
"icons": [ | ||
{ | ||
"src": "favicon.ico", | ||
"sizes": "192x192", | ||
"type": "image/png" | ||
} | ||
], | ||
"start_url": "./index.html", | ||
"display": "standalone", | ||
"theme_color": "#000000", | ||
"background_color": "#ffffff" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
// @flow | ||
|
||
import { css } from 'glamor'; | ||
import React from 'react'; | ||
import { colors } from './styles'; | ||
|
||
const DEFAULT_CODE_MIRROR_OPTIONS = { | ||
autoCloseBrackets: true, | ||
keyMap: 'sublime', | ||
lineNumbers: true, | ||
matchBrackets: true, | ||
mode: 'text/jsx', | ||
showCursorWhenSelecting: true, | ||
styleActiveLine: true, | ||
tabWidth: 2 | ||
}; | ||
|
||
type Props = { | ||
autoFocus: boolean, | ||
onChange: (value: string) => void, | ||
options: Object, | ||
placeholder?: string, | ||
value: ?string, | ||
preserveScrollPosition: boolean | ||
}; | ||
|
||
export default class CodeMirror extends React.Component { | ||
static defaultProps = { | ||
autoFocus: false, | ||
preserveScrollPosition: false, | ||
onChange: (value: string) => {} | ||
}; | ||
|
||
props: Props; | ||
state = { | ||
isFocused: false | ||
}; | ||
|
||
_codeMirror: any; | ||
_textAreaRef: HTMLTextAreaElement; | ||
|
||
componentDidMount() { | ||
this._codeMirror = window.CodeMirror.fromTextArea(this._textAreaRef, { | ||
...DEFAULT_CODE_MIRROR_OPTIONS, | ||
...this.props.options | ||
}); | ||
this._codeMirror.on('change', this._onChange); | ||
this._codeMirror.setValue(this.props.value || ''); | ||
} | ||
|
||
componentWillUnmount() { | ||
// is there a lighter-weight way to remove the cm instance? | ||
if (this._codeMirror) { | ||
this._codeMirror.toTextArea(); | ||
} | ||
} | ||
|
||
componentWillReceiveProps(nextProps: Props) { | ||
if ( | ||
nextProps.value && | ||
nextProps.value !== this.props.value && | ||
this._codeMirror.getValue() !== nextProps.value | ||
) { | ||
if (nextProps.preserveScrollPosition) { | ||
var prevScrollPosition = this._codeMirror.getScrollInfo(); | ||
this._codeMirror.setValue(nextProps.value); | ||
this._codeMirror.scrollTo( | ||
prevScrollPosition.left, | ||
prevScrollPosition.top | ||
); | ||
} else { | ||
this._codeMirror.setValue(nextProps.value); | ||
} | ||
} else if (!nextProps.value) { | ||
this._codeMirror.setValue(''); | ||
} | ||
|
||
if (typeof nextProps.options === 'object') { | ||
for (let optionName in nextProps.options) { | ||
if (nextProps.options.hasOwnProperty(optionName)) { | ||
this._updateOption(optionName, nextProps.options[optionName]); | ||
} | ||
} | ||
} | ||
} | ||
|
||
focus() { | ||
if (this._codeMirror) { | ||
this._codeMirror.focus(); | ||
} | ||
} | ||
|
||
render() { | ||
return ( | ||
<textarea | ||
autoComplete="off" | ||
autoFocus={this.props.autoFocus} | ||
defaultValue={this.props.value} | ||
ref={this._setTextAreaRef} | ||
placeholder={this.props.placeholder} | ||
/> | ||
); | ||
} | ||
|
||
_updateOption(optionName: string, newValue: any) { | ||
const oldValue = this._codeMirror.getOption(optionName); | ||
|
||
if (oldValue !== newValue) { | ||
this._codeMirror.setOption(optionName, newValue); | ||
} | ||
} | ||
|
||
_onChange = (doc: any, change: any) => { | ||
if (change.origin !== 'setValue') { | ||
this.props.onChange(doc.getValue()); | ||
} | ||
}; | ||
|
||
_setTextAreaRef = (ref: HTMLTextAreaElement) => { | ||
this._textAreaRef = ref; | ||
}; | ||
} | ||
|
||
css.global('.CodeMirror', { | ||
height: '100% !important', | ||
width: '100% !important', | ||
'-webkit-overflow-scrolling': 'touch' | ||
}); | ||
|
||
css.global('pre.CodeMirror-placeholder', { | ||
color: colors.foregroundLight | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// @flow | ||
|
||
import { css } from 'glamor'; | ||
import CodeMirror from './CodeMirror'; | ||
import React from 'react'; | ||
import { colors } from './styles'; | ||
|
||
type Props = { | ||
className?: string, | ||
code: ?string, | ||
error: ?Error, | ||
info?: ?string, | ||
onChange?: (value: string) => void, | ||
options: Object, | ||
placeholder?: string | ||
}; | ||
|
||
export default function CodeMirrorPanel(props: Props) { | ||
const { className = '', error, info, onChange } = props; | ||
|
||
return ( | ||
<div className={`${styles.panel} ${className}`}> | ||
<div className={styles.codeMirror}> | ||
<CodeMirror | ||
onChange={onChange} | ||
options={{ | ||
...props.options, | ||
readOnly: onChange == null | ||
}} | ||
placeholder={props.placeholder} | ||
preserveScrollPosition={onChange == null} | ||
value={props.code} | ||
/> | ||
</div> | ||
{info && | ||
<pre className={styles.info}> | ||
{info} | ||
</pre>} | ||
{error && | ||
<pre className={styles.error}> | ||
{error.message} | ||
</pre>} | ||
</div> | ||
); | ||
} | ||
|
||
const sharedBoxStyles = { | ||
flex: '0 0 auto', | ||
maxHeight: '33%', | ||
overflow: 'auto', | ||
margin: 0, | ||
padding: '0.25rem 0.5rem', | ||
whiteSpace: 'pre-wrap', | ||
'-webkit-overflow-scrolling': 'touch' | ||
}; | ||
|
||
const styles = { | ||
codeMirror: css({ | ||
display: 'block', | ||
height: '100%', | ||
width: '100%', | ||
overflow: 'auto' | ||
}), | ||
error: css({ | ||
order: 2, | ||
backgroundColor: colors.errorBackground, | ||
borderTop: `1px solid ${colors.errorBorder}`, | ||
color: colors.errorForeground, | ||
...sharedBoxStyles | ||
}), | ||
info: css({ | ||
order: 1, | ||
backgroundColor: colors.infoBackground, | ||
borderTop: `1px solid ${colors.infoBorder}`, | ||
color: colors.infoForeground, | ||
...sharedBoxStyles | ||
}), | ||
panel: css({ | ||
height: '100%', | ||
display: 'flex', | ||
flexDirection: 'column', | ||
justifyContent: 'stretch', | ||
overflow: 'auto' | ||
}) | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe merge this with the root
package.json
so we don't have toyarn install
in two separate directories? I'm not sure what the benefit of splitting them is.