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

React rewrite of Babel REPL #1297

Merged
merged 33 commits into from
Aug 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
09d855a
Imported create-react-app based Babel REPL from github.com/bvaughn/ba…
bvaughn Aug 7, 2017
9842aa1
Removed pre-commit hook (for now)
bvaughn Aug 7, 2017
67455a5
Reorganized code/folders slightly
bvaughn Aug 7, 2017
28b2154
Removed some unnecessary packages/fields from package.json
bvaughn Aug 7, 2017
aa6f6dc
Removed unnecessary App component and repl subdir
bvaughn Aug 7, 2017
a1ae25f
Removed some detritus
bvaughn Aug 7, 2017
0647578
Merged .gitignore from new React REPL into main
bvaughn Aug 7, 2017
da257a3
Removed some gratuitous destructuring
bvaughn Aug 7, 2017
a8a3b67
Removed codemirror dep since it's coming from CDN
bvaughn Aug 8, 2017
615bad7
Added :isPreloaded attribute to PluginConfig type to signify which pr…
bvaughn Aug 8, 2017
e04ac19
Updated to React 16 beta
bvaughn Aug 8, 2017
9bf84d2
Fixed Babili plug-in option. It had gotten disconnected from the comp…
bvaughn Aug 8, 2017
c10d2e9
Load Babel polyfill runtime if 'evaluate' is checked
bvaughn Aug 11, 2017
70c6f04
Minor tweaks to error display
bvaughn Aug 12, 2017
8882f57
Added new sidebar UI and styles
bvaughn Aug 12, 2017
7296873
Basic support for babel-preset-env
bvaughn Aug 12, 2017
65f6f1b
Sidebar can be toggled open/closed now
bvaughn Aug 12, 2017
1aeed3b
Removed Input/Output labels
bvaughn Aug 12, 2017
03eef6a
Added placeholder to left CodeMirror input
bvaughn Aug 13, 2017
4f9087b
Highlight active line
bvaughn Aug 13, 2017
e450ce8
Expounded on Prettier AST issue TODO
bvaughn Aug 13, 2017
cef32db
Move preset-loading animation into its own file
bvaughn Aug 13, 2017
d7e2ac8
Added a little animation to the expande/collapse button
bvaughn Aug 13, 2017
e5f24a2
Support builtIns query param
bvaughn Aug 13, 2017
654396b
Reorganized Env preset section and built-ins option
bvaughn Aug 13, 2017
8030294
Removed :experimental flag; I don't see any mention of it in the live…
bvaughn Aug 13, 2017
85af5fa
Disabled "built-ins" option if "evaluate" is checked
bvaughn Aug 13, 2017
feaea87
Env debug option/panel working
bvaughn Aug 13, 2017
b93786d
Minor tidying up
bvaughn Aug 13, 2017
fc8fd62
Fixed cheesy Firefox sizing CSS issue
bvaughn Aug 13, 2017
8f6a9ba
Show sidebar by default (unless explicitly collapsed)
bvaughn Aug 13, 2017
ee8c944
Misc code review tweaks
bvaughn Aug 13, 2017
4951d6f
CSS transition for hover colors in sidebar
bvaughn Aug 13, 2017
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
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,20 @@ node_modules
.DS_Store
npm-debug.log
_includes/readmes/*.md

# testing
coverage

# production
build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
9 changes: 9 additions & 0 deletions js/repl/.flowconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[ignore]

[include]

[libs]

[lints]

[options]
15 changes: 15 additions & 0 deletions js/repl/README.md
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
```
25 changes: 25 additions & 0 deletions js/repl/package.json
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"
Copy link
Member

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 to yarn install in two separate directories? I'm not sure what the benefit of splitting them is.

},
"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}'",
Copy link
Member

Choose a reason for hiding this comment

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

Likewise this would be good for the entire site.

Copy link
Member

Choose a reason for hiding this comment

The 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.

Copy link
Member

Choose a reason for hiding this comment

The 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": {}
}
Binary file added js/repl/public/favicon.ico
Binary file not shown.
55 changes: 55 additions & 0 deletions js/repl/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<!doctype html>
Copy link
Member

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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. 😄

Copy link
Member

Choose a reason for hiding this comment

The 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

Copy link
Contributor Author

@bvaughn bvaughn Aug 7, 2017

Choose a reason for hiding this comment

The 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 yarn dev workflow for CRA.) Maybe this is a good enough reason to bail on CRA, although I like the idea of being able to test the REPL without running the whole (slow) Jekyll build. It's painful.

Copy link
Member

Choose a reason for hiding this comment

The 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 _site directory. That way, you'd only care about the Jekyll build if you touch the HTML. I wonder if Jekyll would get angry at us for touching the _site files directly though. Could try it and see 😛

Yeah, Jekyll is slow... Maybe we should transition the site to something like Hugo, it's a lot faster.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 _site directory.

That's what the PR currently does (via yarn build) although nothing hooks into the make build process to run it.

Yeah, Jekyll is slow...

I've been waiting for npm start to run for about 5 minutes and I'm stuck at "Generating..." 🤔

Copy link
Member

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Seems likely, although I rm -rf ./_site && npm start and it still seems to run to that point and then stick.

Copy link
Contributor Author

@bvaughn bvaughn Aug 8, 2017

Choose a reason for hiding this comment

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

Running bundle exec jekyll serve directly (with the --verbose flag) shows it getting hung after:

   GitHub Metadata: Initializing...
        Generating: Jekyll::GitHubMetadata::GHPMetadataGenerator finished in 0.001932 seconds.
        Generating: JekyllOptionalFrontMatter::Generator finished in 0.091768 seconds.
        Generating: JekyllReadmeIndex::Generator finished in 24.729063 seconds.

This is true on master as well. Hm. I wonder what broke. This worked for me at one point.

Edit 1

A 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 2

As far as the fresh checkout goes- looks like I needed to run npm run build before npm start. Didn't see that in the docs. Still having trouble with this checkout though. Hm.

Edit 3

Checking out my branch in the new repo and yarn building this project before starting Jekyll up again caused it to hang also. I'm not familiar with Jekyll so I don't know how fragile it's supposed to be. Seems to be pretty easy to hang it though. Anyone with more Jekyll experience willing to lend a hand?

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.

Copy link
Member

Choose a reason for hiding this comment

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

I'l just make a make bootstrap like babel's

<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">
Copy link
Member

@Daniel15 Daniel15 Aug 13, 2017

Choose a reason for hiding this comment

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

I guess we'll remove this %PUBLIC_URL% once the build of this page is moved into Jekyll as it handles the URLs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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>
15 changes: 15 additions & 0 deletions js/repl/public/manifest.json
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"
}
132 changes: 132 additions & 0 deletions js/repl/src/CodeMirror.js
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
});
85 changes: 85 additions & 0 deletions js/repl/src/CodeMirrorPanel.js
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'
})
};
Loading