babel, webpack with nodemon script? - javascript

I was wondering if there is a way to configure webpack with babel and nodemon. I I pretty much searched the web but found nothing helpful or it may be me because i am pretty much new to build tools.
I have this script in my package.json:
"start": "nodemon app.js --exec babel-node"
It transpile my code and also restart the server when there is changes. I was wondering if there is such configuration for webpack with the watch functionality. Can i do it with webpack (run the server and watch for changes and restart along with the babel transpile) ?

You don't have to use nodemon, you can use webpack's watch feature.
Here's an example script, let's call it backend-dev.js:
const path = require('path');
const webpack = require('webpack');
const spawn = require('child_process').spawn;
const compiler = webpack({
// add your webpack configuration here
});
const watchConfig = {
// compiler watch configuration
// see https://webpack.js.org/configuration/watch/
aggregateTimeout: 300,
poll: 1000
};
let serverControl;
compiler.watch(watchConfig, (err, stats) => {
if (err) {
console.error(err.stack || err);
if (err.details) {
console.error(err.details);
}
return;
}
const info = stats.toJson();
if (stats.hasErrors()) {
info.errors.forEach(message => console.log(message));
return;
}
if (stats.hasWarnings()) {
info.warnings.forEach(message => console.log(message));
}
if (serverControl) {
serverControl.kill();
}
// change app.js to the relative path to the bundle created by webpack, if necessary
serverControl = spawn('node', [path.resolve(__dirname, 'app.js')]);
serverControl.stdout.on('data', data => console.log(data.toString()));
serverControl.stderr.on('data', data => console.error(data.toString()));
});
You can start this script on the command line with
node backend-dev.js
When you make changes in your server code, webpack will recompile and restart your server.

As for the babel part, I believe babel loader have you covered. I use this in my webpack.config.js (webpack 2):
module: {
...
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {presets: ['es2015']}
}
]
}
But I don't use nodemon, so sorry for just half an answer. I do use webpack-dev-server in development. and pm2 in staging/production and I'm using it's watch while staging so I don't have to restart things manually, and it's much easier to configure than webpacks dito:
// pm2's ecosystem.json (just to be thorough):
"watch" : "./",
"ignore_watch" : "node_modules",
No watch in production though, no no, not me, no touchy - The less things that can go wrong the better.

Related

Next.js Scripts Error: Cannot find module '../../webpack-runtime.js'

