Separate client and server in Webpack - node.js

Goal. Configuring app, which has: React, Webpack and MongoDB.
So, I've already setup Webpack for React and tried import Mongoose. The problem: React client-side and Mongoose - server-side, and because of that Webpack must have configurations for both. Using this answer: https://stackoverflow.com/a/37391247/7479176 I tried to configure Webpack. After that, I tried import Mongoose in my server.jsx file, but it didn't work.
Question. How to configure Webpack, so I can work with MongoDB?
Edited. I figured out how to rid of warnings (see Warnings):
output: {
filename: 'bundle.node.js',
libraryTarget: 'commonjs',
path: path.resolve(__dirname, 'dist')
},
externals: [
/^(?!\.|\/).+/i
],
But, when I added code into server.jsx (see server.jsx), it didn't log message in console.
Webpack configurations:
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = [
{
entry: {
index: './src/app/app.jsx'
},
devtool: 'inline-source-map',
devServer: {
port: 3000,
host: 'localhost',
historyApiFallback: true,
noInfo: false,
stats: 'minimal',
hot: true, // Tell the dev-server we're using HMR
contentBase: path.resolve(__dirname, './dist'),
publicPath: '/'
},
plugins: [
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(), // Enable HMR
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
inject: 'body'
})
],
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
},
{
entry: {
index: './src/server/server.jsx'
},
target: 'node',
output: {
filename: 'bundle.node.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
}
]
}
}
]
server.jsx:
import mongoose from 'mongoose'
import '../config/database.js'
mongoose.Promise = global.Promise
mongoose.connect(config.database)
// check connection
mongoose.connection.once('open', () => console.log('Connected to MongoDB'))
// check for db errors
mongoose.connection.on('error', err => console.log(err))
Warnings:
WARNING in ./node_modules/mongoose/lib/drivers/index.js
10:13-49 Critical dependency: the request of a dependency is an expression
WARNING in ./node_modules/require_optional/index.js
82:18-42 Critical dependency: the request of a dependency is an expression
WARNING in ./node_modules/require_optional/index.js
90:20-44 Critical dependency: the request of a dependency is an expression
WARNING in ./node_modules/require_optional/index.js
97:35-67 Critical dependency: the request of a dependency is an expression
WARNING in ./node_modules/es6-promise/dist/es6-promise.js
Module not found: Error: Can't resolve 'vertx' in 'D:\Projects\JavaScriptProjects\pizzaday\node_modules\es6-promise\dist'
# ./node_modules/es6-promise/dist/es6-promise.js 131:20-30
# ./node_modules/mongodb/lib/mongo_client.js
# ./node_modules/mongodb/index.js
# ./node_modules/mongoose/lib/index.js
# ./node_modules/mongoose/index.js
# ./src/server/server.jsx

