How can I use webpack with express? - javascript

When I try to use webpack with a simple express server I always get TONS of errors:
express.js
'use strict';
var express = require('express');
var path = require('path');
var url = require('url');
// -------- my proxy----------------------
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.set('port', process.env.PORT || 8080);
app.use(function logErrors(err, req, res, next) {
console.error(err.stack);
next(err);
}
);
app.listen(app.get('port'), function() {
console.info('Express server started at http://localhost:' + app.get('port'));
});
I get all those errors:
Version: webpack 1.10.0
Time: 1200ms
Asset Size Chunks Chunk Names
outfile 559 kB 0 [emitted] main
chunk {0} outfile (main) 498 kB [rendered]
[0] ../app/server/express2.js 553 bytes {0} [built]
+ 125 hidden modules
WARNING in ../~/express/lib/view.js
Critical dependencies:
78:29-56 the request of a dependency is an expression
# ../~/express/lib/view.js 78:29-56
ERROR in ../~/express/lib/request.js
Module not found: Error: Cannot resolve module 'net' in /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/lib
# ../~/express/lib/request.js 18:11-25
ERROR in ../~/express/lib/view.js
Module not found: Error: Cannot resolve module 'fs' in /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/lib
# ../~/express/lib/view.js 18:9-22
ERROR in ../~/express/~/send/index.js
Module not found: Error: Cannot resolve module 'fs' in /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/node_modules/send
# ../~/express/~/send/index.js 25:9-22
ERROR in ../~/express/~/etag/index.js
Module not found: Error: Cannot resolve module 'fs' in /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/node_modules/etag
# ../~/express/~/etag/index.js 22:12-25
ERROR in ../~/express/~/send/~/destroy/index.js
Module not found: Error: Cannot resolve module 'fs' in /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/node_modules/send/node_modules/destroy
# ../~/express/~/send/~/destroy/index.js 1:17-30
ERROR in ../~/express/~/send/~/mime/mime.js
Module not found: Error: Cannot resolve module 'fs' in /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/node_modules/send/node_modules/mime
# ../~/express/~/send/~/mime/mime.js 2:9-22
ERROR in ../~/express/~/send/~/statuses/codes.json
Module parse failed: /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/node_modules/send/node_modules/statuses/codes.json Line 2: Unexpected token :
You may need an appropriate loader to handle this file type.
| {
| "100": "Continue",
| "101": "Switching Protocols",
| "102": "Processing",
# ../~/express/~/send/~/statuses/index.js 2:12-35
ERROR in ../~/express/~/send/~/mime/types.json
Module parse failed: /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/node_modules/send/node_modules/mime/types.json Line 1: Unexpected token :
You may need an appropriate loader to handle this file type.
|
# ../~/express/~/send/~/mime/mime.js 87:12-35
ERROR in ../~/express/~/accepts/~/mime-types/~/mime-db/db.json
Module parse failed: /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/node_modules/accepts/node_modules/mime-types/node_modules/mime-db/db.json Line 2: Unexpected token :
You may need an appropriate loader to handle this file type.
| {
| "application/1d-interleaved-parityfec": {
| "source": "iana"
| },
# ../~/express/~/accepts/~/mime-types/~/mime-db/index.js 11:17-37
ERROR in ../~/express/~/type-is/~/mime-types/~/mime-db/db.json
Module parse failed: /Users/Dynopia/Development/DS_Stalker_Frontend/node_modules/express/node_modules/type-is/node_modules/mime-types/node_modules/mime-db/db.json Line 2: Unexpected token :
You may need an appropriate loader to handle this file type.
| {
| "application/1d-interleaved-parityfec": {
| "source": "iana"
| },
# ../~/express/~/type-is/~/mime-types/~/mime-db/index.js 11:17-37
and this is my config file:
var webpack = require('webpack');
module.exports = {
// Makes sure errors in console map to the correct file
// and line number
devtool: 'eval',
entry: [
'./bin/www.js'
],
output: {
path: './bin/out',
filename: 'server.js'
},
extensions: [
'',
'.jsx', '.js'
],
module: {
loaders: [
// Compile es6 to js.
{
test: /app\/.*\.js?$/,
loaders: [
'react-hot',
'babel-loader'
]
}
]
},
devtool: 'source-map'
};
What can I do, I need to use webpack on my server side as well.
I run the express.js file like so:
./node_modules/webpack/bin/webpack.js ../app/server/express.js outfile --display-chunks -c --progress -d

What I ended up doing was I used 2 different configurations, 1 for packing the server stuff together using webpack, and 1 for packing all the browser stuff together and also run webpack dev server for hot reloading.
Server webpack config aka webpack.node.config.js now looks like this:
var webpack = require('webpack');
var path = require('path');
var fs = require('fs');
var nodeModules = {};
// note the path.resolve(__dirname, ...) part
// without it, eslint-import-resolver-webpack fails
// since eslint might be invoked with different cwd
fs.readdirSync(path.resolve(__dirname, 'node_modules'))
.filter(x => ['.bin'].indexOf(x) === -1)
.forEach(mod => { nodeModules[mod] = `commonjs ${mod}`; });
// es5 style alternative
// fs.readdirSync(path.resolve(__dirname, 'node_modules'))
// .filter(function(x) {
// return ['.bin'].indexOf(x) === -1;
// })
// .forEach(function(mod) {
// nodeModules[mod] = 'commonjs ' + mod;
// });
module.exports =
{
// The configuration for the server-side rendering
name: 'server',
target: 'node',
entry: './app/server/serverEntryPrototype.js',
output: {
path: './bin/',
publicPath: 'bin/',
filename: 'serverEntryPoint.js'
},
externals: nodeModules,
module: {
loaders: [
{ test: /\.js$/,
loaders: [
// 'imports?document=this',
// 'react-hot',
'babel-loader'
//,'jsx-loader'
]
},
{ test: /\.json$/, loader: 'json-loader' },
]
},
plugins: [
// new webpack.NormalModuleReplacementPlugin("^(react-bootstrap-modal)$", "^(react)$")
// new webpack.IgnorePlugin(new RegExp("^(react-bootstrap-modal)$"))
// new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
]
};
Browser webpack config aka webpack.browser.config.js now looks like this:
var webpack = require('webpack');
var path = require('path');
var buildPath = path.resolve(__dirname, 'assets');
var fs = require('fs');
var commonLoaders = [
{ test: /\.js$/,
loaders: [
'react-hot',
'babel-loader'
//,'jsx-loader'
]
}
];
module.exports =
{
// Makes sure errors in console map to the correct file
// and line number
name: 'browser',
devtool: 'eval',
entry: [
//'./bin/www.js',
'./app/index.js',
'webpack/hot/dev-server',
'webpack-dev-server/client?http://localhost:8081' // WebpackDevServer host and port
],
output: {
path: buildPath,
filename: '[name].js',
// Everything related to Webpack should go through a build path,
// localhost:3000/build. That makes proxying easier to handle
publicPath: 'http://localhost:8081/assets/'
},
extensions: [
'',
'.jsx', '.js',
'.json',
'.html',
'.css', '.styl', '.scss', '.sass'
],
module: {
loaders: [
// Compile es6 to js.
{
test: /app\/.*\.jsx?$/,
loaders: [
'react-hot',
'babel-loader'
]
},
///app\/.*\.json$/
{ test: /\.json$/, loader: 'json-loader' },
// Styles
{ test: /\.css$/, loader: 'style-loader!css-loader' },
{ test: /\.s(a|c)ss$/, loader: 'style!css?localIdentName=[path][name]---[local]---[hash:base64:5]!postcss!sass' },
// Fonts
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader?limit=10000&minetype=application/font-woff' },
{ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'file-loader' }
//{ test: /\.png$/, loader: 'url-loader?limit=100000' },
//{ test: /\.jpg$/, loader: 'file-loader' }
],
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
]
},
postcss: [
require('autoprefixer-core')
],
devtool: 'source-map'
}
;

It can be realized by specifying "node" to "target" option, since v1.10.2.
For reference: http://jlongster.com/Backend-Apps-with-Webpack--Part-I
If you want to bundle the server and the client's code at the same time, it is possible to use multiple configuration in the following manner.
// webpack.config.js
module.exports = [
{
name: 'server',
entry: './src/server/index.js',
target: 'node',
output: {
path: __dirname + '/dist/server',
filename: 'bundle.js',
},
},
{
name: 'client',
entry: './src/client/index.js',
// target: 'web', // by default
output: {
path: __dirname + '/dist/client',
filename: 'bundle.js',
},
}
];

I am just clarifying #meta2's answer because I believe it can be written in a more understandable way - although full points to him!
tl;dr - set target: 'node' in your webpack.config.js to fix the errors that get generated when using Webpack with Express.
You still get warnings like:
WARNING in ./node_modules/express/lib/view.js
81:13-25 Critical dependency: the request of a dependency is an expression
To fix those, use https://github.com/liady/webpack-node-externals. FYI - this reduces you bundle size significantly (check size before and after) and speeds up the bundling time incredibly.
Full example:
const path = require('path')
const nodeExternals = require('webpack-node-externals')
module.exports = {
entry: './src/app.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
target: 'node', // THIS IS THE IMPORTANT PART
externals: [nodeExternals()],
mode: 'development'
}

Additionally, if you are working with Typescript, make sure to also include the ".js" extension in your config:
module.exports = {
entry: './src/server/index.ts',
target: 'node',
output: {
path: __dirname + '/dist/server',
filename: 'bundle.js',
},
resolve: {
modules: [
"node_modules"
],
extensions: [".ts", ".js"]
}
};

I took an easy approach that could be useful in a small or medium project. I make it so webpack would serve as the bundler for ecma script and scss, though in this aproach i dont use hot reloading.
The server configuration is the default given by express generator.
webpack.config.js
const path = require("path");
module.exports = {
entry: "./resources/index.js",
output: {
path: path.join(__dirname, "/public/dist"),
publicPath: "/public/dist",
filename: "main.js"
},
mode: "development",
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"]
}
]
}
};
package.json is devDependencies
"devDependencies": {
"#babel/core": "^7.6.4",
"#babel/preset-env": "^7.6.3",
"babel-loader": "^8.0.6",
"css-loader": "^3.2.0",
"mini-css-extract-plugin": "^0.8.0",
"node-sass": "^4.13.0",
"sass-loader": "^8.0.0",
"style-loader": "^1.0.0",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.9"
}
package.json is scripts
"scripts": {
"start": "node ./bin/www",
"dev": "nodemon",
"build": "webpack",
"watch": "webpack --watch"
},