I want to create RSS script using Next.js.
So I put up a script in a subfolder inside the root folder scripts/ & named it build-rss.js
next.config.js
module.exports = {
webpack: (config, options) => {
config.module.rules.push({
test: /\.svg$/,
issuer: { and: [/\.(js|ts|md)x?$/] },
use: [
{
loader: '#svgr/webpack',
options: {
prettier: false,
svgo: true,
svgoConfig: { plugins: [{ removeViewBox: false }] },
titleProp: true,
},
},
],
})
if (!options.dev && options.isServer) {
const originalEntry = config.entry
config.entry = async () => {
const entries = { ...(await originalEntry()) }
entries['./scripts/build-rss'] = './scripts/build-rss.js'
return entries
}
}
if (!options.isServer) {
config.resolve.fallback.fs = false
}
return config
},
}
When I try to run my script npm run build:development which in package.json represents:
"scripts": {
"clean": "rimraf .next",
"dev": "next dev",
"export": "next export",
"start": "next start",
"lint": "next lint",
"build:development": "next build && npm run export && npm run rss:development",
"build": "next build && npm run export && npm run rss",
"rss:development": "node ./.next/server/scripts/build-rss.js",
"rss": "node ./.next/serverless/scripts/build-rss.js"
}
It throws an error saying:
Error: Cannot find module '../../webpack-runtime.js'
But I checked. The file does exist.
The blunder is this used to work earlier. Probably few versions ago when my other project used the same combination.
I have made a complete reproduction showcasing the error → https://github.com/deadcoder0904/next-script-rss-error
Just clone it, install it & try the script npm run build:development in the terminal to see the error.
Based on our conversation:
entry: path.join(__dirname, '..', 'path/to/file')
That's what a webpack entry looks like. It can also be an array or an object:
entry: [
path.join(__dirname, '..', 'path/to/file'),
// other entries here
]
Whereas you're already getting the whole webpack config:
webpack: (config, options)
So doing:
const originalEntry = config.entry
config.entry = async () => {
const entries = { ...(await originalEntry()) }
entries['./scripts/build-rss'] = './scripts/build-rss.js'
return entries
}
Makes no sense to me if you can just do:
config.entry.push('./scripts/build-rss')
// config.entry['./scripts/build-rss'] = './scripts/build-rss.js'
Unless I miss something with how nextjs is loading the webpack config.
Even then I'd suggest that you use path.join in order to ensure it's loaded to the correct location, because that relative root will execute from wherever webpack is compiled from.
Along with that in your first project you used nextjs v10 and now you're using nextjs v11, which has an upgrade from webpack 4 to 5, which is a major upgrade. I don't know the details, I can only speculate, but under no conditions should you assume that "because your previous project was working this one should using the same stuff", it won't necessarily (especially not in this case).
The first intuitive thing I thought was that webpack should by default bundle everything to a single output file, unless the configuration for that was changed by nextjs (I don't know). So using a script you added to entries didn't make sense to me, because it wouldn't exist. But you're saying that it does exist so I can only assume that webpack is configured to do code splitting and outputs each entry to a different file. In which case I have no idea. As far as I'm aware in webpack 5 (I don't know about webpack 4) code splitting is disabled in dev and enabled in production so your problem is likely a discrepancy between dev and production.
Perhaps the last thing you can try is to change your !options.dev, because right now you're only adding that script when it's production but you're trying to run the script using development.
If you really just have to get it working you can downgrade your nextjs to the previous version you were using (v10), even though that's not really a solution.
Other than that I'm out of ideas.
Not sure if you are still looking for an answer, but simply changing the webpack entry as follows seems to have fixed the problem.
entries['scripts/build-rss'] = './scripts/build-rss.js';
// instead of entries['./scripts/build-rss']
I had the same Error! I deleted the .next Folder and did an npm run dev, It started to work for me!

Access fs module in typescript and webpack [duplicate]

I'm using node.js and webpack to create a bundle. From what I've read, node.js should contain fs module for managing files. However when I call require("fs") I get an Cannot find module "fs" error. What should I do?
I came across this problem myself when bundling with webpack and found the answer on this thread.
The way to solve it for me was to use the following config:
module.exports = {
entry: "./app",
output: {
path: __dirname,
filename: "bundle.js"
},
module: {
loaders: [
{
test: /\.js$/,
exclude: 'node_modules',
loader: 'babel',
query: {presets: ['es2015']},
}
]
},
target: 'node'
};
By setting target to node webpack will make the necessary changes to bundle your node application
Edit: This answer targeted webpack 1.x which has now been superseded.
If you are running your webpack bundle in nodejs environment then target: 'node' is required in webpack.config.js file otherwise webpack takes default value as web for target check here.
You can resolve the issue in two ways
Add below configuration to your webpack.config.js
node: {
fs: "empty"
}
OR
Add below configuration to your package.json
"browser": {
"fs": false
}
Edit:
promising fix is
"browser": {
"fs": false
}
I had the same issue when bundling a NWjs application using webworkers (which in turn had node enabled).
The solution I found was to include each native module I used in externals with the prefix commonjs to the name of the module. For example:
...
target: "webworker", // or 'node' or 'node-webkit'
externals:{
fs: "commonjs fs",
path: "commonjs path"
}
...
I've done the same for targets "webworker" and "node-webkit" in different projects to solve the same issue.
webpack nwjs webworker nodejs node
Add below configuration to your webpack.config.js
resolve: {
fallback: {
fs: false
}
}
I needed to build a class that would use fetch if executed in a browser, or fs if executed in node. For other reasons, it was impractical to produce separate bundles, so I produced a single browser-targeted bundle.
The solution I used was to use eval('require("fs")') if the script was running in node.
const fs = eval('require("fs")')
Browser-safe (fs is null in the browser):
const fs = typeof window === 'object'
? null
: eval('require("fs")')
After trying everything I found on the internet (target, externals, node configs), the only solution that actually worked for me was replacing:
const filesystem = require("fs")
or
import fs from "fs"
by the special webpack version
const fs = __non_webpack_require__("fs")
This generates a require function that is not parsed by webpack.
In addition to the answer of PDG
I'm used to this short copy/paste candy.
Using path and fs :
var nodeModules = {};
fs.readdirSync(path.resolve(__dirname, 'node_modules'))
.filter(x => ['.bin'].indexOf(x) === -1)
.forEach(mod => { nodeModules[mod] = `commonjs ${mod}`; });
// Before your webpack configuration
module.exports = {
...
}
Then inside your configuration file, include the nodeModules variable in the externals
...
externals: nodeModules,
...
It would be more elegant to use pre-defined solution as:
Adding target: 'node' to webpack config file.
More info on: official documentation
For the solution we are building we had to force an older version of webpack:
npm install --save --force webpack#webpack-3

