Skip to content

Commit 5100376

Browse files
authored
feat: restart server when svelte config file changes (fixes #63) (#72)
* feat: restart server when svelte config file changes (fixes #63) * fix: make sure the absolute path of the loaded svelte config file is kept in resolvedOptions * refactor: use package.json scripts and execa to start servers for e2e-tests; add tests for svelte config watching * fix: remove syntax not supported by node12 from e2e script * fix: use writeFileSync instead of fs/promises for node12 * chore: remove debugging screenshots * chore: update dependencies * test: move to lower portrange and archive dist on failure * test: fix e2e-server script. correct error output and don't throw if closing server wasn't graceful * fix: really bad c&p err * test: increase sleep time on windows to account for slower devserver restart * fix invalid doc * chore: update changeset
1 parent 97ee68c commit 5100376

File tree

42 files changed

+1059
-850
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1059
-850
lines changed

.changeset/large-ears-press.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@sveltejs/vite-plugin-svelte': minor
3+
---
4+
5+
- Restart dev server when svelte config file changes
6+
- Refactored e2e-tests to use package.json scripts
7+
- Updated dependencies

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ jobs:
168168
- name: archive tests temp directory
169169
if: failure()
170170
shell: bash
171-
run: tar -cvf test-temp.tar --exclude="node_modules" --exclude=".yarn" --exclude="dist" --exclude=".pnp.js" temp/
171+
run: tar -cvf test-temp.tar --exclude="node_modules" temp/
172172
- uses: actions/upload-artifact@v2
173173
if: failure()
174174
with:

package.json

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
"build": "pnpm --dir packages/vite-plugin-svelte build",
88
"test": "run-s test:serve test:build",
99
"test:serve": "jest",
10-
"test:serve:debug": "cross-env VITE_DEBUG_SERVE=1 node --inspect-brk ./node_modules/.bin/jest",
10+
"test:serve:debug": "cross-env DEBUG=pw:api VITE_DEBUG_SERVE=1 node --inspect-brk ./node_modules/jest/bin/jest --runInBand",
1111
"test:build": "cross-env VITE_TEST_BUILD=1 jest",
12-
"test:build:debug": "cross-env VITE_TEST_BUILD=1 VITE_PRESERVE_BUILD_ARTIFACTS=1 node --inspect-brk ./node_modules/.bin/jest",
12+
"test:build:debug": "cross-env DEBUG=pw:api VITE_TEST_BUILD=1 VITE_PRESERVE_BUILD_ARTIFACTS=1 node --inspect-brk ./node_modules/jest/bin/jest --runInBand",
1313
"test:ci": "run-s test:ci:serve test:ci:build",
1414
"test:ci:serve": "cross-env VITE_PRESERVE_BUILD_ARTIFACTS=1 jest --verbose --no-cache --runInBand --force-exit --ci --json --outputFile=\"temp/serve/jest-results.json\"",
1515
"test:ci:build": "cross-env VITE_TEST_BUILD=1 VITE_PRESERVE_BUILD_ARTIFACTS=1 jest --verbose --no-cache --runInBand --force-exit --ci --json --outputFile=\"temp/build/jest-results.json\"",
@@ -27,14 +27,14 @@
2727
"@changesets/cli": "^2.16.0",
2828
"@types/fs-extra": "^9.0.11",
2929
"@types/jest": "^26.0.23",
30-
"@types/node": "^15.12.4",
30+
"@types/node": "^15.12.5",
3131
"@types/semver": "^7.3.6",
32-
"@typescript-eslint/eslint-plugin": "^4.28.0",
33-
"@typescript-eslint/parser": "^4.28.0",
32+
"@typescript-eslint/eslint-plugin": "^4.28.1",
33+
"@typescript-eslint/parser": "^4.28.1",
3434
"chalk": "^4.1.1",
3535
"cross-env": "^7.0.3",
3636
"enquirer": "^2.3.6",
37-
"esbuild": "^0.12.9",
37+
"esbuild": "^0.12.12",
3838
"eslint": "^7.29.0",
3939
"eslint-config-prettier": "^8.3.0",
4040
"eslint-plugin-html": "^6.1.2",
@@ -46,22 +46,22 @@
4646
"execa": "^5.1.1",
4747
"fs-extra": "^10.0.0",
4848
"husky": "^6.0.0",
49-
"jest": "^27.0.5",
50-
"jest-environment-node": "^27.0.5",
49+
"jest": "^27.0.6",
50+
"jest-environment-node": "^27.0.6",
5151
"jest-junit": "^12.2.0",
5252
"lint-staged": "^11.0.0",
5353
"minimist": "^1.2.5",
5454
"node-fetch": "^2.6.1",
5555
"npm-check-updates": "^11.7.1",
5656
"npm-run-all": "^4.1.5",
57-
"playwright-core": "^1.12.2",
58-
"pnpm": "^6.8.0",
59-
"prettier": "^2.3.1",
57+
"playwright-core": "^1.12.3",
58+
"pnpm": "^6.9.1",
59+
"prettier": "^2.3.2",
6060
"prettier-plugin-svelte": "^2.3.1",
6161
"rimraf": "^3.0.2",
6262
"semver": "^7.3.5",
6363
"sirv": "^1.0.12",
64-
"svelte": "^3.38.2",
64+
"svelte": "^3.38.3",
6565
"ts-jest": "^27.0.3",
6666
"typescript": "^4.3.4",
6767
"vite": "^2.3.8"

packages/e2e-tests/autoprefixer-browerslist/package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,19 @@
33
"private": true,
44
"version": "1.0.0",
55
"scripts": {
6+
"dev": "vite",
67
"build": "vite build",
7-
"dev": "vite"
8+
"preview": "vite preview"
9+
},
10+
"dependencies": {
11+
"e2e-tests-hmr-test-dependency": "workspace:*"
812
},
9-
"dependencies": {
10-
"e2e-tests-hmr-test-dependency": "workspace:*"
11-
},
1213
"devDependencies": {
1314
"@sveltejs/vite-plugin-svelte": "workspace:*",
1415
"autoprefixer": "^10.2.6",
1516
"postcss": "^8.3.5",
1617
"postcss-load-config": "^3.1.0",
17-
"svelte": "^3.38.2",
18+
"svelte": "^3.38.3",
1819
"svelte-hmr": "^0.14.4",
1920
"svelte-preprocess": "^4.7.3",
2021
"vite": "^2.3.8"
Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
const { svelte } = require('@sveltejs/vite-plugin-svelte');
22
const { defineConfig } = require('vite');
33

4-
module.exports = defineConfig(({ command, mode }) => {
5-
const isProduction = mode === 'production';
4+
module.exports = defineConfig(() => {
65
return {
76
plugins: [svelte()],
87
build: {
9-
minify: isProduction
8+
// make build faster by skipping transforms and minification
9+
target: 'esnext',
10+
minify: false
11+
},
12+
server: {
13+
watch: {
14+
// During tests we edit the files too fast and sometimes chokidar
15+
// misses change events, so enforce polling for consistency
16+
usePolling: true,
17+
interval: 100
18+
}
1019
}
1120
};
1221
});

packages/e2e-tests/configfile-custom/package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@
33
"private": true,
44
"version": "1.0.0",
55
"scripts": {
6+
"dev": "vite",
67
"build": "vite build",
7-
"dev": "vite"
8+
"preview": "vite preview"
9+
},
10+
"dependencies": {
11+
"e2e-tests-hmr-test-dependency": "workspace:*"
812
},
9-
"dependencies": {
10-
"e2e-tests-hmr-test-dependency": "workspace:*"
11-
},
1213
"devDependencies": {
1314
"@sveltejs/vite-plugin-svelte": "workspace:*",
14-
"svelte": "^3.38.2",
15+
"svelte": "^3.38.3",
1516
"svelte-hmr": "^0.14.4",
16-
"svelte-preprocess": "^4.7.3",
1717
"vite": "^2.3.8"
1818
}
1919
}
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
const sveltePreprocess = require('svelte-preprocess');
2-
31
module.exports = {
4-
preprocess: sveltePreprocess()
2+
emitCss: false
53
};
Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
/*
2-
const sveltePreprocess = require('svelte-preprocess');
3-
4-
module.exports = {
5-
preprocess: sveltePreprocess()
6-
};
7-
*/
81
export default {
9-
emitCss: true
2+
emitCss: false
103
}
Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
const { svelte } = require('@sveltejs/vite-plugin-svelte');
22
const { defineConfig } = require('vite');
33

4-
module.exports = defineConfig(({ command, mode }) => {
5-
const isProduction = mode === 'production';
4+
module.exports = defineConfig(() => {
65
return {
76
plugins: [svelte({ configFile: 'svelte.config.custom.cjs' })],
87
build: {
9-
minify: isProduction
8+
// make build faster by skipping transforms and minification
9+
target: 'esnext',
10+
minify: false
11+
},
12+
server: {
13+
watch: {
14+
// During tests we edit the files too fast and sometimes chokidar
15+
// misses change events, so enforce polling for consistency
16+
usePolling: true,
17+
interval: 100
18+
}
1019
}
1120
};
1221
});

packages/e2e-tests/configfile-esm/package.json

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,19 @@
33
"private": true,
44
"version": "1.0.0",
55
"scripts": {
6+
"dev": "vite",
67
"build": "vite build",
7-
"dev": "vite"
8+
"preview": "vite preview"
9+
},
10+
"dependencies": {
11+
"e2e-tests-hmr-test-dependency": "workspace:*"
812
},
9-
"dependencies": {
10-
"e2e-tests-hmr-test-dependency": "workspace:*"
11-
},
1213
"devDependencies": {
1314
"@sveltejs/vite-plugin-svelte": "workspace:*",
14-
"svelte": "^3.38.2",
15+
"svelte": "^3.38.3",
1516
"svelte-hmr": "^0.14.4",
1617
"svelte-preprocess": "^4.7.3",
1718
"vite": "^2.3.8"
1819
},
19-
"type": "module"
20+
"type": "module"
2021
}

packages/e2e-tests/configfile-esm/vite.config.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,20 @@ import { svelte } from '@sveltejs/vite-plugin-svelte';
22
import { defineConfig } from 'vite';
33

44
export default defineConfig(({ command, mode }) => {
5-
const isProduction = mode === 'production';
65
return {
76
plugins: [svelte()],
87
build: {
9-
minify: isProduction
8+
// make build faster by skipping transforms and minification
9+
target: 'esnext',
10+
minify: false
11+
},
12+
server: {
13+
watch: {
14+
// During tests we edit the files too fast and sometimes chokidar
15+
// misses change events, so enforce polling for consistency
16+
usePolling: true,
17+
interval: 100
18+
}
1019
}
1120
};
1221
});

packages/e2e-tests/e2e-server.js

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// script to start package.json dev/build/preview scripts with execa for e2e tests
2+
const execa = require('execa');
3+
const treeKill = require('tree-kill');
4+
const fs = require('fs');
5+
const path = require('path');
6+
const isWin = process.platform === 'win32';
7+
async function startedOnPort(serverProcess, port, timeout) {
8+
let id;
9+
let stdoutListener;
10+
const timerPromise = new Promise(
11+
(_, reject) =>
12+
(id = setTimeout(() => {
13+
reject(`timeout for server start after ${timeout}`);
14+
}, timeout))
15+
);
16+
const startedPromise = new Promise((resolve, reject) => {
17+
stdoutListener = (data) => {
18+
const str = data.toString();
19+
// hack, console output may contain color code gibberish
20+
// skip gibberish between localhost: and port number
21+
const match = str.match(/(http:\/\/localhost:)(?:.*)(\d{4})/);
22+
if (match) {
23+
const startedPort = parseInt(match[2], 10);
24+
if (startedPort === port) {
25+
resolve();
26+
} else {
27+
const msg = `test server started on ${startedPort} instead of ${port}`;
28+
console.log(msg);
29+
reject(msg);
30+
}
31+
}
32+
};
33+
34+
serverProcess.stdout.on('data', stdoutListener);
35+
});
36+
37+
return Promise.race([timerPromise, startedPromise]).finally(() => {
38+
serverProcess.stdout.off('data', stdoutListener);
39+
clearTimeout(id);
40+
});
41+
}
42+
43+
exports.serve = async function serve(root, isBuild, port) {
44+
const logDir = path.join(root, 'logs');
45+
const logs = {
46+
server: null,
47+
build: null
48+
};
49+
const writeLogs = async (name, result) => {
50+
try {
51+
if (result.out && result.out.length > 0) {
52+
fs.writeFileSync(path.join(logDir, `${name}.log`), result.out.join(''), 'utf-8');
53+
}
54+
if (result.err && result.err.length > 0) {
55+
fs.writeFileSync(path.join(logDir, `${name}.err.log`), result.err.join(''), 'utf-8');
56+
}
57+
} catch (e1) {
58+
console.error(`failed to write ${name} logs in ${logDir}`, e1);
59+
}
60+
};
61+
62+
if (isBuild) {
63+
let buildResult;
64+
let hasErr = false;
65+
let out = [];
66+
let err = [];
67+
68+
try {
69+
const buildProcess = execa('pnpm', ['build'], {
70+
preferLocal: true,
71+
cwd: root,
72+
stdio: 'pipe'
73+
});
74+
logs.build = { out, err };
75+
buildProcess.stdout.on('data', (d) => out.push(d.toString()));
76+
buildProcess.stderr.on('data', (d) => err.push(d.toString()));
77+
await buildProcess;
78+
} catch (e) {
79+
buildResult = e;
80+
if (buildResult.stdout) {
81+
out.push(buildResult.stdout);
82+
}
83+
if (buildResult.stderr) {
84+
err.push(buildResult.stderr);
85+
}
86+
hasErr = true;
87+
}
88+
await writeLogs('build', logs.build);
89+
if (hasErr) {
90+
throw buildResult;
91+
}
92+
}
93+
94+
const serverProcess = execa('pnpm', [isBuild ? 'preview' : 'dev', '--', '--port', port], {
95+
preferLocal: true,
96+
cwd: root,
97+
stdio: 'pipe'
98+
});
99+
const out = [],
100+
err = [];
101+
logs.server = { out, err };
102+
serverProcess.stdout.on('data', (d) => out.push(d.toString()));
103+
serverProcess.stderr.on('data', (d) => err.push(d.toString()));
104+
105+
const closeServer = async () => {
106+
if (serverProcess) {
107+
if (serverProcess.pid) {
108+
await new Promise((resolve) => {
109+
treeKill(serverProcess.pid, (err) => {
110+
if (err) {
111+
console.error(`failed to treekill serverprocess ${serverProcess.pid}`, err);
112+
}
113+
resolve();
114+
});
115+
});
116+
} else {
117+
serverProcess.cancel();
118+
}
119+
120+
try {
121+
await serverProcess;
122+
} catch (e) {
123+
if (e.stdout) {
124+
out.push(e.stdout);
125+
}
126+
if (e.stderr) {
127+
err.push(e.stderr);
128+
}
129+
if (!isWin) {
130+
// treekill on windows uses taskkill and that ends up here always
131+
console.error(`server process did not exit gracefully. dir: ${root}`, e);
132+
}
133+
}
134+
}
135+
await writeLogs('server', logs.server);
136+
};
137+
try {
138+
await startedOnPort(serverProcess, port, 20000);
139+
return {
140+
port,
141+
logs,
142+
close: closeServer
143+
};
144+
} catch (e) {
145+
try {
146+
await closeServer();
147+
} catch (e1) {
148+
console.error('failed to close server process', e1);
149+
}
150+
}
151+
};

0 commit comments

Comments
 (0)