Skip to content

Commit e74f1fd

Browse files
committed
feat(server): report bundler error by overlay
1 parent 92a020f commit e74f1fd

File tree

8 files changed

+247
-5
lines changed

8 files changed

+247
-5
lines changed

lib/commands/server.js

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ var connect = require('connect'),
88
fs = require('fs'),
99
http = require('http'),
1010
https = require('https'),
11+
socketIO = require('socket.io'),
1112
serveStatic = require('serve-static'),
1213
serveIndex = require('serve-index'),
1314
moment = require('moment'),
@@ -54,6 +55,9 @@ exports.run = function (options) {
5455
allAssetsEntry = {},
5556
watchCacheNames = {};
5657

58+
var io = null,
59+
assetEntrys = {};
60+
5761
var usingHotServer = false;
5862
var dateFormat = 'HH:mm:ss';
5963

@@ -264,6 +268,13 @@ exports.run = function (options) {
264268
config.plugins.push(require('../plugins/compileInfoPlugin.js'));
265269

266270
nextConfig = extend({}, config);
271+
272+
// 注入 sockitIO
273+
nextConfig.module.postLoaders.push({
274+
test: /\.(js)$/,
275+
loader: sysPath.join(__dirname, '../modules/SocketClientLoader.js?cacheId=' + cacheId)
276+
});
277+
267278
if (shouldCompileAllEntries) {
268279
return nextConfig;
269280
} else {
@@ -365,8 +376,8 @@ exports.run = function (options) {
365376
var state = _ref.state,
366377
stats = _ref.stats;
367378

379+
// 打印编译完成时间(小于 100ms 不展示)
368380
if (!stats.hasErrors() && !stats.hasWarnings()) {
369-
// 打印编译完成时间(过小的不展示)
370381
var minDuration = 100;
371382
if (stats.endTime - stats.startTime > minDuration) {
372383
var dateLog = '[' + moment().format(dateFormat) + ']';
@@ -378,6 +389,13 @@ exports.run = function (options) {
378389
spinner.stop();
379390
spinner.text = '';
380391

392+
// emit compile info by socket
393+
var statsInfo = stats.toJson({ errorDetails: false });
394+
assetEntrys[cacheId] = {
395+
compilationId: statsInfo.hash,
396+
errors: statsInfo.errors
397+
};
398+
381399
Object.keys(stats.compilation.assets).map(function (key) {
382400
var keyCacheId = sysPath.join(projectName, key);
383401
middlewareCache[keyCacheId] = middleware;
@@ -390,11 +408,13 @@ exports.run = function (options) {
390408
resolve();
391409
}
392410
});
411+
393412
if (hot) {
394413
app.use(require('webpack-hot-middleware')(compiler, {
395414
log: false
396415
}));
397416
}
417+
398418
middleware(req, res, next);
399419
}
400420

@@ -429,6 +449,7 @@ exports.run = function (options) {
429449
servers.push(extend(https.createServer(httpsOpts, app), { _port: '443', _isHttps: true }));
430450
}
431451

452+
// setup server
432453
servers.forEach(function (server) {
433454
server.on('error', function (e) {
434455
if (e.code === 'EACCES') {
@@ -438,15 +459,26 @@ exports.run = function (options) {
438459
}
439460
process.exit(1);
440461
});
462+
441463
server.listen(server._port, function () {
442464
var serverUrl = (server._isHttps ? 'https' : 'http') + '://127.0.0.1:' + server._port;
443465

444466
!server._isHttps && log('Starting up server, serving at: ' + options.cwd);
445467
logInfo('Available on: ' + serverUrl.underline);
468+
469+
// socket
470+
if (!server._isHttps) {
471+
io = socketIO(server);
472+
io.on('connection', function (socket) {
473+
setInterval(function () {
474+
io && io.volatile.emit('testAppID', assetEntrys);
475+
}, 500);
476+
});
477+
}
446478
});
447479
});
448480

449-
// 代理
481+
// proxy
450482
var proxyProcess;
451483
if (proxy) {
452484
var proxyPath = sysPath.join(requireg.resolve('jerryproxy'), '../bin/jerry.js');

lib/modules/SocketClientLoader.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
'use strict';
2+
3+
var UglifyJS = require('uglify-js');
4+
5+
module.exports = function (content) {
6+
var embedScript = '';
7+
8+
if (!this._compiler.overLayPath || this._compiler.overLayPath === this.resourcePath) {
9+
this._compiler.overLayPath = this.resourcePath;
10+
11+
// 去除形如 index.scss.js 的文件
12+
var basename = sysPath.basename(this.resourcePath, '.js');
13+
var isNotPkg = this.resourcePath.indexOf('node_modules') === -1;
14+
15+
if (sysPath.extname(this.resourcePath) === '.js' && sysPath.extname(basename).length === 0 && isNotPkg) {
16+
var socketScript = fs.readFileSync(sysPath.join(__dirname, '../../static/SocketEmbedment.js'), { encoding: 'utf-8' });
17+
var overlayScript = fs.readFileSync(sysPath.join(__dirname, '../../static/SocketOverlay.js'), { encoding: 'utf-8' });
18+
overlayScript = UglifyJS.minify(overlayScript, {
19+
fromString: true,
20+
mangle: true
21+
}).code;
22+
23+
var cacheId = this.query.replace('?cacheId=', '');
24+
embedScript = socketScript.replace('@OVERLAY_SCRIPT', overlayScript).replace('@COMPILING_ASSET', cacheId);
25+
}
26+
}
27+
28+
return embedScript + content;
29+
};

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"serve-index": "^1.8.0",
5151
"serve-static": "^1.11.1",
5252
"shelljs": "^0.7.5",
53+
"socket.io": "1.7.3",
5354
"style-loader": "^0.13.1",
5455
"through2": "^2.0.1",
5556
"uglify-js": "2.7.5",

src/commands/server.js

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const connect = require('connect'),
44
fs = require('fs'),
55
http = require('http'),
66
https = require('https'),
7+
socketIO = require('socket.io'),
78
serveStatic = require('serve-static'),
89
serveIndex = require('serve-index'),
910
moment = require('moment'),
@@ -50,6 +51,9 @@ exports.run = (options) => {
5051
allAssetsEntry = {},
5152
watchCacheNames = {};
5253

54+
let io = null,
55+
assetEntrys = {};
56+
5357
let usingHotServer = false;
5458
const dateFormat = 'HH:mm:ss';
5559

@@ -260,6 +264,13 @@ exports.run = (options) => {
260264
config.plugins.push(require('../plugins/compileInfoPlugin.js'));
261265

262266
nextConfig = extend({}, config);
267+
268+
// 注入 sockitIO
269+
nextConfig.module.postLoaders.push({
270+
test: /\.(js)$/,
271+
loader: sysPath.join(__dirname, '../modules/SocketClientLoader.js?cacheId=' + cacheId)
272+
});
273+
263274
if(shouldCompileAllEntries) {
264275
return nextConfig;
265276
} else {
@@ -364,8 +375,8 @@ exports.run = (options) => {
364375
compiler,
365376
{
366377
quiet: true, reporter: ({state, stats}) => {
378+
// 打印编译完成时间(小于 100ms 不展示)
367379
if(!stats.hasErrors() && !stats.hasWarnings()) {
368-
// 打印编译完成时间(过小的不展示)
369380
const minDuration = 100;
370381
if(stats.endTime - stats.startTime > minDuration) {
371382
const dateLog = '[' + moment().format(dateFormat) + ']';
@@ -377,6 +388,13 @@ exports.run = (options) => {
377388
spinner.stop();
378389
spinner.text = '';
379390

391+
// emit compile info by socket
392+
const statsInfo = stats.toJson({errorDetails: false});
393+
assetEntrys[cacheId] = {
394+
compilationId: statsInfo.hash,
395+
errors: statsInfo.errors
396+
};
397+
380398
Object.keys(stats.compilation.assets).map((key) => {
381399
const keyCacheId = sysPath.join(projectName, key);
382400
middlewareCache[keyCacheId] = middleware;
@@ -390,11 +408,13 @@ exports.run = (options) => {
390408
}
391409
}
392410
);
411+
393412
if(hot) {
394413
app.use(require('webpack-hot-middleware')(compiler, {
395414
log: false
396415
}));
397416
}
417+
398418
middleware(req, res, next);
399419
}
400420

@@ -429,6 +449,7 @@ exports.run = (options) => {
429449
servers.push(extend(https.createServer(httpsOpts, app), { _port: '443', _isHttps: true }));
430450
}
431451

452+
// setup server
432453
servers.forEach((server) => {
433454
server.on('error', (e) => {
434455
if (e.code === 'EACCES') {
@@ -438,17 +459,28 @@ exports.run = (options) => {
438459
}
439460
process.exit(1);
440461
});
462+
441463
server.listen(server._port, () => {
442464
const serverUrl = (server._isHttps ? 'https' : 'http')
443465
+ '://127.0.0.1:'
444466
+ server._port;
445467

446468
!server._isHttps && log('Starting up server, serving at: ' + options.cwd);
447469
logInfo('Available on: ' + serverUrl.underline);
470+
471+
// socket
472+
if(!server._isHttps) {
473+
io = socketIO(server);
474+
io.on('connection', function(socket) {
475+
setInterval(function() {
476+
io && io.volatile.emit('testAppID', assetEntrys);
477+
}, 500);
478+
});
479+
}
448480
});
449481
});
450482

451-
// 代理
483+
// proxy
452484
var proxyProcess;
453485
if (proxy) {
454486
const proxyPath = sysPath.join(requireg.resolve('jerryproxy'), '../bin/jerry.js');

src/modules/SocketClientLoader.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const UglifyJS = require('uglify-js');
2+
3+
module.exports = function (content) {
4+
let embedScript = '';
5+
6+
if((!this._compiler.overLayPath) || this._compiler.overLayPath === this.resourcePath) {
7+
this._compiler.overLayPath = this.resourcePath;
8+
9+
// 去除形如 index.scss.js 的文件
10+
const basename = sysPath.basename(this.resourcePath, '.js');
11+
const isNotPkg = this.resourcePath.indexOf('node_modules') === -1;
12+
13+
if(sysPath.extname(this.resourcePath) === '.js' && sysPath.extname(basename).length === 0 && isNotPkg) {
14+
const socketScript = fs.readFileSync(sysPath.join(__dirname, '../../static/SocketEmbedment.js'), {encoding: 'utf-8'});
15+
let overlayScript = fs.readFileSync(sysPath.join(__dirname, '../../static/SocketOverlay.js'), {encoding: 'utf-8'});
16+
overlayScript = UglifyJS.minify(overlayScript, {
17+
fromString: true,
18+
mangle: true
19+
}).code;
20+
21+
const cacheId = this.query.replace('?cacheId=', '');
22+
embedScript = socketScript
23+
.replace('@OVERLAY_SCRIPT', overlayScript)
24+
.replace('@COMPILING_ASSET', cacheId);
25+
}
26+
}
27+
28+
return embedScript + content;
29+
};

static/SocketEmbedment.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
;(function(global){
2+
var compilingAsset = '@COMPILING_ASSET';
3+
4+
if(global._ykit_assets) {
5+
global._ykit_assets.push(compilingAsset);
6+
} else {
7+
global._ykit_assets = [compilingAsset];
8+
}
9+
10+
if(!global.socketIO) {
11+
var socketIO = global.socketIO = document.createElement('script');
12+
socketIO.src = '/socket.io/socket.io.js';
13+
document.body.appendChild(socketIO);
14+
15+
socketIO.onload = function() {
16+
var socketClient = document.createElement('script');
17+
socketClient.innerHTML = '@OVERLAY_SCRIPT';
18+
document.body.appendChild(socketClient);
19+
}
20+
}
21+
})(window);

0 commit comments

Comments
 (0)