Here is a simple setup to build an express+webpack app. Please pay attention to package.json file scripts part which starts simultaneously express server and webpack process.
And also please pay attention server.js file "app.use(express.static('dist'));" part. Express static should point to webpack folder which contains index.html and bundle.js
server.js file:
const express = require ("express");
const path = require ("path");
const app = express();
app.use(express.json());
app.use(express.urlencoded({extended: true}));
app.use(express.static('dist'));
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.html'));
})
const server = app.listen (process.env.PORT || 4000);
const portNumber = server.address().port;
console.log("ГОСПОДИН ПОРТ СЕИЧАС ОТКРЫТ "+ portNumber);
now package.json file:
{
"name": "firebase1",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack",
"server": "node server.js",
"dev": "concurrently --kill-others-on-fail \"npm run build\" \"npm run server\""
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.64.0",
"webpack-cli": "^4.9.1"
},
"dependencies": {
"express": "^4.17.1"
}
}
Now, webpack.config.js file:
const path = require("path");
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js"
},
watch: true
}
And finally index.html file:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FIREBASE PROJECT OF MY LORD TOM AND JERRY</title>
</head>
<body>
<h1>Getting Started with Firebase</h1>
<script type="text/javascript" src="bundle.js"></script>
</body>
</html>

Related

