Best way to manage express server dependencies in production env - javascript

I’ve developed an application with a react front end and a node server on the backend. The React dependencies are bundled by webpack into bundle.min.js, but when I put my server.js on a container/VM wherever, how do I ensure its dependences (i.e. express, winston, body-parser, etc) are installed.
npm install --production
will install my production dependences on the server but this will include everything from react, react-dom, d3, etc.
I have tried using a separate webpack configuration to make a server bundle, along the lines of,
{
name: 'server',
target: 'node',
entry: path.resolve(__dirname, 'src', 'server', 'app.js'),
devtool: 'cheap-module-source-map',
output: {
path: path.resolve(__dirname, 'dist', 'server'),
filename: 'server.bundle.js'
}
},
node: {
__dirname: false
}
but when I start the server I am getting a Cannot Get / error.
What is the best method to install only the dependencies related to my express server for a production build?

Unless you are potentially going to run out of file space, I don't think its a problem to have all of your dependencies installed. It certainly makes maintainability simpler vs creating two separate projects. What advantage do you get from trying to only install production packages on your server? Or better yet, what disadvantage is there to having all of them?

Related

Is webpack a suitable tool to bundle a Node.js backend code? [duplicate]

I was just wondering, I started using Webpack for a new project and so far it's working fine. I almost would say I like it better than Grunt, which I used before. But now I'm quite confused how and or I should use it with my Express back-end?
See, I'm creating one app with a front-end (ReactJS) and a back-end (ExpressJS). The app will be published on Heroku. Now it seems like I should use Webpack with ExpressJS as well to get the app up and running with one single command (front-end and back-end).
But the guy who wrote this blogpost http://jlongster.com/Backend-Apps-with-Webpack--Part-I seems to use Webpack for bundling all back-end js files together, which is in my opinion really not necessary. Why should I bundle my back-end files? I think I just want to run the back-end, watch my back-end files for changes and use the rest of Webpack's power just for the front-end.
How do you guys bundle the front-end but at the same time run the back-end nodejs part? Or is there any good reason to bundle back-end files with Webpack?
Why to use webpack on node backend
If we are talking about react and node app you can build isomorphic react app. And if you are using import ES6 Modules in react app on client side it's ok - they are bundled by webpack on the client side.
But the problem is on server when you are using the same react modules since node doesn't support ES6 Modules. You can use require('babel/register'); in node server side but it transipile code in runtime - it's not effective. The most common way to solve this problem is pack backend by webpack (you don't need all code to be transpile by webpack - only problematic, like react stuff in this example).
The same goes with JSX.
Bundling frontend and backend at the same time
Your webpack config can have to configs in array: one for frontend and second for backend:
webpack.config.js
const common = {
module: {
loaders: [ /* common loaders */ ]
},
plugins: [ /* common plugins */ ],
resolve: {
extensions: ['', '.js', '.jsx'] // common extensions
}
// other plugins, postcss config etc. common for frontend and backend
};
const frontend = {
entry: [
'frontend.js'
],
output: {
filename: 'frontend-output.js'
}
// other loaders, plugins etc. specific for frontend
};
const backend = {
entry: [
'backend.js'
],
output: {
filename: 'backend-output.js'
},
target: 'node',
externals: // specify for example node_modules to be not bundled
// other loaders, plugins etc. specific for backend
};
module.exports = [
Object.assign({} , common, frontend),
Object.assign({} , common, backend)
];
If you start this config with webpack --watch it will in parallel build your two files. When you edit frontend specific code only frontend-output.js will be generated, the same is for backend-output.js. The best part is when you edit isomorphic react part - webpack will build both files at once.
You can find in this tutorial explanation when to use webpack for node (in chapter 4).
This is my second update to this answer, which is beyond outdated by now.
If you need full a stack web framework in 2023, I'd recommend nextjs (which is built on top of react). No need to go around setting up anything, it just works out of the box, and is full stack.
On the other hand, if you need to compile your nodejs project written in typescript (which you should use as much as you can for js projects), I would use tsup-node.
You don't need to be a genius to imagine that in 3-5 years I'll come back to this and say this is really outdated, welcome to javascript.
This answer is outdated by now since node now has better support for ES modules
There's only a couple of aspects I can redeem the need to use webpack for backend code.
ES modules (import)
import has only experimental support in node (at least since node 8 up to 15). But you don't need to use webpack for them work in node.
Just use esm which is very lightweight and has no build step.
Linting
Just use eslint, no need to use webpack.
Hot reloading/restart
You can use nodemon for this. It's not hot reloading but I think it's way easier to deal with.
I wished I could refer to a more lightweight project than nodemon, but it does do the trick.
The blog post you shared (which is dated by now) uses webpack for having hot reloading. I think that's an overkill, opens a can of worms because now you have to deal with webpack config issues and hot reloading can also lead to unexpected behaviour.
The benefits we get from using tools like webpack on the frontend don't really translate to backend.
The other reasons why we bundle files in frontend is so browsers can download them in an optimal way, in optimal chunks, with cache busting, minified. There's no need for any of these in the backend.
Old (and terrible, but maybe useful) answer
You can use webpack-node-externals, from the readme:
npm install webpack-node-externals --save-dev
In your webpack.config.js:
var nodeExternals = require('webpack-node-externals');
module.exports = {
...
target: 'node', // in order to ignore built-in modules like path, fs, etc.
externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
...
};
to use Webpack for bundling all back-end js files together, which is in my opinion really not necessary.
I think you are absolutely right. It's not necessary at all. I've been researching on this topic for a while. I've asked lots of questions on this topic, and up to this day, I haven't found yet a single "real" reason for one to use webpack on a Node.js back-end.
I'm not saying you can't or shouldn't set up a webpack-dev-server to develop your back-end code locally. But you definitely don't need to bundle your backend code on your build process.
webpack bundles are meant for the browser. Take a look at its official docs: Why webpack?. Historically, browsers never had a built-in module system, that's the reason why you need webpack. It basically implements a module system on the browser. On the other hand, Node.js has a built-it module system out of the box.
And I do re-use all of my front-end code for SSR on my server. The very same front-end files are run on my server as-is without any bundling (they are just transpiled, but the folder structured and number of files is the same). Of course I bundle it to run on the browser, but that's all.
To run on your Node.js server, simply transpile it with babel, without webpack.
Just use ["#babel/preset-env", { targets: { node: "12" }}], on your babel config. Choose the Node version of your backend environment.
backend
dist_app // BABEL TRANSPILED CODE FROM frontend/src
dist_service // BABEL TRANSPILED CODE FROM backend/src
src
index.tsx
frontend
src
App.tsx
public // WEBPACK BUNDLED CODE FROM frontend/src
You can perfectly render your frontend code on the server, by doing:
backend/src/index.tsx
import { renderToString } from "react-dom/server";
import App from "../dist_app/App";
const html = renderToString(<App/>);
This would be considered isomorphic, I guess.
If you use path aliases on your code, you should use babel-plugin-module-resolver.

How do I execute/bundle JS with Webpack from another task runner?

I've been using webpack for my latest projects, but I have legacy projects using grunt or gulp or other.
In those cases, I'd still love a bundler like webpack with ultra minimal configs to use ES6 imports and such.
How do I execute a single webpack bundle command from within say gulp or longrunning node script?
I can spawn a subprocess and call webpack but I'm curious how I'd use it in legacy toolchains via JS.
webpack({...}) // does nothing
I found the use of webpack().apply() on some other stack overflow post and webpack does compile once, but not a second time when called within a gulp task.
(function exampleCreateBundle() => {
const compiler = webpack({
entry: './_js/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'js')
}
});
compiler.apply(new ProgressPlugin(function(percentage, msg) {
console.log((percentage * 100) + '%', msg);
}));
// works once
})();
Thanks for any help!
Update:
Honestly, I'm just spawning a child process and running npx webpack.
At this point the question is academic.

