Internal Packages
This guide explains how to organize JavaScript developed inside a Ruby project as independent workspace packages while using Web Packages for testing and static deployment.
Why Use Workspace Packages?
Internal JavaScript often has its own module boundaries, tests and release concerns. Mixing it into the Ruby lib/ hierarchy makes both languages harder to navigate, while placing authored code directly in node_modules makes it disposable.
Web Packages recommends three distinct layers:
components/ # Authored internal JavaScript packages.
node_modules/ # Disposable package-manager projection.
public/_components/ # Generated static deployment projection.
package.json # Workspace and Web Packages configuration.
components/ describes the role of the code without requiring a second language-level hierarchy. A single directory can contain one or many packages.
Create an Internal Package
Give each internal library its own package.json and tests:
components/
live/
package.json
Live.js
test/
Live.js
For example:
{
"name": "@example/live",
"private": true,
"type": "module",
"exports": "./Live.js",
"scripts": {
"test": "node --test"
}
}
The directory name and package name do not need to match. Package identity comes from the internal package.json.
Add the Workspace
Expose internal packages through the root workspace configuration:
{
"private": true,
"workspaces": ["components/*"],
"web-packages": {
"packages": {
"@example/live": {
"include": ["Live.js"],
"imports": {
"live": "Live.js"
}
}
}
}
}
The package manager projects the workspace package into node_modules/@example/live, usually using a link. Web Packages resolves that link, ensures selected files remain inside the package, and copies the resulting files into public/_components/@example/live.
The components/ path is a convention rather than a requirement. Any workspace or local-package layout supported by the selected package manager can be used.
Test Internal Packages
Each package can keep its own test command. Define a root script which invokes the workspace tests according to the selected package manager, then let Web Packages run that script:
{
"scripts": {
"test": "npm test --workspaces --if-present"
}
}
$ bundle exec bake web:packages:test
pnpm, Yarn and Bun have their own workspace script syntax. Web Packages deliberately does not abstract those differences; the root script remains the project's explicit test entry point.
Multiple Internal Libraries
No additional multiplexing layer is needed. Add more package directories beneath components/, include them in the workspace pattern, and select the packages which should be deployed:
components/
editor/
package.json
live/
package.json
syntax/
package.json
Packages used only for development do not need to appear in web-packages.packages. Packages listed there can be deployed even when they are not direct root dependencies.