Remove console on browser when loading react app with npm start via webpack-dev-server

So after npm build and npm run , why does my react application open with console on the screen? It was not happening when my packages were "webpack-cli": "^4.2.0" and "webpack-dev-server": "^3.11.1". Upgrading them is causing this issue. How can we fix this?
My package.json contains (devDependencies)
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^7.0.0",
"webpack": "^5.11.0",
"webpack-bundle-analyzer": "^4.3.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.3",
"webpack-manifest-plugin": "2.2.0",
"webpack-merge": "^5.7.2"
"eslint-webpack-plugin": "^2.1.0",
"html-webpack-plugin": "5.3.2",
"scripts": {
"start": "webpack serve --config config/webpack.config.js --env TARGET_ENV=development --env app=web --port 3000",
"build": "webpack --config config/webpack.config.js --env TARGET_ENV=production",
"build:staging": "webpack --config config/webpack.config.js --env TARGET_ENV=staging"
}
webpack.config.js
const { merge } = require("webpack-merge");
//const commonConfig = require("./webpack.common.js");
const paths = require("./paths");
const webpack = require("webpack");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ESLintPlugin = require("eslint-webpack-plugin");
const getClientEnvironment = require("./env");
module.exports = (env) => {
const targetEnv = env.TARGET_ENV;
const mode = targetEnv === "development" ? "development" : "production";
process.env.NODE_ENV = mode;
// Source maps are resource heavy and can cause out of memory issue for large source files.
// const shouldUseSourceMap = webpackEnv === "development";
const commonConfig = {
mode: mode,
// Where webpack looks to start building the bundle
entry: {
web: paths.src + "/web.tsx",
},
// Where webpack outputs the assets and bundles
resolve: {
extensions: [".tsx", ".ts", ".js"],
fallback: {
util: require.resolve("util/"),
},
modules: ["node_modules", "./src"],
},
// Customize the webpack build process
plugins: [
new webpack.ProvidePlugin({
process: "process/browser",
}),
// Makes some environment variables available to the JS code, for example:
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
// It is absolutely essential that NODE_ENV is set to production
// during a production build.
// Otherwise React will be compiled in the very slow development mode.
new webpack.DefinePlugin(getClientEnvironment(targetEnv).stringified),
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/locale$/,
contextRegExp: /moment$/,
}),
// Removes/cleans build folders and unused assets when rebuilding
new CleanWebpackPlugin(),
// Copies files from target to destination folder
new CopyWebpackPlugin({
patterns: [
{
from: paths.public,
to: paths.build,
globOptions: {
ignore: ["**/*.html"],
},
},
{
from: paths.appPath + "/web.config",
to: paths.build,
},
],
}),
// Generates an HTML file from a template
// Generates deprecation warning: https://github.com/jantimon/html-webpack-plugin/issues/1501
new HtmlWebpackPlugin({
//favicon: paths.src + "/images/favicon.png",
template: paths.public + "/web.html", // template file
chunks: ["vendor", "web"],
filename: "web.html", // output file
inject: true,
}),
new HtmlWebpackPlugin({
template: paths.public + "/crossplatform.html", // template file
chunks: ["vendor", "crossplatform"],
filename: "crossplatform.html", // output file
inject: true,
}),
new ESLintPlugin({
// Plugin options
extensions: ["js", "jsx", "ts", "tsx"],
}),
],
// Determine how modules within the project are treated
module: {
rules: [
// JavaScript: Use Babel to transpile JavaScript files
{
test: /\.(ts|js)x?$/,
include: paths.src,
//exclude: /node_modules/,
loader: "babel-loader",
options: {
cacheDirectory: true,
// See #6846 for context on why cacheCompression is disabled
cacheCompression: false,
// Babel sourcemaps are needed for debugging into node_modules
// code. Without the options below, debuggers like VSCode
// show incorrect code and set breakpoints on the wrong lines.
//sourceMaps: shouldUseSourceMap,
//inputSourceMap: shouldUseSourceMap,
},
},
// Images: Copy image files to build folder
{ test: /\.(?:ico|gif|png|jpg|jpeg)$/i, type: "asset/resource" },
// Fonts and SVGs: Inline files
{ test: /\.(woff(2)?|eot|ttf|otf|svg|)$/, type: "asset/inline" },
],
},
};
const envConfig = require(`./webpack.${mode}.js`)({ app: env.app });
return merge(commonConfig, envConfig);
};
webpack.development.js
const webpack = require("webpack");
const paths = require("./paths");
module.exports = (args) => {
return {
// Control how source maps are generated
devtool: "cheap-module-source-map",
output: {
//path: paths.build,
publicPath: "./",
filename: "[name].js",
},
// Needed because of an issue with webpack dev server HMR with Webpack https://github.com/webpack/webpack-dev-server/issues/2758
target: "web",
// Spin up a server for quick development
devServer: {
historyApiFallback: {
index: "/" + args.app + ".html",
},
open: true,
devMiddleware: {
publicPath: "/",
},
hot: true,
// By default files from `contentBase` will not trigger a page reload.
// watchContentBase: true,
},
module: {
rules: [
// Styles: Inject CSS into the head with source maps
{
test: /\.(css)$/,
use: [
"style-loader",
{
loader: "css-loader",
//options: { sourceMap: true },
},
],
},
],
},
};
};

