Doric cli: add dev

This commit is contained in:
pengfeizhou 2021-02-05 18:20:42 +08:00 committed by osborn
parent a9cfd8b41a
commit d4c8d08660
6 changed files with 205 additions and 12 deletions

View File

@ -17,16 +17,21 @@ export async function clean() {
await Shell.exec("rm", ["-rf", "bundle"]);
}
export async function doMerge(jsFile: string) {
const mappingFile = `${jsFile}.map`;
async function doMerge(jsFile: string) {
const mapFile = `${jsFile}.map`;
console.log(`Bundle -> ${jsFile.green}`);
if (!fs.existsSync(mappingFile)) {
if (!fs.existsSync(mapFile)) {
return;
}
console.log(` -> ${mappingFile.green}`);
const mergedMap = createMergedSourceMapFromFiles([
mappingFile.replace(/bundle\//, 'build/'),
mappingFile,
], true);
await fs.promises.writeFile(mappingFile, mergedMap);
console.log(` -> ${mapFile.green}`);
await mergeMap(mapFile);
}
export async function mergeMap(mapFile: string) {
const mergedMap = createMergedSourceMapFromFiles([
mapFile.replace(/bundle\//, 'build/'),
mapFile,
], true);
await fs.promises.writeFile(mapFile, mergedMap);
}

99
doric-cli/src/dev.ts Normal file
View File

@ -0,0 +1,99 @@
import { exec } from "child_process"
import chokidar from "chokidar";
import { createServer } from "./server"
import { delay } from "./util";
import fs from "fs";
import { mergeMap } from "./actions";
import os from "os";
import qrcode from "qrcode-terminal";
import keypress from "keypress";
function getIPAdress() {
const ret: string[] = [];
const interfaces = os.networkInterfaces();
Object.entries(interfaces).map(e => e[1])
.forEach(e => {
if (!!!e) {
return;
}
e.forEach(e => {
if (
e.family === "IPv4" &&
e.address !== "127.0.0.1" &&
!e.internal
) {
ret.push(e.address);
}
})
});
return ret;
}
export default async function dev() {
const server = await createServer()
const tscProcess = exec("node node_modules/.bin/tsc -w -p .");
const rollupProcess = exec("node node_modules/.bin/rollup -c -w");
console.warn("Waiting ...");
const ips = getIPAdress();
ips.forEach((e) => {
console.log(`IP:${e}`);
qrcode.generate(e, { small: true });
});
keypress(process.stdin);
process.stdin.on("keypress", function (ch, key) {
if (key && key.ctrl && key.name == "r") {
ips.forEach((e) => {
console.log(`IP:${e}`);
qrcode.generate(e, { small: true });
});
}
if (key && key.ctrl && key.name == "c") {
process.stdin.pause();
tscProcess.kill("SIGABRT");
rollupProcess.kill("SIGABRT");
process.exit(0);
}
});
process.stdin.setRawMode(true);
process.stdin.resume();
await delay(3000);
console.warn("Start watching");
server.listen(7777);
chokidar
.watch(process.cwd() + "/bundle", {
ignored: /.*?\.map/,
alwaysStat: true,
})
.on("change", (jsFile) => {
console.log("*******", jsFile.replace(process.cwd(), "")
.replace("/bundle/src/", "")
.replace(".js", "")
.green, "*******")
if ((server as any).debugging) {
console.log("debugging, hot reload by pass");
return;
}
fs.readFile(jsFile, "utf-8", (error, data) => {
try {
const sourceMap = mergeMap(`${jsFile}.map`);
server.connections.forEach((e: any) => {
e.sendText(
JSON.stringify({
cmd: "RELOAD",
script: data,
source: (jsFile.match(/[^/\\]*$/) || [""])[0],
sourceMap,
})
);
});
} catch (e) {
console.error(e);
}
});
});
}

View File

@ -3,7 +3,7 @@
import commander from "commander"
import { build, clean } from "./actions";
import create from "./create"
import dev from "./dev"
commander
.command('create <name>')
.action(async function (name, cmd) {
@ -16,7 +16,8 @@ commander
})
commander
.command('dev')
.action(function () {
.action(async function () {
await dev()
})
commander
.command('build')

View File

@ -1 +1,4 @@
declare module 'source-map-merger'
declare module 'source-map-merger'
declare module 'nodejs-websocket'
declare module 'qrcode-terminal'
declare module 'keypress'

77
doric-cli/src/server.ts Normal file
View File

@ -0,0 +1,77 @@
import fs from "fs";
import { exec, spawn } from "child_process";
import ws from "nodejs-websocket";
import "colors";
export async function createServer() {
console.log("Create Server")
let contextId: string = "0"
let clientConnection: any = null
let debuggerConnection: any = null
const server = (ws as any).createServer((connection: any) => {
console.log('Connected', connection.headers.host)
if (connection.headers.host.startsWith("localhost")) {
console.log(`Debugger ${connection.key} attached to dev kit`.green)
debuggerConnection = connection
clientConnection.sendText(JSON.stringify({
cmd: 'SWITCH_TO_DEBUG',
contextId: contextId
}), () => { })
} else {
console.log(`Client ${connection.key} attached to dev kit`.green)
}
connection.on('text', function (result: string) {
let resultObject = JSON.parse(result)
switch (resultObject.cmd) {
case 'DEBUG':
clientConnection = connection;
(server as any).debugging = true;
console.log("Enter debugging");
contextId = resultObject.data.contextId;
let projectHome = '.';
fs.writeFileSync(projectHome + '/build/context', contextId, 'utf8');
let source = resultObject.data.source;
console.log(connection.key + " request debug, project home: " + projectHome);
spawn('code', [projectHome, projectHome + "/src/" + source]);
setTimeout(() => {
exec('osascript -e \'tell application "System Events"\ntell application "Visual Studio Code" to activate\nkey code 96\nend tell\'', (err, stdout, stderr) => {
if (err) {
console.log(`stdout: ${err}`)
}
})
}, 1500);
break;
case 'EXCEPTION':
console.log(resultObject.data.source.red);
console.log(resultObject.data.exception.red);
break;
case 'LOG':
if (resultObject.data.type == 'DEFAULT') {
console.log((resultObject.data.message as string).green);
} else if (resultObject.data.type == 'ERROR') {
console.log((resultObject.data.message as string).red);
} else if (resultObject.data.type == 'WARN') {
console.log((resultObject.data.message as string).yellow);
}
break
}
})
connection.on('connect', function (code: number) {
console.log('connect', code)
})
connection.on('close', function (code: number) {
console.log('close: code = ' + code, connection.key)
console.log("quit debugging");
(server as any).debugging = false
})
connection.on('error', function (code: number) {
console.log('error', code)
})
})
return server
}

View File

@ -1,5 +1,13 @@
import globLib, { IOptions } from "glob";
export async function delay(timeout: number) {
return new Promise((resolve) => {
setTimeout(() => {
resolve('');
}, timeout);
});
}
export function getAssetsDir() {
return `${__dirname}/../assets`;
}