Broccoli Middleware
broccoli-middleware is a utility that integrates the Broccoli asset pipeline's build output into standard Node.js HTTP servers, typically for development environments. It allows applications, especially those built with Ember CLI, to serve dynamically built assets through middleware like Express. The package is currently at version 2.1.1, with its last publication dating back to 2019. Its development is effectively abandoned, with no recent releases or active maintenance. It differentiates itself by providing a direct bridge between the Broccoli build process and a web server's request-response cycle, allowing for on-the-fly serving of compiled assets without a separate build step before server startup. This contrasts with build tools that pre-build all assets to a /dist folder.
Common errors
-
ReferenceError: require is not defined in ES module scope
cause Attempting to use `require()` syntax for `broccoli-middleware` within a Node.js ES module file (e.g., a `.mjs` file or a `.js` file where `"type": "module"` is set in `package.json`). `broccoli-middleware` is a CommonJS module.fixRename your file to `.cjs` or ensure `"type": "commonjs"` is set in your `package.json`. If using an ES module, consider dynamic import: `const broccoliMiddleware = await import('broccoli-middleware');` or refactor the consuming code to use a CJS wrapper. -
Error: The 'secret' option is required for sessions.
cause Not directly related to `broccoli-middleware` itself, but often encountered when `broccoli-middleware` is used within larger Ember CLI setups that include Express or Connect servers with session middleware configured incorrectly or without a secret key.fixEnsure your session middleware (e.g., `express-session`) is configured with a `secret` option, for example: `app.use(session({ secret: process.env.SESSION_SECRET || 'a-very-secret-key', ... }));`.
Warnings
- breaking broccoli-middleware is an abandoned project. It has not been updated since 2019 and targets older Node.js versions (6, 8, >=10). It is highly unlikely to be compatible with modern Node.js environments or current versions of Broccoli without significant workarounds.
- gotcha This package uses CommonJS modules (`require`). Attempting to `import` it in an ESM context will result in a `SyntaxError: Cannot use import statement outside a module` or similar error.
- deprecated While functional for its original purpose within Ember CLI, using `broccoli-middleware` outside of an existing legacy Ember CLI setup is strongly discouraged. Modern web development workflows provide more robust and actively maintained solutions for asset serving and bundling.
Install
-
npm install broccoli-middleware -
yarn add broccoli-middleware -
pnpm add broccoli-middleware
Imports
- broccoliMiddleware
import broccoliMiddleware from 'broccoli-middleware';
const broccoliMiddleware = require('broccoli-middleware');
Quickstart
const express = require('express');
const path = require('path');
const fs = require('fs');
const broccoliMiddleware = require('broccoli-middleware');
// Simulate a Broccoli builder output structure
const outputDir = path.join(__dirname, 'tmp/broccoli-output');
fs.mkdirSync(outputDir, { recursive: true });
fs.writeFileSync(path.join(outputDir, 'app.js'), 'console.log("Hello from Broccoli!");');
fs.writeFileSync(path.join(outputDir, 'styles.css'), 'body { background-color: lightblue; }');
const app = express();
// In a real Ember CLI app, `watcher` and `builder` would be provided by ember-cli.
// For this example, we'll mock the 'builder' interface to return a fixed directory.
const mockBuilder = {
// The `builder.outputPath` is what broccoli-middleware expects.
outputPath: outputDir
};
app.use(broccoliMiddleware(mockBuilder));
app.get('/', (req, res) => {
res.send(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Broccoli Middleware Example</title>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<h1>Welcome to Broccoli Middleware!</h1>
<script src="/app.js"></script>
<p>Assets served dynamically from Broccoli's output.</p>
</body>
</html>
`);
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server listening on http://localhost:${PORT}`);
console.log('Try visiting http://localhost:3000/app.js and http://localhost:3000/styles.css');
console.log('Note: In a real scenario, mockBuilder would be a live Broccoli builder producing actual changes.');
});
// Cleanup on exit (optional for a quickstart, but good practice)
process.on('exit', () => {
try { fs.rmSync(path.join(__dirname, 'tmp'), { recursive: true, force: true }); } catch (e) {}
});