Webpack bundle Node Express with hot reloading = hell

I hate to admit it, but I've been spending three long evenings trying to do - what I thought would be straightforward thing to do. I finally reached the stage where I'm fed up with it, and frankly rather frustrated because "it just won't work".
Here is what I try to achieve:
Bundle my Express server with Webpack (although my current code just renders a string in the browser, it is supposed to compile server rendered React components compiled with Babel)
Save the bundle in memory (or on disk if there is no other way)
Run webpack / dev / hot middleware to serve my Node Express app in a way that changes to the server rendered pages (which will be React components) will auto-update in the browser.
I've tried numerous combinations, tutorials that have been deprecated, npm packages that are no longer maintained and downloaded examples that just don't work.
Here is my current setup:
webpack.server.config.js:
const path = require('path');
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');
module.exports = {
name: 'server',
mode: 'development',
target: 'node',
externals: nodeExternals(),
entry: [ './src/server/index' ],
output: {
path: path.resolve(__dirname, 'dist'),
// path: "/",
filename: '[name].js',
publicPath: '/assets/',
libraryTarget: 'commonjs2'
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
module: {
rules: [
{
test: /.js$/,
loader: 'babel-loader',
include: path.resolve(__dirname, 'src/'),
exclude: /node_modules/,
options: {
presets:
[['#babel/preset-env', { modules: 'false' }], '#babel/preset-react'],
plugins: [
['#babel/plugin-proposal-object-rest-spread', { useBuiltIns: true }],
'#babel/plugin-proposal-class-properties'
]
}
},
{
test: /\.scss$/,
loader: 'ignore-loader'
},
{
test: /\.css$/,
loader: 'ignore-loader'
},
{
test: /\.(jpg|png|svg|gif|pdf)$/,
loader: 'file-loader',
options: {
name: '[path][name].[ext]'
}
}
]
}
};
index.js:
import http from 'http';
import fs from "fs";
import express from "express";
import favicon from 'serve-favicon';
// import renderer from "./renderer";
import renderApp from './welcome';
const app = express();
app.use(favicon('./public/favicon.ico'));
app.use(express.static("public"));
if (process.env.NODE_ENV !== 'production') {
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const serverConfig = require('../../webpack.server.config');
const compiler = webpack(serverConfig);
app.use(webpackDevMiddleware(compiler, {
stats: {colors: true},
headers: { "Access-Control-Allow-Origin": "http://localhost"},
publicPath: serverConfig.output.publicPath
}));
app.use(require("webpack-hot-middleware")(compiler));
}
app.get("*", function(req, res) {
fs.readFile("./src/server/html/index.html", "utf8", function(err, data) {
const context = {};
const html = renderApp();
//const html = renderer(data, req.path, context);
res.set('content-type', 'text/html');
res.send(html);
res.end();
});
});
const PORT = process.env.PORT || 8080;
app.listen(3000);
Frankly I'm also rather confused about how this is supposed to work.
Are the following steps supposed to be executed?:
webpack webpack.server.config.js --watch
node dist/server.js // webpack output folder
Would this magically hot reload my server?
All help is welcome, or if you happened to have a working demo.
I just couldn't manage to make this work.
In the end I will also hot reload (re-render) my client bundle but I guess that will be the easy part as I've seen many, many resources about that.
Night sleep was probably needed.
I got this working (incl with React server rendered components) using StartServerPlugin.
Following setup hot reloads the Node Express server:
const path = require('path');
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');
const StartServerPlugin = require('start-server-webpack-plugin');
module.exports = {
name: 'server',
mode: 'development',
target: 'node',
externals: nodeExternals({
whitelist: ['webpack/hot/poll?1000']
}),
entry: [ 'webpack/hot/poll?1000', './src/server/index' ],
output: {
path: path.resolve(__dirname, 'dist'),
// path: "/",
filename: 'server.js',
publicPath: '/assets/',
libraryTarget: 'commonjs2'
},
plugins: [
new StartServerPlugin({'name': 'server.js', nodeArgs: ['--inspect']}),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
"process.env": {
"BUILD_TARGET": JSON.stringify('server')
}
})
],
module: {
rules: [
{
test: /.js$/,
loader: 'babel-loader',
include: path.resolve(__dirname, 'src/'),
exclude: /node_modules/,
options: {
presets:
[['#babel/preset-env', { modules: 'false' }], '#babel/preset-react'],
plugins: [
['#babel/plugin-proposal-object-rest-spread', { useBuiltIns: true }],
'#babel/plugin-proposal-class-properties'
]
}
},
{
test: /\.scss$/,
loader: 'ignore-loader'
},
{
test: /\.css$/,
loader: 'ignore-loader'
},
{
test: /\.(jpg|png|svg|gif|pdf)$/,
loader: 'file-loader',
options: {
name: '[path][name].[ext]'
}
}
]
}
};
index.js:
import http from 'http'
import app from './server'
const server = http.createServer(app)
let currentApp = app;
const PORT = process.env.PORT || 8080;
server.listen(PORT);
if (module.hot) {
module.hot.accept('./server', () => {
server.removeListener('request', currentApp);
server.on('request', app);
currentApp = app;
})
}
server.js:
import http from 'http';
import fs from "fs";
import express from "express";
import favicon from 'serve-favicon';
import renderer from "./renderer";
import renderApp from './welcome';
const app = express();
app.use(favicon('./public/favicon.ico'));
app.use(express.static("public"));
app.get("*", function(req, res) {
fs.readFile("./src/server/html/index.html", "utf8", function(err, data) {
const context = {};
//const html = renderApp();
console.log('test');
const html = renderer(data, req.path, context);
res.set('content-type', 'text/html');
res.send(html);
res.end();
});
});
export default app;
Run with:
rm -rf ./dist && webpack --config webpack.server.config.js --watch
I think anwsers here are bit too complicated. It seems that Webpack does not make this easy.
Rather than trying to cook up complicated configurations, I took the issue in my own hand and created a small devserver, that does both the webpack build and server reload upon file changes. The client also has a reload logic, so the page in both cases is auto reloaded.
hot module reload for express server and webpack client
Synopsis
devserver
const fetch = require('node-fetch')
let process
function spawnserver(){
process = require('child_process').spawn("node", ["server/server.js", "dev"])
process.stdout.on('data', (data) => {
console.error(`stdout: ${data}`)
})
process.stderr.on('data', (data) => {
console.error(`stderr: ${data}`)
})
}
function rebuildsrc(){
process = require('child_process').spawn("npm", ["run", "build"])
process.stdout.on('data', (data) => {
console.error(`stdout: ${data}`)
})
process.stderr.on('data', (data) => {
console.error(`stderr: ${data}`)
})
process.on("close", code => {
console.log("build exited with code", code)
fetch("http://localhost:3000/reloadsrc").then(response=>response.text().then(content=>console.log(content)))
})
}
spawnserver()
const watcher = require("chokidar").watch("./server")
watcher.on("ready", _=>{
watcher.on("all", _=>{
console.log("server reload")
process.kill()
spawnserver()
})
})
const srcWatcher = require("chokidar").watch("./src")
srcWatcher.on("ready", _=>{
srcWatcher.on("all", _=>{
console.log("rebuild src")
rebuildsrc()
})
})
client reload
let stamp = new Date().getTime()
let lastStamp = null
app.get('/stamp', (req, res) => {
lastStamp = new Date().getTime()
res.send(`${stamp}`)
})
app.get('/reloadsrc', (req, res) => {
stamp = new Date().getTime()
res.send(`updated stamp to ${stamp}`)
})
let welcomeMessage = "Welcome !!"
let reloadScript = IS_PROD ? ``:`
let stamp = null
let reloadStarted = false
setInterval(_=>{
fetch('/stamp').then(response=>response.text().then(content=>{
if(stamp){
if(content != stamp) setTimeout(_=>{
if(!reloadStarted){
console.log("commence reload")
setInterval(_=>{
fetch(document.location.href).then(response=>response.text().then(content=>{
if(content.match(/Welcome/)){
console.log("reloading")
document.location.reload()
}
}))
}, 1000)
reloadStarted = true
}
}, 500)
}else{
if(!reloadStarted){
stamp = content
console.log("stamp set to", stamp)
}
}
}))
}, 200)
`
app.use('/dist', express.static('dist'))
app.get('/', (req, res) => {
res.send(`
<!doctype html>
<head>
<title>Reload Express Sample App</title>
</head>
<body>
<h1>${welcomeMessage}</h1>
<script>
${reloadScript}
</script>
<script src="dist/bundle.js"></script>
</body>
</html>
`)
})
Node.js, babel and webpack have been the bane of my month. There's several components that should be included. You should have a start file called "package.json"
The contents should look like:
{
"name": "react-complete-guide",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server",
"build": "rimraf dist && webpack --config webpack.prod.config.js --progress --profile --color"
},
"author": "",
"license": "ISC",
"devDependencies": {
"autoprefixer": "^7.1.5",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-preset-env": "^1.6.0",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"css-loader": "^0.28.7",
"file-loader": "^1.1.5",
"html-webpack-plugin": "^2.30.1",
"postcss-loader": "^2.0.7",
"style-loader": "^0.19.0",
"url-loader": "^0.6.2",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.9.1"
},
"dependencies": {
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-router-dom": "^4.2.2"
}
}
If you type "npm start", then the bit of code "start": "webpack-dev-server" is run. This will load a preview of the code.
To package the contents into a build you type "npm run build" and that will run the code "build": "rimraf dist && webpack --config webpack.prod.config.js --progress --profile --color". That code will run the "rimraf", which deletes the "dist" folder if it exists, the rest runs the webpack config file.
You should have two webpack files. One for hot reloads and one for packaging for the production environment. The files should be called:
"webpack.config.js" and "webpack.prod.config.js".
The contents of "webpack.config.js" look like this:
const path = require('path');
const autoprefixer = require('autoprefixer');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'cheap-module-eval-source-map',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
chunkFilename: '[id].js',
publicPath: ''
},
resolve: {
extensions: ['.js', '.jsx']
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
exclude: /node_modules/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: true,
localIdentName: '[name]__[local]__[hash:base64:5]'
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
autoprefixer({
browsers: [
"> 1%",
"last 2 versions"
]
})
]
}
}
]
},
{
test: /\.(png|jpe?g|gif)$/,
loader: 'url-loader?limit=8000&name=images/[name].[ext]'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: __dirname + '/src/index.html',
filename: 'index.html',
inject: 'body'
})
]
};
The contents of "webpack.prod.config.js" look like this:
const path = require('path');
const autoprefixer = require('autoprefixer');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
module.exports = {
devtool: 'cheap-module-source-map',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist/new'),
filename: 'bundle.js',
chunkFilename: '[id].js',
publicPath: ''
},
resolve: {
extensions: ['.js', '.jsx']
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
exclude: /node_modules/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: true,
localIdentName: '[name]__[local]__[hash:base64:5]'
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
autoprefixer({
browsers: [
"> 1%",
"last 2 versions"
]
})
]
}
}
]
},
{
test: /\.(png|jpe?g|gif)$/,
loader: 'url-loader?limit=8000&name=images/[name].[ext]'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: __dirname + '/src/index.html',
filename: 'index.html',
inject: 'body'
}),
new webpack.optimize.UglifyJsPlugin()
]
};
You also need a file to tell babel how to act. The file is called ".babelrc" if you are using babel. The contents look like this
{
"presets": [
["env", {
"targets": {
"browsers": [
"> 1%",
"last 2 versions"
]
}
}],
"stage-2",
"react"
],
"plugins": [
"syntax-dynamic-import"
]
}
There's a lot going on in this code. I strongly recomment watching some tutorial videos on this.

