< A) Directory Structure | B) Dev | > C) Build |
This page explains how to use jsenv to start a development server for your source files.
Best parts of the jsenv dev server:
- Standard web server: Complies with web standards, ensuring transparency and predictability.
- Auto-reload on save: Automatically refreshes the browser when files are saved.
- Error resilient: Remains functional even with syntax errors, allowing uninterrupted work.
- Large browser support: Serves code compatible with majors browsers, including older versions.
This section explains how to serve project source files using jsenv.
project/ src/ index.html package.json
src/index.html:
<!doctype html>
<html>
<head>
<title>Title</title>
<meta charset="utf-8" />
<link rel="icon" href="data:," />
</head>
<body>
Hello world
</body>
</html>
Add a dev.mjs
file:
project/
+ scripts/
+ dev.mjs
src/
index.html
package.json
scripts/dev.mjs:
import { startDevServer } from "@jsenv/core";
await startDevServer({
sourceDirectoryUrl: new URL("../src/", import.meta.url),
});
a. Install dependencies:
npm i --save-dev @jsenv/core
b. Start the server
node ./scripts/dev.mjs
Expected output:
✔ start dev server (done in 0.009 second)
- http://localhost:3456
- http://127.0.0.1:3456
Figure: The development server in action, showing the served files and URLs
The dev server automatically serves the most compatible version of your code for the browser being used.
Supported browsers during development:
- Chrome 64+
- Safari 11.3+
- Edge 79+
- Firefox 67+
- Opera 51+
- Safari on IOS 12+
- Samsung Internet 9.2+
Note: The browser support after the build process is broader, see browser support after build.
The dev server is compatible with any directory structure and does not impose assumptions. However, organizing source files into a dedicated directory is recommended for clarity.
Not ideal: Source files are mixed with other files.
project/
node_modules/
foo/
foo.js
package.json
.gitignore
index.html
package.json
Better: Source files are in a separate directory.
project/
node_modules/
foo/
foo.js
package.json
src/
index.html
.gitignore
package.json
The root URL /
is equivalent to /index.html
:
http://localhost:3456 | http://localhost:3456/index.html |
---|---|
![]() |
![]() |
The main file can be configured with sourceMainFilePath
:
import { startDevServer } from "@jsenv/core";
await startDevServer({
sourceDirectoryUrl: new URL("../src/", import.meta.url),
sourceMainFilePath: "./main.html",
});
Without a visual marker it's hard to distinguish source files from build files.
dev server | build server |
---|---|
![]() |
![]() |
To differentiate source files from build files, the dev server injects a visual marker (ribbon) into HTML files:
Figure: The ribbon in action, marking the page as served by the dev server
The code below shows how to disable the ribbon:
import { startDevServer } from "@jsenv/core";
await startDevServer({
sourceDirectoryUrl: new URL("../src/", import.meta.url),
ribbon: false, // Disables the ribbon
});
The dev server displays an error overlay when issues occur, complementing the browser’s dev tools:
Figure: The error overlay showing an error in the code.
Example HTML causing an error:
<!doctype html>
<html>
<head>
<title>Title</title>
<meta charset="utf-8" />
<link rel="icon" href="data:," />
</head>
<body>
Hello world
<script type="module" src="./main.js"></script>
</body>
</html>
A lot of examples are available at tests/dev_server/errors/screenshots/.
Error overlay can be disabled as follow:
import { startDevServer } from "@jsenv/core";
await startDevServer({
sourceDirectoryUrl: new URL("../src/", import.meta.url),
supervisor: {
errorOverlay: false, // Disables the error overlay
},
});
In that case opening the same HTML file does not display error overlay. So devtools must be opened to see the error:
The dev server automatically applies changes when files are saved. Some updates can be applied without reloading the page, while others trigger a full reload.
TODO:
- Explain what is "partial reload" + when it can be used (css for instance)
- screenshots
- explain
import.meta.hot
to unlock partial reload on js - Explain what is "full reload" + when it is used
- screenshots
By default the following files can trigger a reload:
{
"**/*": true, // All files inside the source directory
"**/.*/": false, // Exclude directory starting with a dot
"**/node_modules/": false, // Exclude node_modules
}
The following would change the files being watched:
import { startDevServer } from "@jsenv/core";
await startDevServer({
sourceDirectoryUrl: new URL("../src/", import.meta.url),
sourceFilesConfig: {
"./**/*.js": true,
"./**/*.css": false,
},
});
import { startDevServer } from "@jsenv/core";
await startDevServer({
sourceDirectoryUrl: new URL("../src/", import.meta.url),
clientAutoreload: false,
});
Enhance dev server capabilities with plugins. For example, to use React and JSX:
import { startDevServer } from "@jsenv/core";
import { jsenvPluginReact } from "@jsenv/plugin-react";
await startDevServer({
sourceDirectoryUrl: new URL("../src/", import.meta.url),
plugins: [jsenvPluginReact()],
});
See the full list of plugins in G) Plugins
The dev server generates source mappings, helping browsers remap compiled code to its original source.
Value | Description |
---|---|
"inline" |
Inline mappings as base64 in sourcemap comments. |
"file" |
Generate separate .map files. |
"none" |
Disable sourcemap generation. |
Default: "inline"
The dev server defaults to port 3456. Change it as needed:
import { startDevServer } from "@jsenv/core";
await startDevServer({
sourceDirectoryUrl: new URL("../src/", import.meta.url),
port: 8888,
});
The dev server can use HTTPS with a certificate and private key:
import { startDevServer } from "@jsenv/core";
await startDevServer({
sourceDirectoryUrl: new URL("../src/", import.meta.url),
https: {
certificate: "-----BEGIN CERTIFICATE-----...-----END CERTIFICATE-----",
privateKey:
"-----BEGIN RSA PRIVATE KEY-----...'-----END RSA PRIVATE KEY-----",
},
});
Tip: Use @jsenv/https-local↗ to generate certificates programmatically.
< A) Directory Structure | B) Dev | > C) Build |