UNPKG

6.23 kBJavaScriptView Raw
1process.env.DEBUG = 'app:*';
2const debug = require('debug')('app:demos');
3const commander = require('commander');
4const connect = require('connect');
5const getPort = require('get-port');
6const http = require('http');
7const open = require('open');
8const serveStatic = require('serve-static');
9const bodyParser = require('body-parser');
10const parseurl = require('parseurl');
11const url = require('url');
12const assign = require('lodash').assign;
13const path = require('path');
14const resolve = path.resolve;
15const join = path.join;
16const fs = require('fs');
17const JSZip = require('jszip');
18const readFileSync = fs.readFileSync;
19const writeFileSync = fs.writeFileSync;
20const nunjucks = require('nunjucks');
21const renderString = nunjucks.renderString;
22const shelljs = require('shelljs');
23const webpack = require('webpack');
24const webpackConfig = require('../webpack.config');
25const pkg = require('../package.json');
26const blocks = require('./data/blocks.json');
27const template = require('./data/template');
28
29shelljs.config.execPath = shelljs.which('node');
30
31commander
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
37function startService(port) {
38 const server = connect();
39 server
40 .use(bodyParser.urlencoded({
41 extended: true
42 }))
43 .use((req, res, next) => { // pre-handlers
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 // add req._params (combination of query and body)
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 // res._JSONRes(data) (generate JSON response)
65 res._JSONRes = data => {
66 res._sendRes(JSON.stringify(data), 'application/json;charset=utf-8');
67 };
68 // TODO res._JSONError()
69 // res._HTMLRes(data) (generate HTML response)
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 // step1: prepare entry __index.js
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 // step2: build it
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 'data-set': './src/__index.js'
102 };
103 config.output.path = distPath;
104 webpack(config, (err, stats) => {
105 // shelljs.rm(entryPath);
106 if (err || stats.hasErrors()) {
107 // Handle errors here
108 // shelljs.rm('-rf', distPath);
109 shelljs.rm(entryPath);
110 shelljs.rm('-rf', distPath);
111 }
112 // step3: uglify
113 shelljs.exec('uglifyjs -c -m -o __dist/data-set.min.js -- __dist/data-set.js');
114 // step4: zipping it
115 const zip = new JSZip();
116 zip.folder('data-set-dist').file('entry.js', entryFileContent);
117 zip.folder('data-set-dist').file('data-set.js', readFileSync(join(distPath, './data-set.js'), 'utf8'));
118 zip.folder('data-set-dist').file('data-set.js.map', readFileSync(join(distPath, './data-set.js.map'), 'utf8'));
119 zip.folder('data-set-dist').file('data-set.min.js', readFileSync(join(distPath, './data-set.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 // step5: clear up
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('@lite-js/torch/lib/windowBoundsConfig')(
152 resolve(app.getPath('userData'), './data-set-bundler-config.json')
153 );
154
155 let win;
156 app.once('ready', () => {
157 win = new BrowserWindow(assign({
158 // transparent: true
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
178if (commander.port) {
179 startService(commander.port);
180} else {
181 getPort().then(port => {
182 startService(port);
183 });
184}