Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v9.0.0 / 2023-09-19 #304

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ build: off

environment:
matrix:
- nodejs_version: '20'
- nodejs_version: '18'
- nodejs_version: '16'
- nodejs_version: '14'

install:
- ps: Install-Product node $env:nodejs_version
Expand Down
33 changes: 26 additions & 7 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@ on:

jobs:
build_ubuntu:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: ["14.x", "16.x", "18.x"]
node-version: ["18.x", "20.x"]

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm i
Expand All @@ -29,13 +28,33 @@ jobs:

strategy:
matrix:
node-version: ["14.x", "16.x", "18.x"]
node-version: ["18.x", "20.x"]

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm i
- run: npm test

lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: 20
- run: npm i
- run: npm run lint

prettier:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: 20
- run: npm i
- run: npm run prettier
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ jobs:
script: npm run lint
language: node_js
node_js:
- 20
- 18
- 16
- 14
sudo: false
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# node-dev

## v9.0.0 / 2023-09-16

- Drop support for node v14 and v16, the new minimum version of node is v18 (@bjornstar)
- Add support for node v20 (@bjornstar)
- Removed tests for `experimental-specifier-resolution` as it's no longer supported (@bjornstar)
- [CI] Test v18 & v20 (@bjornstar)
- [CI] Perform linting and prettier in github actions (@bjornstar)
- [`devDependencies`] Update most devDependencies to their latest version (@bjornstar)

## v8.0.0 / 2022-12-30

- Suppress experimental warnings in node v18 (@tmont)
Expand Down
21 changes: 8 additions & 13 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
const { fork } = require('child_process');
const filewatcher = require('filewatcher');
const { join } = require('path');
const semver = require('semver');
const { pathToFileURL } = require('url');
const { join } = require('node:path');
const { pathToFileURL } = require('node:url');

