mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-17 04:41:36 +08:00
chore: implement basic devServer
This commit is contained in:
71
packages/webpack5/src/bin/devServer.ts
Normal file
71
packages/webpack5/src/bin/devServer.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { createServer } from 'http'
|
||||
// import { spawn } from 'child_process'
|
||||
// yarn --cwd /Users/rigor789/Code/echo-server start
|
||||
|
||||
// let statuses: {
|
||||
// [hash: string]: IHMRStatusData
|
||||
// } = {}
|
||||
|
||||
export interface IHMRStatusData {
|
||||
seq: number
|
||||
uuid: string,
|
||||
hash: string
|
||||
status: string
|
||||
}
|
||||
|
||||
export function run() {
|
||||
createServer((req, res) => {
|
||||
if (req.url === '/ping') {
|
||||
console.log('PING -> PONG!')
|
||||
return res.end("Pong.");
|
||||
}
|
||||
|
||||
if (req.method !== 'POST') {
|
||||
res.statusCode = 400;
|
||||
return res.end("Unsupported method.");
|
||||
}
|
||||
|
||||
let data = "";
|
||||
req.on("data", chunk => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
req.on("end", () => {
|
||||
try {
|
||||
const signal = JSON.parse(data) as IHMRStatusData;
|
||||
// if (!statuses[signal.hash] || statuses[signal.hash].seq < signal.seq) {
|
||||
// statuses[signal.hash] = signal
|
||||
// }
|
||||
if (process.send) {
|
||||
process.send({
|
||||
type: 'hmr-status',
|
||||
version: 1,
|
||||
hash: signal.hash,
|
||||
data: signal
|
||||
}, (error) => {
|
||||
if (error) {
|
||||
console.error(`Process Send Error: `, error);
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
res.end('ok.');
|
||||
} catch (e) {
|
||||
res.statusCode = 400;
|
||||
res.end("Invalid JSON.");
|
||||
}
|
||||
});
|
||||
}).listen(8238)
|
||||
|
||||
// spawn('/Users/rigor789/Code/echo-server/node_modules/.bin/ts-node', ['/Users/rigor789/Code/echo-server/index.ts'], {
|
||||
// cwd: '/Users/rigor789/Code/echo-server/',
|
||||
// stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
|
||||
// }).on('message', function (data) {
|
||||
// console.log({
|
||||
// messageFromEchoServer: data
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
import { parseEnvFlags } from '../cli/parseEnvFlags';
|
||||
import { run } from "./devServer";
|
||||
|
||||
const defaultConfig = path.resolve(
|
||||
__dirname,
|
||||
@ -43,9 +44,10 @@ program
|
||||
program
|
||||
.command('build')
|
||||
.description('Build...')
|
||||
.option('--env [name]', 'environment options')
|
||||
.option('--hmr', 'enable HMR')
|
||||
.option('--no-hmr', 'disable HMR')
|
||||
.option('--env [name]', 'environment name')
|
||||
.option('--config [path]', 'config path')
|
||||
// .option('--hmr', 'enable HMR')
|
||||
// .option('--no-hmr', 'disable HMR')
|
||||
.option('--watch', 'watch for changes')
|
||||
.allowUnknownOption()
|
||||
.action((options, command) => {
|
||||
@ -56,47 +58,69 @@ program
|
||||
if (options.env) {
|
||||
env['env'] = options.env;
|
||||
}
|
||||
// const env = {
|
||||
// platform: 'ios',
|
||||
// verbose: true,
|
||||
// appResourcesPath: 'App_Resources',
|
||||
// appPath: 'src'
|
||||
// }
|
||||
|
||||
const configPath = path.resolve(process.cwd(), 'webpack.config.js');
|
||||
const configPath = (() => {
|
||||
if (options.config) {
|
||||
return path.resolve(options.config);
|
||||
}
|
||||
|
||||
return path.resolve(process.cwd(), 'webpack.config.js')
|
||||
})();
|
||||
|
||||
// todo: validate config exists
|
||||
// todo: guard against invalid config
|
||||
let configuration;
|
||||
let configuration: webpack.Configuration;
|
||||
try {
|
||||
configuration = require(configPath)(env);
|
||||
} catch (ignore) {
|
||||
console.log(ignore);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
if (!configuration) {
|
||||
console.log('No configuration!!!!!');
|
||||
console.log('No configuration!');
|
||||
return;
|
||||
}
|
||||
|
||||
const compiler = webpack(configuration);
|
||||
|
||||
// todo: handle --watch flag
|
||||
// todo: promisify callback?
|
||||
compiler.watch(
|
||||
{
|
||||
ignored: ['platforms'],
|
||||
},
|
||||
(err, stats) => {
|
||||
const webpackCompilationCallback = (err: webpack.WebpackError, stats: webpack.Stats) => {
|
||||
if (err) {
|
||||
// Do not keep cache anymore
|
||||
compiler.purgeInputFileSystem();
|
||||
|
||||
console.error(err.stack || err);
|
||||
if (err.details) {
|
||||
console.error(err.details);
|
||||
}
|
||||
|
||||
process.exitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (stats) {
|
||||
console.log(
|
||||
stats.toString({
|
||||
chunks: false,
|
||||
colors: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
// err && console.log(err)
|
||||
}
|
||||
|
||||
if (options.watch) {
|
||||
// run dev server
|
||||
run();
|
||||
|
||||
console.log('webpack is watching the files...')
|
||||
compiler.watch(
|
||||
configuration.watchOptions ?? {},
|
||||
webpackCompilationCallback
|
||||
);
|
||||
} else {
|
||||
compiler.run(
|
||||
webpackCompilationCallback
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
program.parse(process.argv);
|
||||
|
@ -1,4 +1,5 @@
|
||||
import dedent from 'ts-dedent';
|
||||
import { env } from "@nativescript/webpack";
|
||||
|
||||
// de-indents strings so multi-line string literals can be used
|
||||
function cleanup(data: any[]) {
|
||||
@ -28,8 +29,10 @@ export function warn(...data: any): void {
|
||||
}
|
||||
|
||||
export function info(...data: any): void {
|
||||
if(env.verbose) {
|
||||
console.log(`[@nativescript/webpack] Info: \n`, ...cleanup(data));
|
||||
}
|
||||
}
|
||||
|
||||
// todo: refine
|
||||
// export function error(message: string, info?: { possibleCauses?: string[] }) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { dirname, resolve } from 'path';
|
||||
|
||||
import { getPackageJson, getProjectRootPath } from './project';
|
||||
import { error } from './log';
|
||||
import { error, info } from './log';
|
||||
import { env } from '../';
|
||||
|
||||
import AndroidPlatform from '../platforms/android';
|
||||
@ -29,7 +29,7 @@ const platforms: {
|
||||
* @param platform A platform definition of the platform specifics
|
||||
*/
|
||||
export function addPlatform(name: string, platform: INativeScriptPlatform) {
|
||||
console.log('adding platform', name, platform);
|
||||
info(`Adding platform ${name}`, platform);
|
||||
platforms[name] = platform;
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,13 @@
|
||||
// todo: log correct message format for CLI to pick up
|
||||
// todo: build CLI service to listen for state changes
|
||||
// ---
|
||||
import { Http } from '@nativescript/core'
|
||||
|
||||
import type { IHMRStatusData } from "../../bin/devServer";
|
||||
import { Http, Device } from '@nativescript/core'
|
||||
|
||||
const uuid = Device.uuid;
|
||||
|
||||
console.log(`[HMR] uuid = ${uuid}`)
|
||||
|
||||
let __NS_DEV_HOST_URL__;
|
||||
Promise.race(__NS_DEV_HOST_IPS__
|
||||
@ -11,7 +17,7 @@ Promise.race(__NS_DEV_HOST_IPS__
|
||||
.map(async url => {
|
||||
await Http.request({
|
||||
method: 'get',
|
||||
url
|
||||
url: url + 'ping'
|
||||
})
|
||||
|
||||
return url;
|
||||
@ -19,47 +25,63 @@ Promise.race(__NS_DEV_HOST_IPS__
|
||||
__NS_DEV_HOST_URL__ = winner
|
||||
})
|
||||
|
||||
let __SEQ = 0;
|
||||
|
||||
if (module.hot) {
|
||||
module.hot.dispose(() => {
|
||||
console.log('Disposing entry file?!')
|
||||
// require('@nativescript/core').Application.resetRootView()
|
||||
})
|
||||
|
||||
const orig = global.__onLiveSync
|
||||
const log = (type, info) => {
|
||||
console.log(`[nds] HMR ${type}:`, info)
|
||||
// console.log(__NS_DEV_HOST_IPS__[0])
|
||||
|
||||
const send = (content: object) => {
|
||||
if (__NS_DEV_HOST_URL__) {
|
||||
Http.request({
|
||||
method: 'post',
|
||||
url: __NS_DEV_HOST_URL__,
|
||||
content: JSON.stringify({
|
||||
type,
|
||||
info
|
||||
})
|
||||
content: JSON.stringify(content)
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const sendStatus = (status, hash) => {
|
||||
send({
|
||||
seq: __SEQ++,
|
||||
uuid,
|
||||
hash,
|
||||
status
|
||||
} as IHMRStatusData)
|
||||
}
|
||||
|
||||
const orig = global.__onLiveSync
|
||||
const log = (type, info) => {
|
||||
// console.log(`[nds] HMR ${type}:`, info)
|
||||
}
|
||||
|
||||
log('init')
|
||||
|
||||
module.hot.addStatusHandler(status => {
|
||||
log('status', status)
|
||||
// sendStatus(status)
|
||||
})
|
||||
|
||||
global.__onLiveSync = async function () {
|
||||
// handle hot updated on LiveSync
|
||||
console.log('~~~ livesynced ~~~')
|
||||
// handle hot updates on LiveSync
|
||||
console.log('~~~ livesync ~~~')
|
||||
|
||||
log('checking')
|
||||
|
||||
const hash = __webpack_require__.h();
|
||||
|
||||
await module.hot.check().catch(err => {
|
||||
log('checking-failed', err)
|
||||
sendStatus('failure', hash)
|
||||
});
|
||||
|
||||
log('checked')
|
||||
log('applying')
|
||||
|
||||
await module.hot.apply({
|
||||
ignoreUnaccepted: false,
|
||||
ignoreDeclined: false,
|
||||
@ -67,9 +89,11 @@ if(module.hot) {
|
||||
|
||||
onDeclined(info) {
|
||||
log('declined', info)
|
||||
sendStatus('failure', hash);
|
||||
},
|
||||
onUnaccepted(info) {
|
||||
log('unaccepted', info)
|
||||
sendStatus('failure', hash);
|
||||
},
|
||||
onAccepted(info) {
|
||||
log('accepted', info)
|
||||
@ -79,10 +103,15 @@ if(module.hot) {
|
||||
},
|
||||
onErrored(info) {
|
||||
log('errored', info)
|
||||
sendStatus('failure', hash);
|
||||
}
|
||||
}).then(() => {
|
||||
sendStatus('success', hash)
|
||||
}).catch((err) => {
|
||||
sendStatus('failure', hash)
|
||||
log('applying-failed', err)
|
||||
})
|
||||
|
||||
// log('applying')
|
||||
// await module.hot.apply()
|
||||
log('applying-done')
|
||||
|
@ -34,10 +34,6 @@ export class PlatformSuffixPlugin {
|
||||
}
|
||||
|
||||
apply(compiler: any) {
|
||||
console.log(
|
||||
// this.extensions,
|
||||
this.platform
|
||||
);
|
||||
const platformRE = new RegExp(`\.${this.platform}\.`);
|
||||
|
||||
// require.context
|
||||
|
@ -1,5 +1,6 @@
|
||||
const id = 'WatchStatePlugin';
|
||||
const version = 1;
|
||||
const DEBUG = false;
|
||||
|
||||
export enum messages {
|
||||
compilationComplete = 'Webpack compilation complete.',
|
||||
@ -12,8 +13,6 @@ export enum messages {
|
||||
* So the {N} CLI can get some idea when compilation completes.
|
||||
*/
|
||||
export class WatchStatePlugin {
|
||||
isRunningWatching: boolean;
|
||||
|
||||
apply(compiler: any) {
|
||||
let isWatchMode = false;
|
||||
let prevAssets = [];
|
||||
@ -21,8 +20,24 @@ export class WatchStatePlugin {
|
||||
compiler.hooks.watchRun.tapAsync(id, function (compiler, callback) {
|
||||
callback();
|
||||
|
||||
isWatchMode = true;
|
||||
if (isWatchMode) {
|
||||
console.log(messages.changeDetected);
|
||||
|
||||
if (DEBUG) {
|
||||
if (compiler.modifiedFiles) {
|
||||
Array.from(compiler.modifiedFiles).forEach(file => {
|
||||
console.log(`MODIFIED: ${file}`)
|
||||
})
|
||||
}
|
||||
|
||||
if (compiler.removedFiles) {
|
||||
Array.from(compiler.removedFiles).forEach(file => {
|
||||
console.log(`REMOVED: ${file}`)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
isWatchMode = true;
|
||||
});
|
||||
|
||||
compiler.hooks.afterEmit.tapAsync(id, function (compilation, callback) {
|
||||
@ -53,21 +68,23 @@ export class WatchStatePlugin {
|
||||
notify({
|
||||
type: 'compilation',
|
||||
version,
|
||||
hash: compilation.hash,
|
||||
|
||||
data: {
|
||||
emittedAssets,
|
||||
staleAssets,
|
||||
hash: compilation.hash,
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function notify(message: any) {
|
||||
DEBUG && console.log(`[${id}] Notify: `, message);
|
||||
if (!process.send) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[${id}] Notify: `, message);
|
||||
process.send(message, (error) => {
|
||||
if (error) {
|
||||
console.error(`[${id}] Process Send Error: `, error);
|
||||
|
Reference in New Issue
Block a user