Solution. I used webpack-dev-middleware and webpack-hot-middleware with basic Express server. I tried launch MongoDB with React on webpack-dev-server and thats was main problem.
I made new server.js within separate folder following advice from Neil Lunn and setup basic Express server with middleware and split Webpack config into 3 separate files common, dev and prod.
This fragment of code in server.js helped me to run server and client together with Webpack which bonded everything together:
app.use(webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath
}))
app.use(webpackHotMiddleware(compiler))
New Webpack config (webpack.common.js):
const webpack = require('webpack')
const path = require('path')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: {
app: [
'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=2000&reload=true',
'./src/index.jsx'
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
template: './index.html',
filename: 'index.html',
inject: 'body'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
}

Related

importing react-virtuoso throws error "You may need an appropriate loader to handle this file type."

My project works fine but after installing and importing react-virtuoso it throws error.
ERROR in ./~/react-virtuoso/dist/index.mjs
Module parse failed: C:\Users\Rocky\Documents\betterdash\node_modules\react-virtuoso\dist\index.mjs Unexpected token (364:22)
You may need an appropriate loader to handle this file type.
| }
| const Component = forwardRef((propsWithChildren, ref) => {
| const { children, ...props } = propsWithChildren;
| const [system2] = useState(() => {
| return tap(init(systemSpec), (system22) => applyPropsToSystem(system22, props));
# ./src/components/order-viewer.jsx 13:21-46
# ./src/main.js
# multi whatwg-fetch ./src/main.js
Here is my webpack.config.js
const path = require("path");
const webpack = require("webpack");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: ["whatwg-fetch", "./src/main.js"],
output: {
path: path.join(__dirname, "dist"),
filename: "bundle.js",
publicPath: "/",
},
module: {
loaders: [
{
test: /.jsx?$/,
loader: "babel-loader",
include: path.join(__dirname, "src"),
exclude: /node_modules/,
query: {
presets: ["es2015", "react", "flow"],
plugins: ["transform-flow-strip-types"],
},
},
{
test: /\.s?css$/,
loaders: ExtractTextPlugin.extract({
use: ["css-loader", "sass-loader"],
fallback: "style-loader",
}),
},
],
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new ExtractTextPlugin({
filename: "style.css",
allChunks: true,
disable: process.env.NODE_ENV === "development",
}),
],
devtool: "source-map",
};
I tried deleting node_modules then run npm install but it doesn't solve the problem. If I remove the part of code that imports the react-virtuoso the error also gone.
import { Virtuoso } from "react-virtuoso";
I had the same problem with Jest and I noticed they have renamed the index.js file to index.cjs from version 4.0.0 to version 4.0. I would assume you have to do something similar with Webpack.
transform: {
'^.+\\.(cjs|js|jsx)$': [
'babel-jest',
{ configFile: './babel.config.js' }
]
},
If you install V4.0.0 it will work if that is the same issue.

Problem with building react ssr server with express and webpack

I'm struggling with webpack setup for my ssr react server. I've read several posts here on stackoverflow, other articles and nothing works. Issue is connected with webpack-node-externals package. I've tried several configurations:
without nodeExternals: my app throws an error "process.hrtime" is not a function
with nodeExternals: my bundle is missing dependencies listed in mypackage.json (compression, etc.). This is because it leaves require('moduleName') everyywhere, obvious
with nodeExternals and with options.modulesFromFile argument set to
modulesFromFile: {
fileName: path.resolve(__dirname),
includeInBundle: ['dependencies']
}
I ended up here with error from user-agent module (not listed in my deps) "Cannot find module request". When I installed request manually, there where other errors I don't remember now.
Finally I don't know what I'm doing wrong. Here sample of my webpack config file:
const path = require('path');
const {
CleanWebpackPlugin
} = require('clean-webpack-plugin');
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
const nodeExternals = require('webpack-node-externals');
const {
BundleAnalyzerPlugin
} = require('webpack-bundle-analyzer');
const IS_PRODUCTION = process.env.MODE === 'production';
const config = {
entry: path.resolve(__dirname, 'src/server/index.ts'),
mode: IS_PRODUCTION ? 'production' : 'development',
output: {
path: path.resolve(__dirname, 'dist/server'),
publicPath: IS_PRODUCTION ? 'dist/' : undefined,
filename: 'index.js',
},
externals: [nodeExternals()],
resolve: {
extensions: ['.js', '.ts', '.tsx', '.json'],
fallback: {
fs: false,
yamlparser: false,
tls: false,
net: false,
},
},
target: 'node',
module: {
rules: [{
test: /\.((t|j)s(x?))$/u,
exclude: /node_modules/,
use: {
loader: 'swc-loader',
},
},
{
test: /\.(ts|tsx)$/u,
exclude: /node_modules/,
loader: 'ts-loader',
options: {
configFile: path.resolve(__dirname, 'tsconfig.webpack.json'),
},
},
{
test: /\.(png|jpg|jpeg|ico)$/u,
exclude: /node_modules/,
loader: 'file-loader',
},
],
},
plugins: [new NodePolyfillPlugin(), new CleanWebpackPlugin()],
};
if (IS_PRODUCTION) {
config.optimization = {
minimize: true,
};
}
if (process.env.BUNDLE_ANALYZER === 'true') {
config.plugins.push(
new BundleAnalyzerPlugin({
analyzerMode: 'static',
reportFilename: 'bundle-report-server.html',
})
);
}
module.exports = config;
I've already managed to fix it on myself.
The problem was in node polyfill plugin which was not necessary in my webpack config and it was causing errors like process.hrtime is not a function

Can't find index.html when bundling Node.js server with Webpack

I'm trying to setup webpack to bundle my backend code.
My webpack config looks like:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const nodeExternals = require('webpack-node-externals');
const outputDirectory = 'dist';
const client = {
mode: 'production',
entry: {
'app': [
'babel-polyfill',
'./client/index.js'
]
},
output: {
path: path.join(__dirname, outputDirectory),
publicPath: '/',
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'babel-loader'
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(gif|svg|jpg|png)$/,
loader: "file-loader"
}
]
},
plugins: [
new CleanWebpackPlugin([outputDirectory]),
new HtmlWebpackPlugin({
template: './index.html',
})
]
}
const server = {
mode: 'production',
target: 'node',
entry: {
'app': [
'./server/server.js'
]
},
externals: [nodeExternals()],
output: {
path: path.join(__dirname, '/server'),
filename: 'server.bundle.js'
}
}
module.exports = [client, server]
If I run the non-webpack server.js, everything works fine. However if I run the webpack bundled server.bundle.js, express throws:
Error: ENOENT: no such file or directory, stat '/dist/index.html'
Both server files are in the same directory. Has anyone run into this issue before?
I figured it out, it's not explicitly stated in webpack's documentation but you need to configure a "node" property when using express
Ex. add this to your config
node: {
// Need this when working with express, otherwise the build fails
__dirname: false, // if you don't put this is, __dirname
__filename: false, // and __filename return blank or /
},

How to use webpack to create a front end and a admin?

I am actually new on node.js. I am trying to create an app with admin and frontend using webpack and express. I have created an example app but now the problem is how I can create the app with the admin. Below I have shared my webpack config file
var webpack = require('webpack');
var path = require('path');
module.exports = {
entry: {
frontend: './src/index',
backend: './admin/index'
},
module: {
loaders: [
{
test: /\.js?$/, loader: 'babel', exclude: /node_modules/
},
{
test: /\.css$/,
loaders: [
'style?sourceMap',
'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]'
]
}
]
},
resolve: {
extensions: ['', '.js']
},
output: {
path: path.join(__dirname, '/public'),
publicPath: '/',
filename: 'bundle.js'
},
devServer: {
contentBase: './public',
hot: true
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
]
};
Webpack production configuration file
var config = require('./webpack.config.js');
var webpack = require('webpack');
config.plugins.push(
new webpack.DefinePlugin({
"process.env": {
"NODE_ENV": JSON.stringify("production")
}
})
);
config.plugins.push(
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
);
Is there any easy solution or what I can do now?

How to configure webpack for nodejs with server side rendering

I'm trying to setup Webpack to generate 2 bundles, one for server code with server side rendering and one for client code. So far the bundle seems to generate correctly but when I run the server code and it tries to render some of my React components it throws errors like this one:
ERROR in ./~/react-load-script/lib/index.js
Module build failed: ReferenceError: Unknown plugin "add-module-exports" specified in "/Users/alex/Development/muub/one/website/node_modules/react-load-script/.babelrc" at 0, attempted to resolve relative to "/Users/alex/Development/muub/one/website/node_modules/react-load-script"
at /Users/alex/Development/muub/one/website/node_modules/babel-core/lib/transformation/file/options/option-manager.js:180:17
at Array.map (native)
at Function.normalisePlugins (/Users/alex/Development/muub/one/website/node_modules/babel-core/lib/transformation/file/options/option-manager.js:158:20)
at OptionManager.mergeOptions (/Users/alex/Development/muub/one/website/node_modules/babel-core/lib/transformation/file/options/option-manager.js:234:36)
at OptionManager.init (/Users/alex/Development/muub/one/website/node_modules/babel-core/lib/transformation/file/options/option-manager.js:368:12)
at File.initOptions (/Users/alex/Development/muub/one/website/node_modules/babel-core/lib/transformation/file/index.js:212:65)
at new File (/Users/alex/Development/muub/one/website/node_modules/babel-core/lib/transformation/file/index.js:135:24)
at Pipeline.transform (/Users/alex/Development/muub/one/website/node_modules/babel-core/lib/transformation/pipeline.js:46:16)
at transpile (/Users/alex/Development/muub/one/website/node_modules/babel-loader/lib/index.js:46:20)
at Object.module.exports (/Users/alex/Development/muub/one/website/node_modules/babel-loader/lib/index.js:163:20)
# ./App/Containers/Publish/Payment/Payment.jsx 18:0-39
# ./App/Containers/Publish/Payment/index.js
# ./App/Containers/Publish/Publish.jsx
# ./App/Containers/Publish/index.js
# ./App/Routes/index.js
# ./App/Containers/App.jsx
# ./App/index.js
# multi webpack-hot-middleware/client react-hot-loader/patch ./App
There are more errors similar to this one but related with other 3rd party npm packages.
Here is my webpack server config:
const path = require('path');
const webpack = require('webpack');
const ExternalsPlugin = require('webpack2-externals-plugin');
let conf = {
devtool: 'source-map',
context: path.resolve(__dirname),
entry: [
path.resolve(__dirname, 'index.js')
],
target: 'node',
output: {
path: path.join(__dirname, 'build'),
pathinfo: true,
filename: 'server.js',
publicPath: '/public/',
libraryTarget: 'commonjs2'
},
resolve: {
modules: ['App', 'node_modules'],
extensions: ['.js', '.jsx']
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: 'css-loader/locals',
options: {
modules: true,
sourceMap: true,
importLoaders: 1,
localIdentName: '[name]__[local]__[hash:base64:5]'
}
},
'postcss-loader'
]
},
{
test: /\.(js|jsx)?$/,
loader: 'babel-loader',
exclude: /node_modules/
}
]
},
plugins: [
new webpack.NoEmitOnErrorsPlugin(),
new webpack.HotModuleReplacementPlugin(),
new ExternalsPlugin({
type: 'commonjs2',
include: path.join(__dirname, 'node_modules'),
exclude: [path.join(__dirname, 'node_modules', 'webpack/buildin'), path.join(__dirname, 'App')]
}),
new webpack.optimize.LimitChunkCountPlugin({maxChunks: 1}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development')
})
]
}
module.exports = conf;
What could I be doing wrong?

Resources