Skip to content

Commit 9755e94

Browse files
Refactored to simple server implementation, added sandbox domain and handling entry points
1 parent 6caa8d3 commit 9755e94

26 files changed

+255
-106
lines changed

app/components/AddFile/index.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,20 @@ function AddFile(props) {
3030
<form onSubmit={onSubmit}>
3131
<input
3232
value={props.value}
33+
onClick={(e) => e.stopPropagation()}
3334
onChange={onAddFileInputChange}
3435
onKeyDown={onAddFileInputKeyDown}
3536
className={styles.input}
3637
autoFocus
37-
placeholder={props.placeholder}
38-
onBlur={() => props.onAddFileAborted()}>
39-
</input>
38+
placeholder={props.placeholder}/>
39+
<label className={styles.entry} onClick={(e) => e.stopPropagation()}>
40+
<input
41+
type="checkbox"
42+
checked={props.isEntry}
43+
disabled={props.disableEntry}
44+
onChange={() => props.onEntryChange()}/>
45+
<span>Is entry</span>
46+
</label>
4047
</form>
4148
</div>
4249
</div>

app/components/AddFile/styles.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,18 @@
3838
.input:focus {
3939
outline: 0;
4040
}
41+
42+
.entry {
43+
display: inline-block;
44+
margin: 0 5px;
45+
height: 30px;
46+
}
47+
48+
.entry input {
49+
margin-right: 5px;
50+
}
51+
52+
.entry span {
53+
position: relative;
54+
top: 1px;
55+
}

app/components/Preview/index.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,33 @@ class Preview extends React.Component {
1414
}
1515
componentDidUpdate(prevProps) {
1616
if (prevProps.isRunning && !this.props.isRunning) {
17-
this.refs.iframe.src = location.origin + '/api/sandbox';
17+
this.refs.iframe.src = [
18+
location.protocol,
19+
'//',
20+
location.hostname.replace('www', 'sandbox'),
21+
(location.port ? ':' + location.port : ''),
22+
'/'
23+
].join('')
1824
}
1925
}
2026
componentDidMount() {
2127
window.addEventListener('message', this.onIframeMessage);
2228
this.refs.iframe.addEventListener('load', () => {
23-
this.refs.iframe.contentWindow.document.addEventListener('click', () => {
24-
this.props.signals.bin.appClicked();
25-
});
29+
2630
});
2731
}
2832
onIframeMessage(event) {
2933
if (event.data.type === 'loaded') {
30-
console.log('Loaded!');
3134
this.props.signals.bin.iframeLoaded();
3235
}
3336
if (event.data.type === 'log') {
3437
this.props.signals.bin.logReceived({
3538
value: event.data.value
3639
});
3740
}
41+
if (event.data.type === 'click') {
42+
this.props.signals.bin.appClicked();
43+
}
3844
}
3945
render() {
4046
return (

app/components/Toolbar/index.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import ToolbarButtonPopover from '../ToolbarButtonPopover';
1010
import Npm from '../Npm';
1111
import Boilerplates from '../Boilerplates';
1212

13+
import hasEntry from '../../computed/hasEntry';
14+
1315
@Cerebral({
1416
files: 'bin.currentBin.files',
1517
selectedFileIndex: 'bin.selectedFileIndex',
@@ -25,7 +27,9 @@ import Boilerplates from '../Boilerplates';
2527
showBoilerplatesSelector: 'bin.showBoilerplatesSelector',
2628
vimModeEnabled: 'bin.vimMode',
2729
currentBin: 'bin.currentBin',
28-
highlightCreateIssue: 'bin.highlightCreateIssue'
30+
highlightCreateIssue: 'bin.highlightCreateIssue',
31+
isEntry: 'bin.isEntry',
32+
hasEntry: hasEntry
2933
})
3034
class Toolbar extends React.Component {
3135
static propTypes = {
@@ -157,11 +161,14 @@ class Toolbar extends React.Component {
157161
<div className={styles.row}>
158162
<AddFile
159163
onAddFileClick={signals.bin.addFileClicked}
164+
onEntryChange={signals.bin.entryToggled}
160165
onFileNameChange={signals.bin.addFileNameUpdated}
161166
onFileSubmit={signals.bin.addFileSubmitted}
162167
onAddFileAborted={signals.bin.addFileAborted}
163168
showInput={this.props.showAddFileInput}
164169
placeholder="Filename..."
170+
isEntry={this.props.isEntry}
171+
disableEntry={this.props.hasEntry}
165172
value={this.props.newFileName}/>
166173
{this.renderFiles()}
167174
</div>

app/computed/hasEntry.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
function canControl(get) {
2+
const files = get('bin.currentBin.files');
3+
return Boolean(files.filter((file) => {
4+
return file.isEntry;
5+
}).length)
6+
}
7+
8+
export default canControl;

app/modules/Bin/actions/addFile.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ function addFile({state}) {
33
const ext = fileName.split('.')[fileName.split('.').length - 1];
44
state.push('bin.currentBin.files', {
55
name: fileName,
6-
content: ''
6+
content: '',
7+
isEntry: state.get('bin.isEntry')
78
});
89

910
if (ext === 'ts' && !state.get('bin.currentBin.loaders.typescript')) {

app/modules/Bin/actions/setEmptyBin.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,16 @@ function setEmptyBin({state}) {
33
packages: {},
44
loaders: {},
55
files: [{
6-
name: 'main.js',
7-
content: ''
6+
name: 'index.html',
7+
content: `<!DOCTYPE html>
8+
<html>
9+
<head>
10+
<meta charset="utf-8"/>
11+
</head>
12+
<body>
13+
14+
</body>
15+
</html>`
816
}]
917
});
1018
state.set('bin.selectedFileIndex', 0);

app/modules/Bin/index.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import logPathSelected from './signals/logPathSelected';
3232
import welcomeBinClicked from './signals/welcomeBinClicked';
3333
import emptyBinClicked from './signals/emptyBinClicked';
3434
import toggleFullLog from './signals/toggleFullLog';
35+
import entryToggled from './signals/entryToggled';
3536

3637
export default (options = {}) => {
3738
return (module, controller) => {
@@ -49,6 +50,7 @@ export default (options = {}) => {
4950
loaders: {},
5051
isLive: false
5152
},
53+
isEntry: false,
5254
isLoadingBin: false,
5355
showBinLoader: false,
5456
logs: [],
@@ -98,6 +100,10 @@ export default (options = {}) => {
98100
logPathSelected: preventIfLive(logPathSelected),
99101
logReceived: preventIfLive(logReceived),
100102
toggleFullLog: preventIfLive(toggleFullLog),
103+
entryToggled: preventIfLive(entryToggled),
104+
addFileAborted: preventIfLive(addFileAborted),
105+
addFileNameUpdated: preventIfLive(addFileNameUpdated),
106+
addFileSubmitted: preventIfLive(addFileSubmitted),
101107
opened,
102108
vimModeClicked,
103109
linterRequested,
@@ -106,9 +112,6 @@ export default (options = {}) => {
106112
rootRouted,
107113
linted,
108114
iframeLoaded,
109-
addFileAborted,
110-
addFileNameUpdated,
111-
addFileSubmitted,
112115
welcomeBinClicked,
113116
emptyBinClicked
114117
});

app/modules/Bin/signals/addFileSubmitted.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ export default [
88
selectLastFile,
99
set('state:/bin.newFileName', ''),
1010
set('state:/bin.showAddFileInput', false),
11+
set('state:/bin.isEntry', false),
1112
shouldLint
1213
];

app/modules/Bin/signals/appClicked.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import set from 'cerebral-addons/set';
12
import hidePopups from '../factories/hidePopups';
23

34
export default [
4-
...hidePopups
5+
...hidePopups,
6+
set('state:/bin.showAddFileInput', false)
57
];
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import toggle from 'cerebral-addons/toggle';
2+
3+
export default [
4+
toggle('state:/bin.isEntry')
5+
];

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,6 @@
5252
<img src="logo.png"/>
5353
<h3>Loading it up!</h3>
5454
</div>
55-
<script type="text/javascript" src="/build/bundle.js"></script>
55+
<script type="text/javascript" src="/client_bundle.js"></script>
5656
</body>
5757
</html>

package.json

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@
2121
"homepage": "https://github.com/cerebral/cerebral-boilerplate",
2222
"scripts": {
2323
"start": "node start.js",
24-
"dev": "concurrently \"npm run client\" \"npm run server\"",
25-
"client": "kotatsu serve app/main.js --public public --index index.html --config webpack.config.js --devtool eval-source-map --proxy /api http://www.webpackbin.dev:4000/api",
26-
"server": "kotatsu start start.js --source-maps",
27-
"build": "npm run build:client",
28-
"build:client": "kotatsu build client app/main.js --config webpack.production.config.js --source-maps --minify -o public/client_build.js",
29-
"build:server": "kotatsu build server start.js --minify -o server_build.js",
24+
"build": "webpack --config webpack.production.config.js",
3025
"postinstall": "node configure && npm run build"
3126
},
3227
"dependencies": {
@@ -89,12 +84,15 @@
8984
"source-map-support": "^0.4.0",
9085
"string-hash": "^1.1.0",
9186
"style-loader": "^0.13.0",
87+
"subdomain": "^1.2.0",
9288
"tar-pack": "^3.1.3",
9389
"ts-loader": "^0.8.1",
9490
"typescript": "^1.8.2",
9591
"url-loader": "^0.5.7",
9692
"usage": "^0.7.1",
9793
"webpack-bin-babel-core": "https://github.com/christianalfoni/webpack-bin-babel-core.git",
94+
"webpack-dev-middleware": "^1.5.1",
95+
"webpack-hot-middleware": "^2.10.0",
9896
"ws": "^1.0.1"
9997
}
10098
}

server/index.js

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
var server = require('http').createServer();
2+
var webpack = require('webpack');
3+
var config = require('../webpack.config.js');
4+
var webpackMiddleware = require('webpack-dev-middleware');
5+
var webpackHotMiddleware = require('webpack-hot-middleware');
26
var WebSocketServer = require('ws').Server;
37
var wss = new WebSocketServer({ server: server });
48
var express = require('express');
5-
var webpack = require('webpack');
9+
var subdomain = require('subdomain');
610
var compression = require('compression');
711
var app = express();
812
var MemoryFileSystem = require("memory-fs");
@@ -22,8 +26,7 @@ var npm = require('./npm');
2226
var bins = require('./bins');
2327
var liveConnection = require('./live');
2428
var zip = require('./zip');
25-
var usage = require('usage');
26-
var vendorsBundlesCleaner = require('./vendorsBundlesCleaner');
29+
var status = require('./status');
2730

2831
preLoadPackages([
2932
// Core node
@@ -74,44 +77,54 @@ if (utils.isProduction()) {
7477
}
7578
});
7679
}
80+
7781
app.use(compression())
7882
app.use(cookieParser());
83+
app.use(subdomain({
84+
base: utils.isProduction() ? 'webpackbin.com' : 'webpackbin.dev',
85+
ignoreWWW: true
86+
}));
7987
app.use(bodyParser.json());
8088
app.use(express.static(path.resolve('public')));
8189
app.use(sessions.middleware);
8290

83-
app.get('/api/bins/:id', bins.get);
91+
if (!utils.isProduction()) {
92+
const compiler = webpack(config);
8493

85-
app.get('/api/sandbox/', sandbox.getIndex);
86-
app.get('/api/sandbox/*', sandbox.getFile)
87-
app.post('/api/sandbox', sandbox.updateSandbox);
94+
app.use(webpackMiddleware(compiler, {
95+
publicPath: config.output.publicPath,
96+
contentBase: 'app',
97+
stats: {
98+
colors: true,
99+
hash: false,
100+
timings: true,
101+
chunks: true,
102+
chunkModules: false,
103+
modules: false
104+
}
105+
}));
106+
107+
app.use(webpackHotMiddleware(compiler));
108+
}
88109

110+
app.get('/api/bins/:id', bins.get);
89111
app.get('/api/packages/:packageName', npm.getPackageFromRegistry);
90112
app.get('/api/bundles', database.searchBundles);
91-
92113
app.get('/api/boilerplates/:id', bins.getBoilerplate);
93-
94114
app.get('/api/project.zip', zip);
115+
app.post('/api/sandbox', sandbox.updateSandbox);
95116

96-
app.get('/status', function (req, res) {
97-
var pid = process.pid;
98-
var options = { keepHistory: true }
99-
usage.lookup(pid, options, function(err, result) {
100-
if (err) {
101-
return res.sendStatus(500);
102-
}
103-
res.send({
104-
memory: result,
105-
vendorsInMemory: vendorsBundlesCleaner.getBundles()
106-
});
107-
});
108-
});
117+
app.get('/subdomain/sandbox/', sandbox.getIndex);
118+
app.get('/subdomain/sandbox/*', sandbox.getFile)
119+
120+
app.get('/status', status.get);
109121

110122
var indexHtml = fs.readFileSync(path.resolve('index.html'))
111123
.toString()
112124
.replace('/build/bundle.js', '/client_build.js')
113125
.replace('</body>', "<script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-74769782-1', 'auto');ga('send', 'pageview');</script>\n </body>");
114126
app.get('*', function(req, res) {
127+
console.log('Got here!');
115128
res.send(indexHtml);
116129
});
117130

0 commit comments

Comments
 (0)