Handling cache beyong Nginx server and webpack js and css versioning

I have a React nodejs app running on EC2.
I have set up 3 instances of it beyond Nginx for the load balancing.
I have also enabled cache in the Nginx configuration.
Basically everything should be cached beside different versions of app.js which holds the bundled React code and style.css which is also bundled.
I would like to add a version number in the js and css src link (e.g http://mywebsite.com/app.js?1.0)
My question is, can I automate this operation with webpack? Is this the way to go?
html-webpack-plugin is your friend here.
Instead of creating your index.html file, allow webpack to do it for you.
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: "./index.js",
output: {
filename: "./dist/app.bundle.[hash].js"
},
plugins: [
new HtmlWebpackPlugin({
hash: true,
filename: './dist/index.html'
})
]
}
This will add the output script into index.html automatically and will generate a hash for the file.

Bundling non-native npm modules with Webpack

Description
I have a nodejs + TypeScript + express project and currently the source *.ts files are being bundled with webpack and node_modules is ignored with webpack-node-externals.
When I deploy bundle.js in Docker, I would need to still run npm i --production on the target image to install the dependencies, which installs all the modules listed in package.json
The Problem:
If I am using only one function from lodash which does not have native parts, the whole lodash module (4.8MB) is installed nonetheless (which is intended).
This results in a huge node_modules folder where functions inside packages aren't always necessarily used in bundle.js. This problem is especially prevalent when containerizing the application with Docker.
Is there any way to bundle non-native modules with Webpack while leaving native modules alone?
This is very similar to https://stackoverflow.com/a/54393299/2234013 - I believe you're looking for nodeExternals({ whitelist }) and babel-loader exclude:
// excerpt from https://stackoverflow.com/a/54393299/2234013
externals: [
nodeExternals({
whitelist: [/lodash/]
})
],
...
module: {
rules: [
{
...
exclude: /node_modules\/(?!(lodash).*/,
use: {
loader: 'babel-loader',
...
}
}
]
}

Transpiled webpack bundle does not export hyphenated package name via require

I am importing fluent-ffmpeg with: import ffmpeg from 'fluent-ffmpeg' in one file.
After running webpack, I receive this error:
Uncaught Exception: ReferenceError: fluent is not defined
I looked inside the transpiled file and I found fluent-ffmpeg included like so:
function(e,t){e.exports=fluent-ffmpeg}
After changing the line to read: function(e,t){e.exports=require("fluent-ffmpeg")} the programs work.
Is there a way to configure webpack to correctly require fluent-ffmpeg when transpiling?
Edit: I am using this electron react webpack boilerplate to build a desktop application - https://github.com/chentsulin/electron-react-boilerplate
Update:
I've created a repo to show the bug - https://github.com/the4dpatrick/congenial-barnacle. The difference between electron-react-boilerplate and this repo can be seen in a single commit
To see bug:
npm i
packaging the electron app (npm run package)
opening the app which is under the release dir.
Alert opens with error
I was able to solve the issue by simply setting the output.libraryTarget setting within webpack.config.electron.js file to commonjs2.
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
libraryTarget: 'commonjs2'
},
For further details read: chentsulin/electron-react-boilerplate#232

Categories

Resources