const { clearFactory } = require('./clear');
const { configureDeps, configureIgnore } = require('./ignore');
Expand Down Expand Up @@ -92,20 +91,16 @@ module.exports = function (
function start() {
isPaused = false;

const args = nodeArgs.slice();

args.push(`--require=${resolveMain(localPath('wrap'))}`);

const loaderName = semver.satisfies(process.version, '>=16.12.0') ? 'load' : 'get-format';

const loaderURL = pathToFileURL(resolveMain(localPath(join('loaders', `${loaderName}.mjs`))));

args.push(`--experimental-loader=${loaderURL.href}`);
const loaderURL = pathToFileURL(resolveMain(localPath(join('loaders', 'load.mjs'))));

child = fork(script, scriptArgs, {
cwd: process.cwd(),
env: process.env,
execArgv: args
execArgv: [
...nodeArgs.slice(),
`--experimental-loader=${loaderURL.href}`,
`--require=${resolveMain(localPath('wrap'))}`
]
});

if (respawn) {
Expand Down
15 changes: 11 additions & 4 deletions lib/loaders/load.mjs
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import { createRequire } from 'module';
import { fileURLToPath } from 'url';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';
import { send } from './ipc.mjs';

const require = createRequire(import.meta.url);

export async function load(url, context, defaultLoad) {
let connectedPort;

export async function initialize({ port } = {}) {
connectedPort = port;
}

export async function load(url, context, nextLoad) {
const required = url.startsWith('file://') ? fileURLToPath(url) : url;

send({ required });
if (connectedPort) connectedPort.postMessage({ required });

try {
return await defaultLoad(url, context, defaultLoad);
return await nextLoad(url, context);
} catch (error) {
if (error.code !== 'ERR_UNKNOWN_FILE_EXTENSION') throw error;
return require('get-package-type')(required).then(format => {
Expand Down
27 changes: 27 additions & 0 deletions lib/register-loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const { register } = require('node:module');
const { join } = require('node:path');
const { pathToFileURL } = require('node:url');
const semver = require('semver');

const { send } = require('./ipc');
const localPath = require('./local-path');
const resolveMain = require('./resolve-main');

exports.registerLoader = () => {
if (!semver.satisfies(process.version, '>=20.6.0')) return;

const loaderURL = pathToFileURL(resolveMain(localPath(join('loaders', 'load.mjs'))));

const { port1, port2 } = new MessageChannel();
port1.on('message', ({ required } = {}) => {
send({ required });
});
Copy link

@HitkoDev HitkoDev Sep 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding process.exit(0) calls in the tests, a better solution would be to just call port1.unref() here (https://nodejs.org/api/worker_threads.html#portunref).


register(loaderURL.href, {
parentURL: loaderURL.href,
data: { port: port2 },
transferList: [port2]
});

return port1;
};
17 changes: 12 additions & 5 deletions lib/wrap.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
const { dirname, extname } = require('path');
const childProcess = require('child_process');
const childProcess = require('node:child_process');
const { dirname, extname } = require('node:path');
const { isMainThread } = require('node:worker_threads');
const { sync: resolve } = require('resolve');
const { isMainThread } = require('worker_threads');

const { getConfig } = require('./cfg');
const hook = require('./hook');
const { relay, send } = require('./ipc');
const { registerLoader } = require('./register-loader');
const resolveMain = require('./resolve-main');
const suppressExperimentalWarnings = require('./suppress-experimental-warnings');

Expand All @@ -25,8 +26,14 @@ if (process.env.NODE_DEV_PRELOAD) {
require(process.env.NODE_DEV_PRELOAD);
}

// We want to exit on SIGTERM, but defer to existing SIGTERM handlers.
process.once('SIGTERM', () => process.listenerCount('SIGTERM') || process.exit(0));
const port = registerLoader();

process.once('SIGTERM', () => {
port?.close();
// We want to exit on SIGTERM, but defer to existing SIGTERM handlers.
if (process.listenerCount('SIGTERM')) return;
process.exit(0);
});

if (fork) {
// Overwrite child_process.fork() so that we can hook into forked processes
Expand Down
33 changes: 17 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "node-dev",
"version": "8.0.0",
"version": "9.0.0",
"description": "Restarts your app when files are modified",
"keywords": [
"restart",
Expand All @@ -24,35 +24,36 @@
},
"main": "./lib",
"engines": {
"node": ">=14"
"node": ">=18"
},
"scripts": {
"lint": "eslint lib test bin/node-dev",
"test": "node test",
"prepare": "husky install"
"prepare": "husky install",
"prettier": "prettier lib test bin/node-dev",
"test": "node test"
},
"dependencies": {
"dateformat": "^3.0.3",
"dynamic-dedupe": "^0.3.0",
"filewatcher": "~3.0.0",
"filewatcher": "^3.0.1",
"get-package-type": "^0.1.0",
"minimist": "^1.2.6",
"node-notifier": "^8.0.1",
"resolve": "^1.22.0",
"semver": "^7.3.7"
"resolve": "^1.22.6",
"semver": "^7.5.4"
},
"devDependencies": {
"@types/node": "^18.11.18",
"eslint": "^8.30.0",
"eslint-plugin-import": "^2.26.0",
"husky": "^8.0.2",
"lint-staged": "^13.1.0",
"prettier": "^2.6.2",
"tap": "^16.3.2",
"@types/node": "^20.6.2",
"eslint": "^8.49.0",
"eslint-plugin-import": "^2.28.1",
"husky": "^8.0.3",
"lint-staged": "^14.0.1",
"prettier": "^3.0.3",
"tap": "^18.0.4",
"tap-xunit": "^2.4.1",
"touch": "^3.1.0",
"ts-node": "^10.7.0",
"typescript": "^4.6.3"
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
},
"lint-staged": {
"*.{js,mjs}": "eslint --cache --fix",
Expand Down
11 changes: 6 additions & 5 deletions test/fixture/cluster.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { disconnect, fork, isMaster, isWorker } = require('cluster');
const { fork, isMaster, isWorker } = require('node:cluster');

const createWorker = i => {
const worker = fork();
Expand Down Expand Up @@ -26,15 +26,16 @@ if (isWorker) {
}

if (isMaster) {
const workers = [];
for (let i = 0; i < 2; i += 1) {
console.log('Forking worker', i);
createWorker(i);
workers.push(createWorker(i));
}

process.once('SIGTERM', () => {
console.log('Master received SIGTERM');
disconnect(() => {
console.log('All workers disconnected.');
});
workers.forEach(worker => worker.kill());
console.log('All workers disconnected.');
process.exit(0);
});
}
1 change: 0 additions & 1 deletion test/fixture/experimental-specifier-resolution/index.mjs

This file was deleted.

4 changes: 2 additions & 2 deletions test/fixture/ipc-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ server
process.on('message', data => {
if (data === 'node-dev:restart') {
console.log('ipc-server.js - IPC received');
server.close();
server.close(() => process.exit(0));
}
});

process.once('beforeExit', () => console.log('exit'));

process.once('SIGTERM', () => {
if (server.listening) server.close();
if (server.listening) server.close(() => process.exit(0));
});
7 changes: 0 additions & 7 deletions test/fixture/resolution.mjs

This file was deleted.

1 change: 1 addition & 0 deletions test/fixture/typescript/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ process.once('SIGTERM', () => {
if (server.listening) {
server.close();
}
process.exit(0);
});

process.once('beforeExit', () => console.log('exit'));
Expand Down
14 changes: 0 additions & 14 deletions test/spawn/esmodule.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,6 @@ const tap = require('tap');

const { spawn, touchFile } = require('../utils');

tap.test('Supports ECMAScript modules with experimental-specifier-resolution', t => {
spawn('--experimental-specifier-resolution=node resolution.mjs', out => {
if (out.match(/touch message.js/)) {
touchFile('message.js');
return out2 => {
if (out2.match(/Restarting/)) {
t.match(out2, /\[INFO\] \d{2}:\d{2}:\d{2} Restarting/);
return { exit: t.end.bind(t) };
}
};
}
});
});

tap.test('Supports ECMAScript modules', t => {
spawn('ecma-script-modules.mjs', out => {
if (out.match(/touch message.mjs/)) {
Expand Down
Loading