Why is Terser minimizer not dropping spaces & newlines when running in watch mode?

Situation
I have a working webpack configuration that includes the EslintWebpackPlugin (fix: false) as part of the preprocessing plugins and when there were no lint errors, webpack correctly output the expected minimized build.
But, when I had numerous lint errors and my workflow required a rerun of the build each time I desired to re-evaluate the build. I tried to increase my workflow speed by using the --watch option on webpack to give me instant feedback on each manual lint fix. This partially worked but my integration with prettier through eslint-plugin-prettier would not be considered during the next iteration of the webpack --watch. To fix this, I modified the ESLintPlugin config in webpack.config.js to set the fix: true based on the WEBPACK_WATCH environment variable. I don't desire the regular build command to also apply lint fixes automatically since it doesn't lead to the code being fixed.
Problem
On the surface this solution works as I get instant feedback on each lint fix as it is modified and webpack stays in sync with prettier/prettier errors as they resolve. BUT upon review of the output bundle, now the bundle has a bunch of spaces and newlines in it instead of minimizing them as it should have.
Problems identified:
ESLintPlugin while in watch mode seems to cache errors even after a save, Requires fix: true for watch mode updates.
Webpack Watch mode causes errors in the TerserPlugin which prevent a proper minimized bundle.
Additional Troubleshooting Findings:
I found that simply running webpack in watch mode and removing eslintplugin configuration, the output bundle does not minify properly. If the same configuration is run without --watch, the bundle is perfect. (Problem 2 isolation)
Files
// webpack.config.js
const isProduction = process.env.NODE_ENV === "production";
const path = require("path");
const SheBangPlugin = require("webpack-shebang-plugin");
const ESLintPlugin = require("eslint-webpack-plugin");
const thisModule = require("./package.json");
function buildConfig(env) {
return {
entry: "./parse.js",
target: "node",
output: {
path: path.resolve(__dirname, "dist"),
filename: path.basename(thisModule.main)
},
plugins: [
new SheBangPlugin({
chmod: 0o755
}),
new ESLintPlugin({
fix: env.WEBPACK_WATCH
})
],
optimization: {
minimize: true,
usedExports: true
},
resolve: {
extensions: [".js", ".json"]
}
};
}
module.exports = (env) => {
const config = buildConfig(env);
if (isProduction) {
config.mode = "production";
} else {
config.mode = "development";
}
return config;
};
Snapshot of bundle.js in a vscode with word-wrap on.
Is there a problem with my configuration or are these bugs? What is it that changes when webpack goes into watch mode which causes a conflict with the TerserPlugin?

