Getting Started
This guide walks you through installing layer-pack, creating your first .layers.json configuration, and building a project with inheritable webpack layers.
Installation
Install layer-pack alongside webpack and webpack-cli as development dependencies:
npm install layer-pack webpack webpack-cli --save-dev
This gives you access to the lpack CLI commands and the layer-pack Node.js API for your webpack configs.
Create .layers.json
Create a .layers.json file in your project root. This file defines your project's layer configuration, including the source root folder, build profiles, and template variables:
{
"default": {
"rootFolder": "App",
"config": "./webpack.config.js",
"vars": {
"rootAlias": "App",
"project": "my-project"
}
}
}
Key fields:
rootFolder— The directory containing your source code. This becomes the namespace root for imports likeApp/components/Foo.config— Path to your webpack configuration file, relative to the project root.vars— Template variables available in webpack configs. These are merged with parent layers (your values win).
Create Your App
Create the source root directory specified by rootFolder and add an entry file:
mkdir -p App
// Your app entry point
// layer-pack resolves "App/..." imports through all layer roots
import { greeting } from 'App/utils/hello';
console.log(greeting('world'));
export function greeting(name) {
return `Hello, ${name}! Built with layer-pack.`;
}
Notice how we import using App/utils/hello — layer-pack's namespace resolution will look for this file in all layer roots, starting from the head project.
Webpack Configuration
Create a webpack.config.js that uses the layer-pack API. The key integration points are the plugin, the config vars, the file exclusion helper, and the head root path:
const layerPack = require('layer-pack');
const lPackCfg = layerPack.getConfig();
module.exports = [
{
mode: 'development',
// Use the rootAlias var as the entry point name
entry: {
App: lPackCfg.vars.rootAlias
},
output: {
path: layerPack.getHeadRoot() + '/dist/',
filename: '[name].js'
},
// The layer-pack plugin hooks into webpack's resolver
// to handle namespace aliases, $super, and glob imports
plugins: [
layerPack.plugin()
],
module: {
rules: [
{
test: /\.jsx?$/,
// isFileExcluded() returns a function that excludes files
// outside the layer inheritance chain from transpilation
exclude: layerPack.isFileExcluded(),
use: 'babel-loader'
}
]
},
resolve: {
extensions: ['.js', '.jsx', '.json']
}
}
];
Build Your Project
Use the lpack CLI to build. It sets up the correct environment variables and spawns webpack with layer-aware module resolution:
# Build using the "default" profile
npx lpack
# Start the dev server with hot module replacement
npx lpack-dev-server
That is it — you have a working layer-pack project. But the real power comes when you start inheriting layers.
Inheriting a Layer
The key feature of layer-pack is layer inheritance via the extend field. Let us extend lpack-react, which provides a complete React 18 + Webpack 5 + Sass + Express SSR stack:
# Install the parent layer
npm install lpack-react --save-dev
# Run lpack-setup to install dependencies from inherited layers
npx lpack-setup
Now update your .layers.json to extend it:
{
"default": {
"rootFolder": "App",
"extend": ["lpack-react"],
"vars": {
"rootAlias": "App",
"project": "my-react-app",
"devPort": 3000,
"targetDir": "dist/www"
}
}
}
Notice we no longer need "config" — the webpack configuration is inherited from lpack-react. Our project inherits:
- Webpack configuration with babel, sass, and asset loaders
- Express-based SSR server configuration
- Hot Module Replacement setup
- React 18 with JSX/TSX support
- Source root resolution across all layer roots
You can still provide your own config field to override or extend the inherited webpack config. The inherited config is used as a base that your config builds upon.
lpack-setup walks the entire layer chain and installs any missing dependencies so the build works out of the box.
Multiple Profiles
A single project often needs multiple build targets: a web frontend, an API server, a static site generator. layer-pack handles this with profiles:
{
"default": {
"rootFolder": "App",
"extend": ["lpack-react"],
"vars": {
"rootAlias": "App",
"project": "my-app",
"devPort": 3000
}
},
"www": {
"basedOn": "default",
"vars": {
"targetDir": "dist/www",
"production": true
}
},
"api": {
"basedOn": "default",
"config": "./webpack.config.api.js",
"vars": {
"targetDir": "dist/api",
"externals": true
}
}
}
Build each profile by name:
# Build the web frontend
npx lpack :www
# Build the API server
npx lpack :api
# Dev server for the web frontend
npx lpack-dev-server :www
The basedOn field tells layer-pack to inherit all settings from another profile in the same file. The www profile inherits everything from default and overrides the vars. The api profile inherits from default but also provides its own webpack config file.
CLI Reference
| Command | Description |
|---|---|
lpack |
Build using the default profile. Spawns webpack with layer-aware resolution. |
lpack :profile |
Build using the named profile (e.g., lpack :api, lpack :www). |
lpack-dev-server |
Start webpack-dev-server with HMR. Accepts :profile suffix. |
lpack-setup |
Install dependencies from all inherited layers in the extend chain. |
lpack-run <script> |
Run a Node.js script with layer-pack module resolution paths active. |
lpack-init |
Scaffold a new layer-pack project from a template. |
All CLI commands accept additional arguments that are passed through to webpack or webpack-dev-server. For example:
# Build with watch mode
npx lpack --watch
# Build for production
npx lpack :www --mode production
# Dev server on a custom port
npx lpack-dev-server :www --port 8080
Next Steps
Documentation
Deep dive into .layers.json format, glob imports, $super, namespace resolution, and the full plugin API.
Tutorials
Hands-on tutorials: build a reusable React layer, set up multi-endpoint architecture, and more.
Glob Imports
Learn how glob imports auto-generate virtual modules from directory trees.
$super Imports
Override parent components while still accessing the original through $super.