Webpack dev server don't reload page when rebuild file

I'm currently trying to put my webpack-dev-server on, but when I save my file and this been rebuild correctly my page dont't reload.
I use this script for ejecute:
"start": "webpack-dev-server --mode development --host myIP --port 8080" (Also I tried with --hot --inline and didn't work too)
Here is my webpack config:
const path = require('path');
const basedir = path.join(__dirname, '../');
module.exports = {
entry: {
theme: path.join(basedir, 'assets/js', 'theme.js'),
custom: path.join(basedir, 'assets/js', 'custom.js'),
},
output: {
path: path.join(basedir, 'assets/js'),
filename: '[name]real.js'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
}
]
}
};
And I import theme.js for example with:
<script src='http://myIP:8080/themereal.js'></script>
I tried also with hot-module-replacement and it didn't work.
After search a lot I saw in the client console the following error:
Invalid Host/Origin header client:187:9
[WDS] Disconnected!
Then I search how to fix this and found --disable-host-check option, which works to me!
"start": "webpack-dev-server --mode development --host myIP --port 8080 --disable-host-check"
I hope this will be useful for somebody more!
You need to set the watch mode. Here is an example file i recently used.
You need not to set any more attributes in dev mode.
webpack --mode development
This config is webpack 4+
const path = require('path');
const webpack = require('webpack');
const HtmlWebPackPlugin = require("html-webpack-plugin");
module.exports = (env, argv) => {
const {
mode
} = argv;
return {
module: {
entry: path.join(__dirname, 'src', 'app.js'),
watch: mode !== 'production',
output: {
path: path.join(__dirname, 'dist'),
filename: mode === 'production' ? 'bundle.min.js' : 'bundle.js'
},
rules: [{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
}
],
plugins: [
new HtmlWebPackPlugin({
title: 'App',
template: "./src/index.html",
filename: "./index.html"
})
]
},
devServer: {
contentBase: path.join(__dirname, 'dist')
}
};
}

