Security News
The Risks of Misguided Research in Supply Chain Security
Snyk's use of malicious npm packages for research raises ethical concerns, highlighting risks in public deployment, data exfiltration, and unauthorized testing.
A no-nonsense dev server toolkit to help you develop quickly and easily for the web
dvlp is a no-configuration, no-conditionals, no-middleware, no-nonsense (no-vowels!) dev server toolkit to help you develop quickly and easily for the web. You shouldn't have to jump through hoops to get a development environment up and running, and you definitely shouldn't have to include development-only stuff in your high-quality production code! dvlp is full of hacks so your code doesn't have to be!
Back in the good old days, our web development workflow went something like this: write HTML/CSS/JS, refresh browser, repeat. Years later, with the help of Node.js and emerging standards, we started pre-processing our CSS and transpiling our JS to take advantage of more expressive, agreeable language features. At the same time, as writing code became easier and more enjoyable, we began bundling and packaging our (growing amount of) code for delivery to the browser. The modern web development workflow soon looked like this: write HTML/JSX/SCSS/LESS/CSS/TS/JS, transpile, compile, bundle, (hot) reload, repeat. For those of us ambitious enough to tackle a full-stack, universal JS application, you would also need to include a well timed server restart (somewhere) in there.
Today, history's pendulum is starting to swing back the other way. Thanks to JS modules and excellent Node.js/browser support for new language features, it's time for a simpler, more comfortable workflow. Bundling should be treated as a production optimization (like minification), and our application web servers shouldn't be responsible for building our development assets.
Less setup, less complexity, and less waiting is surely the path to developer happiness and comfort.
dvlp allows you to easily serve files from one or more project directories (static
mode), or from your custom application server (app
mode). In both cases, dvlp automatically injects the necessary reload script into HTML responses to enable reloading, watches all files for changes, restarts the app
server if necessary, and reloads all connected browsers.
In addition, when working with JS modules, dvlp will ensure that so-called bare imports (import "lodash"
), which are not supported by browsers, work by re-writing all import paths to valid urls. Since most node_modules
packages are still published as CommonJS modules, each bare import is also bundled and converted to an ESM module using Rollup.js. These bundles are versioned and cached for efficient reuse in the .dvlp
directory under the project root.
dvlp also includes a simple testServer
for handling various network request scenarios (mocking, latency, errors, offline, etc.) during testing.
Install globally or locally in your project with npm/yarn:
$ npm install dvlp
$ dvlp --help
Usage: dvlp [options] [path...]
Start a development server, restarting and reloading connected browsers on file changes.
Serves static files from one or more "path" directories, or a custom application
server if "path" is a single file.
Options:
-p, --port <port> port number
-m, --mock <path> path to mock files (directory, file, glob pattern)
-t, --transpiler <path> path to optional transpiler file
-r, --rollup-config <path> path to optional Rollup.js config file
--no-reload disable reloading connected browsers on file change
-v, --version output the version number
-h, --help output usage information
Add a script to your package.json scripts
:
{
"scripts": {
"dev": "dvlp --port 8000 src/app.js"
}
}
...and launch:
$ npm run dev
In some cases you may want to write HTML/CSS/JS in a non-standard, higher-order language like SASS (for CSS), or JSX (for JS). In these cases, you can pass dvlp a transpile
function to convert file contents on the fly when requested by the browser.
The transpile
function should accept a filepath
and return a content string (or Promise resolving to a string) if the file has be transpiled. If nothing is returned, dvlp will handle the file normally:
// scripts/transpile.js
const sass = require('sass');
const RE_SASS = /\.s[ac]ss$/;
module.exports = async function transpile(filepath) {
if (RE_SASS.test(filepath)) {
return sass.renderSync({ file: filepath }).css;
}
};
...reference the original file as you normally would:
<link rel="stylesheet" href="src/index.sass">
...and pass the transpile
file with the -t, --transpiler
flag:
{
"scripts": {
"dev": "dvlp --transpiler scripts/transpile.js --port 8000 src/app.js"
}
}
In order to keep things snappy, dvlp will cache transpiled content and only re-transpile single files when the original contents have changed.
When developing locally, it's often useful to mock requests made from your application server, especially when working with an external API. dvlp lets you quickly and easily mock endpoints by intercepting requests that match those registered with the -m, --mock
flag.
Mock a request by creating a .json
file describing the mocked request/response
:
{
"request": {
"url": "http://www.someapi.com/v1/id/101010",
"ignoreSearch": true
},
"response": {
"headers": {
"x-custom": "custom header"
},
"body": {
"user": {
"name": "Nancy",
"id": "101010"
}
}
}
}
(Note that setting request.ignoreSearch = true
will ignore query parameters when matching an incoming request with the mocked response)
Though JSON responses are probably the most common, it's also possible to mock other types of payloads by linking the response.body
to an external file:
{
"request": {
"url": "http://www.someplace.com/images/avatar.jpg"
},
"response": {
"body": "../assets/avatar.jpg"
}
}
(Note that the file paths referenced in response.body
are relative to the mock file, not the web/project root)
Register mocked responses with the command-line flag -m, --mock
and a path to your mock files:
{
"scripts": {
"dev": "dvlp --mock path/to/mock/files --port 8000 src/app.js"
}
}
Your path/to/mock/files
could be one of the following:
path/to/mock/directory
path/to/mock.json
(Note that the following require wrapping in ""
)
"path/to/mock/{api,assets}"
,
, :
, or ;
: "path/to/mock1.json, path/to/mock2.json"
As mentioned in How it works, dvlp will bundle CommonJS packages imported from node_modules
in order to convert them to es6 modules. Rollup.js is used to create these bundles, and they are then cached on disk inside the .dvlp
directory under your project root.
In the rare case you need to configure Rollup.js to work with the packages you're importing, you can pass a custom configuration file:
{
"scripts": {
"dev": "dvlp --rollup-config rollup.config.js --port 8000 src/app.js"
}
}
dvlp will override/ignore the input
, treeshake
, and watch
input options, as well as the file
, format
, and sourcemap
output options. Here is the default configuration currently used:
{
input: 'path/to/temp/file',
treeshake: false,
output: {
file: 'path/to/cache/file',
format: 'es',
sourcemap: false
},
plugins: [
resolve({
browser: true
}),
json(),
commonjs({
sourceMap: false
})
]
}
All supported options are listed in the Rollup.js documentation.
dvlp uses the debug.js debugging utility internally. Set the following environment variable before running to see detailed debug messages:
$ DEBUG=dvlp* npm run dev
CHILD_WATCHER=true
to run file watching operations in a separate background process (default is false
)BUNDLE_WORKERS=n
(where n
is number of background processes) to run module bundling operations in separate background processes (default is 0
)server(filepath: string|[string], [options]): Promise<{ destroy: () => void }>
Serve files at filepath
, starting static file server if one or more directories, or app server if a single file.
options
include:
mockpath: string|[string]
the path(s) to load mock files from (default ''
)port: number
: port to expose on localhost
. Will use process.env.PORT
if not specified here (default 8080
)reload: boolean
: enable/disable browser reloading (default true
)rollupConfig: string
: path to optional Rollup.js config file to configure bundling of bare importsconst { server } = require('dvlp');
const appServer = await server('path/to/app.js', { port: 8080 });
testServer([options]): Promise<TestServer>
Create a server for handling network requests during testing.
options
include:
port: number
the port to expose on localhost
. Will use process.env.PORT
if not specified here (default 3333
)latency: number
the minimum amount of random artificial latency to introduce (in ms
) for responses (default 50
)webroot: String
the subpath from process.cwd()
to preppend to relative paths (default ''
)const { testServer } = require('dvlp');
const server = await testServer({ port: 8080, latency: 20, webroot: 'lib' });
Returns a TestServer
instance with the following properties:
latency: number
the minimum amount of random artificial latency to introduce (in ms
) for responses (default 50
)webroot: String
the subpath from process.cwd()
to preppend to relative paths (default ''
)loadMockFiles(filepath: string|[string]): void
load and register mock response files (see mocking){
"request": {
"url": "http://www.someapi.com/v1/id/101010"
},
"response": {
"body": {
"user": {
"name": "Nancy",
"id": "101010"
}
}
}
}
server.loadMockFiles('path/to/mock/101010.json');
const res = await fetch('http://www.someapi.com/v1/id/101010');
console.log(await res.json()); // => { user: { name: "nancy", id: "101010" } }
mock(request: string|object, response: object, once: boolean): void
add a mock response
for request
, optionally removing it after first use (see mocking)server.mock('/api/user/1234', {
body: {
id: '1234',
name: 'bob'
}
}, true);
const res = await fetch('http://localhost:8080/api/user/1234');
console.log(await res.json()); // => { id: "1234", name: "bob" }
destroy(): Promise<void>
stop and clean up running serverIf unable to resolve a request to a local file, testServer
will respond with a dummy file of the appropriate type. This makes it easy to test ServiceWorker pre-caching, for example, without having to correctly resolve paths or create mocks. In addition, testServer
supports the following special query parameters:
offline
simulate an offline state by terminating the request (fetch('http://localhost:3333/foo.js?offline')
)error
return a 500 server error response (fetch('http://localhost:3333/foo.js?error')
)missing
return a 404 not found response (fetch('http://localhost:3333/foo.js?missing')
)maxage=value
configure Cache-Control: public, max-age={value}
cache header (fetch('http://localhost:3333/foo.js?maxage=10')
)testServer.disableNetwork(): void
Disable all network requests with origin that is not localhost
. Prevents all external network requests for the current Node.js process.
testServer.disableNetwork();
await fetch('https://github.com/popeindustries/dvlp');
// => Error "network connections disabled"
testServer.enableNetwork(): void
Re-enables all previously disabled external network requests for the current Node.js process.
FAQs
A no-nonsense dev server toolkit to help you develop quickly and easily for the web
The npm package dvlp receives a total of 470 weekly downloads. As such, dvlp popularity was classified as not popular.
We found that dvlp demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Snyk's use of malicious npm packages for research raises ethical concerns, highlighting risks in public deployment, data exfiltration, and unauthorized testing.
Research
Security News
Socket researchers found several malicious npm packages typosquatting Chalk and Chokidar, targeting Node.js developers with kill switches and data theft.
Security News
pnpm 10 blocks lifecycle scripts by default to improve security, addressing supply chain attack risks but sparking debate over compatibility and workflow changes.