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

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!

Related

Parcel Bundler beautify, lint, and create .min.js

I'm new the world of automating/testing/bunding with JS and I've got parcel setup for the most part but I noticed that when it builds files, it does not actually save them with the .min.js part in the file name. I'm wondering if theres a way to do this without having to rename the build file manually.
I'm also trying to find a way to have parcel go through the original source files(the ones that you work on) and lint and beautify them for me
Here's what my package.json looks like
{
"name": "lpac",
"version": "1.3.1",
"description": "",
"dependencies": {},
"devDependencies": {
"parcel": "^2.0.0-rc.0"
},
"scripts": {
"watch": "parcel watch --no-hmr",
"build": "parcel build"
},
"targets": {
"lite-maps": {
"source": ["./path/file1.js", "./path/file2.js", "./path/file3.js"],
"distDir": "./path/build/"
}
},
"browserslist": "> 0.5%, last 2 versions, not dead",
"outputFormat" : "global",
}
I checked out the docs but I couldn't find anything on linting or beautifying with parcel. How can i go about doing that? If you have tutorial links to doing so please also share because resources/tutorials seem scarce for anything other than the basic watching and building files
Unfortunately, there is no out-of-the-box setting that can cause parcel javascript output look like [fileName].[hash].min.js instead of [fileName].[hash].js. The .min.js extension is just a convention to keep output files distinct from source files, though - it has no effect at runtime - and the fact that parcel does automatic content hashing makes it easy enough to tell this. And even though they don't have a .min.js extension, these output files are definitely still minified and optimized by default.
However, if you really, really want this anyways, it's relatively simple to write a Namer plugin for parcel that adds .min.js to all javascript output:
Here's the code:
import { Namer } from "#parcel/plugin";
import path from "path";
export default new Namer({
name({ bundle }) {
if (bundle.type === "js") {
const filePath = bundle.getMainEntry()?.filePath;
if (filePath) {
let baseNameWithoutExtension = path.basename(filePath, path.extname(filePath));
// See: https://parceljs.org/plugin-system/namer/#content-hashing
if (!bundle.needsStableName) {
baseNameWithoutExtension += "." + bundle.hashReference;
}
return `${baseNameWithoutExtension}.min.js`;
}
}
// Returning null means parcel will keep the name of non-js bundles the same.
return null;
},
});
Then, supposing the above code was published in a package called parcel-namer-js-min, you would add it to your parcel pipeline with this .parcelrc:
{
"extends": "#parcel/config-default",
"namers": ["parcel-namer-js-min", "..."]
}
Here is an example repo where this is working.
The answer to your second question (is there "a way to have parcel go through the original source files(the ones that you work on) and lint and beautify them for me") is unfortunately, no.
However, parcel can work well side-by-side with other command line tools that do this do this. For example, I have most of my projects set up with a format command in the package.json, that looks like this:
{
...
"scripts": {
...
"format": "prettier --write src/**/* -u --no-error-on-unmatched-pattern"
}
...
{
You can easily make that command automatically run for git commits and pushes with husky.

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?

What is the best way to add APM to NuxtJS project

What is the right way to configure/enable an Elastic APM agent in a Nuxtjs project?
I referred this documentation for a custom NodeJS app. The key takeaway was:
It’s important that the agent is started before you require any other
modules in your Node.js application - i.e. before http and before your
router etc.
I added the following snippet in nuxt.config.js, but the APM agent is not started or working. I do not see any errors in the app logs.
var apm = require('elastic-apm-node').start({
serviceName: 'nuxt-app',
serverUrl: 'http://ELK_APM_SERVER:8200'
})
Is there any other way to do this?
We managed to get this working using a custom Nuxt module which explicitly requires the Node modules to instrument after it has initiated the APM module.
modules/elastic-apm.js:
const apm = require('elastic-apm-node');
const defu = require('defu');
module.exports = function() {
this.nuxt.hook('ready', async(nuxt) => {
const runtimeConfig = defu(nuxt.options.privateRuntimeConfig, nuxt.options.publicRuntimeConfig);
const config = (runtimeConfig.elastic && runtimeConfig.elastic.apm) || {};
if (!config.serverUrl) {
return;
}
if (!apm.isStarted()) {
await apm.start(config);
// Now explicitly require the modules we want APM to hook into, as otherwise
// they would not be instrumented.
//
// Docs: https://www.elastic.co/guide/en/apm/agent/nodejs/master/custom-stack.html
// Modules: https://github.com/elastic/apm-agent-nodejs/tree/master/lib/instrumentation/modules
require('http');
require('http2');
require('https');
}
});
}
nuxt.config.js:
module.exports = {
// Must be in modules, not buildModules
modules: ['~/modules/elastic-apm'],
publicRuntimeConfig: {
elastic: {
apm: {
serverUrl: process.env.ELASTIC_APM_SERVER_URL,
serviceName: 'my-nuxt-app',
usePathAsTransactionName: true // prevent "GET unknown route" transactions
}
}
}
};
All the answers are outdated and from beginning incorrect (17.02.2022)
To make it work follow these steps:
1.) Create a nodeApm.js in your root dir with the following content:
const nodeApm = require('elastic-apm-node')
if (!nodeApm.isStarted()) {
nodeApm.start()
}
2.) Use environment variables to store your config. For example:
ELASTIC_APM_SERVICE_NAME=NUXT_PRODUCTION
ELASTIC_APM_SECRET_TOKEN=yoursecrettokenhere
3.) Edit your package.json
"scripts": {
// if you want apm also on dev to test, add it also here
"dev": "node -r ./nodeApm.js node_modules/nuxt/bin/nuxt",
...
"start": "node -r ./nodeApm.js node_modules/nuxt/bin/nuxt start",
...
! Be awere that in ~2022 the node_modules bin folder has lost the "." in the directory name
! In all othere anwsers people forget the start parameter at the end
"start": "node -r ./nodeApm.js node_modules/nuxt/bin/nuxt start",
Based on what I've seen it looks like there isn't a "right" way to do this with the stock nuxt command line application. The problem seems to be that while nuxt.config.js is the first time a user has a chance to add some javascript, that the nuxt command line application bootstraps the Node's HTTP frameworks before this config file is required. This means the elastic agent (or any APM agent) doesn't have a chance to hook into the modules.
The current recommendations from the Nuxt team appears to be
Invoke nuxt manually via -r
{
"scripts": {
"start": "node -r elastic-apm-node node_modules/nuxt/.bin/nuxt"
}
}
Skip nuxt and use NuxtJS programmatically as a middleware in your framework of choice
const { loadNuxt } = require('nuxt')
const nuxtPromise = loadNuxt('start')
app.use((req, res) => { nuxtPromise.then(nuxt => nuxt.render(req, res)) })
Based on Alan Storm answer (from Nuxt team) I made it work but with a little modification:
I created a file named nodeApm.js where I added the following code:
const nodeApm = require('elastic-apm-node')
if (!nodeApm.isStarted()) { ... // configuration magic }
In script sections I added:
"start": "node -r ./nodeApm.js node_modules/nuxt/.bin/nuxt"

Fail Gatsby build if environment variable missing

I have experimented with adding environment variables to my Gatsby project using .env.development and .env.production files and it's working great.
I would like to have my builds fail if one of the environment variables is missing, however I can't seem to see how to enable this functionality.
I have read through the Gatsby environment variables documentation, but can't seem to see how this would work? is this possible?
I believe it uses dotenv/webpack define plugin under the hood.
I’m sure there are other ways to do this, but with some quick tests, this approach seems to be working well for me.
In your gatsby-config.js file, you can choose to explicitly require the dotenv, so you can use those environment variables in your config.
I added the following, and now the Gatsby build will fail unless the specified environment variables are present.
// Load the environment variables, per
// https://www.gatsbyjs.org/docs/environment-variables/#server-side-nodejs
require('dotenv').config({
path: `.env.${process.env.NODE_ENV}`,
})
function checkEnv(envName) {
if (typeof process.env[envName] === 'undefined' || process.env[envName] === '') {
throw `Missing required environment variables: ${envName}`
}
}
try {
checkEnv('NODE_ENV')
checkEnv('EXAMPLE_MISSING_ENV')
checkEnv('EXAMPLE_API_KEY')
} catch (e) {
throw new Error(e)
}
// The rest of the config file
I could imagine customizing this further, ex. logging a warning for a variable with a fallback versus throwing an error for one that is required by your content sourcing plugin or theme. Hope this is helpful as a starting point!
I couldn't find built-in solution for this on Gatsby neither. You may do it manually, but still not too easy.
First problem: If you wanna load your environment from file while running npm script; it can not be loaded right away. But you may trigger a script file, and it can load this environment variables before your check.
lets say build.sh on root directory of project :
source ./.env.development # this line will set env variables
if [ "$API_KEY" = 927349872349798 ] ; then
npm run build
fi
Another problem rises; some developers might want to run it on windows maybe. So better use famous cross-env package.
npm i cross-env
Then everything is ready, add your secure-build :
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write \"**/*.{js,jsx,json,md}\"",
"start": "npm run develop",
"serve": "gatsby serve",
"clean": "gatsby clean",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1",
"secure-build": "cross-env-shell \"./build.sh\""
},
And run it :
npm run secure-build
This solution looks too much for me as we created a build.sh and install a new package. Maybe there is cleaner solution. I am not Gatsby Guru after all.
I added env checking to the onPreInit life cycle hook in gatsby-node.ts:
const envVariablesList = [
"ENV1",
"ENV2",
"ENV3",
];
function envVarChecker(vars: string[]): string | undefined {
return vars.find(
(item) => process.env[item] === undefined || process.env[item] === ""
);
}
export const onPreInit: GatsbyNode["onPreInit"] = ({ actions }) => {
const emptyEnv = envVarChecker(envVariablesList);
if (emptyEnv !== undefined) {
throw new Error(`Env variable: ${emptyEnv} is empty!`);
}
};
It fails build almost at the very beginning (during pre-bootstrap phase) if any of the declared variables is missing

babel, webpack with nodemon script?

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.

Categories

Resources