Getting Error: Module parse failed: ... unexpected character '#'

I am using webpack for the first time and want to use some css with my react/redux application. I followed a guide, but still seem to be having problems. I am getting the above error as you can see.
folder structure looks like this:
.git
-node_modules
-public
-bundle.js
-index.html
-src
-actions
-components
-reducers
app.js
-style
-style.css
.babelrc
.gitingore
package-lock.json
package.json
README.md
server.js
webpack.config.js
This is the exact error:
Uncaught Error: Module parse failed: C:\Users\Amazo\projects\reduxApp\style\style.css Unexpected character '#' (1:0)
You may need an appropriate loader to handle this file type.
| #row1 {
| margin-top: 15px;
| }
I will post my webpack config file below:
var path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
var HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/app.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'public')
},
watch: true,
module: {
rules: [
{
test: /\.js$/,
exclude:/node_modules/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-1']
}
},
{
use: ['style-loader', 'css-loader'],
test: /\.css$/
}
]
},
resolve: {
extensions: ['.js','.jsx']
},
plugins: [
new HTMLWebpackPlugin({
template: 'public/index.html';
}),
new ExtractTextPlugin('style.css')
]
};
Add .css to your resolve
resolve: {
extensions: ['.js','.jsx', '.css']
},
Otherwise, webpack won't be able to process it correctly

Webpack2 throws error when running webpack-dev-server

I have the following webpack config file:
var webpack = require('webpack');
var config = {
context: __dirname + '/src', // `__dirname` is root of project and `src` is source
entry: {
app: './app.js',
},
output: {
path: __dirname + '/dist', // `dist` is the destination
filename: '[name].bundle.js',
},
devServer: {
open: true, // to open the local server in browser
contentBase: __dirname + '/src'
},
module: {
rules: [
{
test: /\.js$/, //Check for all js files
use: [{
loader: 'babel-loader',
options: { presets: ['es2015'] }
}]
}
]
}
};
module.exports = config;
when I run "webpack-dev-server" I get the following error:
ERROR in (webpack)-dev-server/client?http://localhost:8080
Module build failed: Error: Couldn't find preset "es2015" relative to directory "/usr/local/lib/node_modules/webpack-dev-server/client/index.js?http:/"
Faced the same problem following a tutorial on Udemy. Adding the .babelrc worked for me.

Categories

Resources