Using webpack > 5
version. Below is my appDevMiddleware.js
congifuration
const path = require('path'); const webpack = require('webpack'); const webpackDevMiddleware = require('webpack-dev-middleware'); const webpackHotMiddleware = require('webpack-hot-middleware'); function createWebpackMiddleware(compiler, publicPath) { return webpackDevMiddleware(compiler, { // noInfo: true, publicPath, // silent: true, stats: 'errors-only', }); } module.exports = function addDevMiddlewares(app, webpackConfig) { const compiler = webpack(webpackConfig); const middleware = createWebpackMiddleware(compiler, webpackConfig.output.publicPath); app.use(middleware); app.use(webpackHotMiddleware(compiler)); // Since webpackDevMiddleware uses memory-fs internally to store build // artifacts, we use it instead const fs = middleware.fileSystem; app.get('*', (req, res) => { fs.readFile(path.join(compiler.outputPath, 'index.html'), (err, file) => { if (err) { res.sendStatus(404); } else { res.send(file.toString()); } }); }); };
When i do npm start
of my React App, i’m getting
TypeError: Cannot read property 'readFile' of undefined at D:master-instore-dashboardservermiddlewaresaddDevMiddlewares.js:29:8
This is exactly showing here
fs.readFile(path.join(compiler.outputPath, 'index.html'), (err, file) => {
I will have to somehow use the promises
for readFile which is something like const { readFile } = require('fs').promises
How should i replace const fs = middleware.fileSystem;
with promise for this issue?
Advertisement
Answer
webpack-dev-middleware
uses memfs as its default outputFileSystem. WDM
didn’t expose the API so that you can NOT get the outputFileSystem
from the instance of WDM
. That’s why you got that error.
You should create your own outputfilesystem
, you can use the memfs
to do that explicitly. Then, you can get the index.html
from the memory file system.
You can use util.promisify()
method from util
Node.js built-in module to promisify the fs.readFile
method.
E.g.
webpack.config.js
:
const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = { entry: path.resolve(__dirname, "src/index.js"), output: { path: path.resolve(__dirname, "dist"), filename: "bundle.js", }, plugins: [new HtmlWebpackPlugin({ template: "./src/index.html" })], mode: "development", };
app.js
:
const path = require("path"); const util = require("util"); const express = require("express"); const webpack = require("webpack"); const webpackDevMiddleware = require("webpack-dev-middleware"); const { createFsFromVolume, Volume } = require("memfs"); const webpackConfig = require("./webpack.config"); const compiler = webpack(webpackConfig); const app = express(); const fs = createFsFromVolume(new Volume()); fs.join = path.join.bind(path); const readFile = util.promisify(fs.readFile); const middleware = webpackDevMiddleware(compiler, { publicPath: webpackConfig.output.publicPath, stats: "errors-only", outputFileSystem: fs, }); app.use(middleware); app.get("*", async (req, res) => { try { const file = await readFile(path.join(compiler.outputPath, "index.html")); res.send(file.toString()); } catch (error) { res.sendStatus(404); } }); app.listen(3000, () => console.log("Example app listening on port 3000!"));
Start the server:
⚡ node app.js Example app listening on port 3000!
Access http://localhost:3000/test
:
⚡ curl http://localhost:3000/test <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script defer src="bundle.js"></script></head> <body> </body> </html>
package version:
{ "name": "68618902", "devDependencies": { "html-webpack-plugin": "^5.3.2", "memfs": "^3.2.2", "webpack": "^5.51.1", "webpack-dev-middleware": "^5.0.0" }, "dependencies": { "express": "^4.17.1" } }