app.js 6.0 KB

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