1 | process.env.DEBUG = 'app:*';
|
2 | const debug = require('debug')('app:demos');
|
3 | const commander = require('commander');
|
4 | const connect = require('connect');
|
5 | const getPort = require('get-port');
|
6 | const http = require('http');
|
7 | const open = require('open');
|
8 | const serveStatic = require('serve-static');
|
9 | const bodyParser = require('body-parser');
|
10 | const parseurl = require('parseurl');
|
11 | const url = require('url');
|
12 | const assign = require('lodash').assign;
|
13 | const path = require('path');
|
14 | const resolve = path.resolve;
|
15 | const join = path.join;
|
16 | const fs = require('fs');
|
17 | const JSZip = require('jszip');
|
18 | const readFileSync = fs.readFileSync;
|
19 | const writeFileSync = fs.writeFileSync;
|
20 | const nunjucks = require('nunjucks');
|
21 | const renderString = nunjucks.renderString;
|
22 | const shelljs = require('shelljs');
|
23 | const webpack = require('webpack');
|
24 | const webpackConfig = require('../webpack.config');
|
25 | const pkg = require('../package.json');
|
26 | const blocks = require('./data/blocks.json');
|
27 | const template = require('./data/template');
|
28 |
|
29 | shelljs.config.execPath = shelljs.which('node');
|
30 |
|
31 | commander
|
32 | .version(pkg.version)
|
33 | .option('-w, --web')
|
34 | .option('-p, --port <port>', 'specify a port number to run on', parseInt)
|
35 | .parse(process.argv);
|
36 |
|
37 | function startService(port) {
|
38 | const server = connect();
|
39 | server
|
40 | .use(bodyParser.urlencoded({
|
41 | extended: true
|
42 | }))
|
43 | .use((req, res, next) => {
|
44 | const urlInfo = url.parse(req.url, true);
|
45 | const query = urlInfo.query || {};
|
46 | const body = req.body || {};
|
47 |
|
48 | req._urlInfo = urlInfo;
|
49 | req._pathname = urlInfo.pathname;
|
50 |
|
51 |
|
52 | const params = Object.assign({}, query, body);
|
53 | req._params = params;
|
54 | req._query = query;
|
55 | req._body = body;
|
56 |
|
57 | res._sendRes = (str, contentType) => {
|
58 | const buf = new Buffer(str);
|
59 | contentType = contentType || 'text/html;charset=utf-8';
|
60 | res.setHeader('Content-Type', contentType);
|
61 | res.setHeader('Content-Length', buf.length);
|
62 | res.end(buf);
|
63 | };
|
64 |
|
65 | res._JSONRes = data => {
|
66 | res._sendRes(JSON.stringify(data), 'application/json;charset=utf-8');
|
67 | };
|
68 |
|
69 |
|
70 | res._HTMLRes = res._sendRes;
|
71 |
|
72 | return next();
|
73 | })
|
74 | .use((req, res, next) => {
|
75 | const pathname = parseurl(req).pathname;
|
76 | if (req.method === 'GET') {
|
77 | if (pathname === '/bundler/index.html') {
|
78 | res.end(renderString(readFileSync(join(__dirname, './index.njk'), 'utf8'), {
|
79 | blocks
|
80 | }));
|
81 | } else {
|
82 | next();
|
83 | }
|
84 | } else if (req.method === 'POST') {
|
85 | if (pathname === '/bundle') {
|
86 |
|
87 | const entryPath = resolve(process.cwd(), './src/__index.js');
|
88 | const ids = req.body.ids.map(id => parseInt(id, 10));
|
89 | const codeBlocks = blocks
|
90 | .filter((item, index) => ids.indexOf(index) !== -1)
|
91 | .map(item => item.code)
|
92 | .join('\n');
|
93 | const entryFileContent = template(codeBlocks);
|
94 | writeFileSync(entryPath, template(codeBlocks), 'utf8');
|
95 |
|
96 | const distPath = resolve(process.cwd(), './__dist');
|
97 | shelljs.rm('-rf', distPath);
|
98 | shelljs.mkdir('-p', distPath);
|
99 | const config = Object.assign({}, webpackConfig);
|
100 | config.entry = {
|
101 | interaction: './src/__index.js'
|
102 | };
|
103 | config.output.path = distPath;
|
104 | webpack(config, (err, stats) => {
|
105 |
|
106 | if (err || stats.hasErrors()) {
|
107 |
|
108 |
|
109 | shelljs.rm(entryPath);
|
110 | shelljs.rm('-rf', distPath);
|
111 | }
|
112 |
|
113 | shelljs.exec('uglifyjs -c -m -o __dist/interaction.min.js -- __dist/interaction.js');
|
114 |
|
115 | const zip = new JSZip();
|
116 | zip.folder('interaction-dist').file('entry.js', entryFileContent);
|
117 | zip.folder('interaction-dist').file('interaction.js', readFileSync(join(distPath, './interaction.js'), 'utf8'));
|
118 | zip.folder('interaction-dist').file('interaction.js.map', readFileSync(join(distPath, './interaction.js.map'), 'utf8'));
|
119 | zip.folder('interaction-dist').file('interaction.min.js', readFileSync(join(distPath, './interaction.min.js'), 'utf8'));
|
120 | res.writeHead(200, {
|
121 | 'Content-Type': 'application/zip'
|
122 | });
|
123 | zip
|
124 | .generateNodeStream({ type: 'nodebuffer', streamFiles: true })
|
125 | .pipe(res)
|
126 | .on('finish', function() {
|
127 |
|
128 | shelljs.rm(entryPath);
|
129 | shelljs.rm('-rf', distPath);
|
130 | res.end();
|
131 | });
|
132 | });
|
133 | }
|
134 | } else {
|
135 | next();
|
136 | }
|
137 | });
|
138 | server.use(serveStatic(process.cwd()));
|
139 | http.createServer(server).listen(port);
|
140 |
|
141 | const urlPath = `http://127.0.0.1:${port}/bundler/index.html`;
|
142 | debug(`server started, bundler available! ${urlPath}`);
|
143 |
|
144 | if (commander.web) {
|
145 | debug('running on web!');
|
146 | open(urlPath);
|
147 | } else {
|
148 | debug('running on electron!');
|
149 | const app = require('electron').app;
|
150 | const BrowserWindow = require('electron').BrowserWindow;
|
151 | const windowBoundsConfig = require('torchjs/lib/windowBoundsConfig')(
|
152 | resolve(app.getPath('userData'), './g2-bundler-config.json')
|
153 | );
|
154 |
|
155 | let win;
|
156 | app.once('ready', () => {
|
157 | win = new BrowserWindow(assign({
|
158 |
|
159 | webPreferences: {
|
160 | nodeIntegration: false
|
161 | }
|
162 | }, windowBoundsConfig.get('bundler')));
|
163 | win.loadURL(urlPath);
|
164 |
|
165 | win.on('close', () => {
|
166 | windowBoundsConfig.set('bundler', win.getBounds());
|
167 | });
|
168 | win.on('closed', () => {
|
169 | win = null;
|
170 | });
|
171 | });
|
172 | app.on('window-all-closed', () => {
|
173 | app.quit();
|
174 | });
|
175 | }
|
176 | }
|
177 |
|
178 | if (commander.port) {
|
179 | startService(commander.port);
|
180 | } else {
|
181 | getPort().then(port => {
|
182 | startService(port);
|
183 | });
|
184 | }
|