bundle an npm package AND convert it into an es module

I want to import chessground into a project of mine. It seems it's a CommonJS module, so i used browserify to import it into my web page.
browserify -r chessground > chessground.js
In order to use it in my webpage, I use
const Chessground = require('chessground').Chessground
but I saw in this project that they import it like
import {Chessground} from 'chessground'
I know they are douing with webpack, but for the life of me I can't figure out how to bundle an entire npm package into one file AND convert it into an ES module. Can anyone help me?
There is noway to bundle your packages without using a bundler like webpack or rollup.js.
If it is necessarily to use task runner you may find a way to make the bundler work with your task runner.
I had the same problem with gulpjs and wepack, and it was really painful to make it work. The solution was using a webpack and webpack plugins in gulpjs.
const webpack = require('webpack');
const webpackStream = require('webpack-stream');
const path = require('path');
const webapckJsConfig = {
mode: (process.env.APP_ENV === 'dev' && process.env.APP_DEBUG === 'true') ? 'development' : 'production',
devtool: (process.env.APP_ENV === 'dev' && process.env.APP_DEBUG === 'true') ? 'source-map' : false,
entry: {
// Website JS Files
'website/home.js': './resources/js/website/home.js',
'website/notfound.js': './resources/js/website/notfound.js',
'website/error.js': './resources/js/website/error.js',
// Admin JS Files
'admin/home.js': './resources/js/admin/home.js',
'admin/notfound.js': './resources/js/admin/notfound.js',
},
output: {
path: path.resolve(__dirname, 'public/'),
filename: '[name]',
},
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
},
},
],
},
};
// JavaScript lint Cehck ✅ Convert 🔂 Compresse 🔄 Output ↪ 📁 public/js
async function scripts() {
return gulp
.src(`${JAVASCRIPT_DIR}/**/*.js`)
.pipe(webpackStream(webapckJsConfig), webpack)
.pipe(gulp.dest(`${JS_PUBLIC_DIR}`));
}
exports.scripts = scripts;
you can also check it here
You can of course take the webpack configuration and put them in external file, but you have to consider that you will confuse other developers because they will think webpack is independent and start to use it as an independent tool, so that's why I keep it in gulp.js.

Pass an argument to Webpack from Node.js

I'm trying to build both minified and unminified versions of my app (js and css) using Webpack.
This can be easily done via command-line interface using -p or --optimize-minimize switch:
webpack
webpack -p
However, I would like to perform these actions with just one command, so I decided to write a small Node.js script which would run both of these Webpack builds:
var webpack = require('webpack');
var config = require('./webpack.config');
webpack(config, callback); // Build unminified version
So the question is: can I pass the aforementioned -p argument to Webpack from the Node.js script in order to build the minified version? Or maybe there is a simpler way of solving my particular problem?
Of course, I can use child_process.exec(), but I don't think it's an authentic Node.js way.
Create your default config to webpack an unminified version. Run webpack with that config. Change the configuration from code and run webpack again. Here is a code example.
var webpack = require('webpack');
//assuming the config looks like this.
var config = {
entry: "./entry.js",
output: {
devtoolLineToLine: true,
sourceMapFilename: "./bundle.js.map",
pathinfo: true,
path: __dirname,
filename: "bundle.js"
},
module: {
loaders: [
{ test: /\.css$/, loader: "style!css" }
]
},
plugins: []
};
webpack(config).run(); // Build unminified version
config.output.filename = 'bundle.min.js'
config.plugins = [
new webpack.optimize.UglifyJsPlugin({
include: /\.min\.js$/,
minimize: true
})];
webpack(config).run(); // Build minified version
Key p is an alias to setting node environment variable process.env.NODE_ENV="production" as described here

Categories

Resources