Dynamically import webpack in Node.js - node.js

I´m trying to dynamically import webpack in Node.js
if (condition) {
import('webpack').then(webpack => webpack);
}
However in my terminal I see the following error:
C:\Users\myUser\react\node_modules\#babel\core\lib\transformation\normalize-file.js:209
throw err;
^
SyntaxError: C:\Users\myUser\react\server\index.js: Support for the experimental syntax 'dynamicImport' isn't currently enabled (23:3):
19 |
20 | if (condition) {
> 21 | import('webpack').then(webpack => webpack);
| ^
22 |
Add #babel/plugin-syntax-dynamic-import (https://git.io/vb4Sv) to the 'plugins' section of your Babel config to enable parsing.
I have #babel/plugin-syntax-dynamic-import installed and in my .babelrc
{
"presets": ["#babel/preset-env", "#babel/preset-react"],
"plugins": [
"#babel/plugin-syntax-dynamic-import",
"#babel/plugin-proposal-class-properties"
]
}
I even tried to add it to the webpack conf file under the rule for .js with loader "babel-loader".
I´m trying to avoid CmJS
const webpack = require('webpack');
In any case I receive the same error and I cannot find a solution. Did anyone go through this? Thanks

add plugins: ["dynamic-import-webpack"] to .babelrc
and also install plug $npm i babel-plugin-dynamic-import-webpack --D

Related

rollup plugin "#rollup/plugin-commonjs" parsing package.json and throwing unexpected token error

TL;DR: Why is #rollup/plugin-commonjs looking in my package.json and how can I stop that so that I don't have to include #rollup/plugin-json arbitrarily to fix the problem?
I have a file written in JS for Node.js, CommonJS require() / module.exports() that I want to work in the Browser, so I am using Rollup to bundle and 'browserify' the Node.js code.
Environment
macOS Monterey Version 12.4
npm version 8.3.1
node version 16.14.0
rollup version 2.75.6
#rollup/plugin-json version 4.1.0
rollup.config.js
Here is my rollup.config.js:
// rollup.config.js
import commonjs from '#rollup/plugin-commonjs';
// import json from '#rollup/plugin-json';
const devMode = (process.env.NODE_ENV === 'development');
console.log(`${ devMode ? 'development' : 'production' } mode bundle`);
export default [
{
input: "test/_client_test.js",
output: {
file: 'build/test/test.js',
format: 'iife'
},
plugins: [
commonjs()
]
}
];
Problem
When running npm rollup -c I get the following output:
[!] (plugin commonjs--resolver) Error: Unexpected token (Note that you need #rollup/plugin-json to import JSON files)
package.json (2:8)
1: {
2: "name": "my-package",
^
3: "version": "0.0.1",
4: "description": "hello world",
Error: Unexpected token (Note that you need #rollup/plugin-json to import JSON files)
at error (/***/node_modules/rollup/dist/shared/rollup.js:198:30)
at Module.error (/***/node_modules/rollup/dist/shared/rollup.js:12553:16)
at Module.tryParse (/***/node_modules/rollup/dist/shared/rollup.js:12930:25)
at Module.setSource (/***/node_modules/rollup/dist/shared/rollup.js:12835:24)
at ModuleLoader.addModuleSource (/***********/rollup.js:22309:20)

ERR_REQUIRE_ESM from webpack's importing an ESM package

I am building an app using Nx for modularisation and Geckos for the server part. With Nx' default Webpack 5 config for Node I get this error when running the app:
/Users/hgrzeskowiak/hugo-game/fresh-nx-geckos/nx-geckos-test/dist/apps/geckos-server-app/main.js:8
module.exports = require("#geckos.io/server");
^
Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/hgrzeskowiak/hugo-game/fresh-nx-geckos/nx-geckos-test/node_modules/#geckos.io/server/lib/index.js from /Users/hgrzeskowiak/hugo-game/fresh-nx-geckos/nx-geckos-test/dist/apps/geckos-server-app/main.js not supported.
Instead change the require of index.js in /Users/hgrzeskowiak/hugo-game/fresh-nx-geckos/nx-geckos-test/dist/apps/geckos-server-app/main.js to a dynamic import() which is available in all CommonJS modules.
(...)
Here are steps to reproduce:
$ npx create-nx-workspace#latest nx-geckos-test
Need to install the following packages:
create-nx-workspace#latest
Ok to proceed? (y) y
✔ What to create in the new workspace · express
✔ Application name · geckos-server-app
✔ Use Nx Cloud? (It's free and doesn't require registration.) · No
> NX Nx is creating your v13.4.1 workspace.
To make sure the command works reliably in all environments, and that the preset is applied correctly,
Nx will run "npm install" several times. Please wait.
✔ Installing dependencies with npm
✔ Nx has successfully created the workspace.
$ npm run start
> nx-geckos-test#0.0.0 start
> nx serve
> nx run geckos-server-app:serve
chunk (runtime: main) main.js (main) 552 bytes [entry] [rendered]
webpack compiled successfully (26ac6f288b082854)
Debugger listening on ws://localhost:9229/70a1d9b4-af2b-4fc9-90f7-f3502e5fdf2e
Debugger listening on ws://localhost:9229/70a1d9b4-af2b-4fc9-90f7-f3502e5fdf2e
For help, see: https://nodejs.org/en/docs/inspector
Issues checking in progress...
Listening at http://localhost:3333/api
At this stage, the default Express app builds and runs.
Now I replace the contents of apps/geckos-server-app/src/main.ts to the Geckos server example from the README:
import geckos from '#geckos.io/server'
const io = geckos()
io.listen(3000) // default port is 9208
io.onConnection(channel => {
channel.onDisconnect(() => {
console.log(`${channel.id} got disconnected`)
})
channel.on('chat message', data => {
console.log(`got ${data} from "chat message"`)
// emit the "chat message" data to all channels in the same room
io.room(channel.roomId).emit('chat message', data)
})
})
...and install the geckos server package using
$ npm install #geckos.io/server
added 4 packages, and audited 785 packages in 7s
87 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
Ok, time to run it again:
$ npm run start
> nx-geckos-test#0.0.0 start
> nx serve
> nx run geckos-server-app:serve
chunk (runtime: main) main.js (main) 610 bytes [entry] [rendered]
webpack compiled successfully (90920432a9d246ea)
Debugger listening on ws://localhost:9229/dc6d9e1a-1a15-432f-a46c-d2ac83b923ea
Debugger listening on ws://localhost:9229/dc6d9e1a-1a15-432f-a46c-d2ac83b923ea
For help, see: https://nodejs.org/en/docs/inspector
/Users/hgrzeskowiak/hugo-game/fresh-nx-geckos/nx-geckos-test/dist/apps/geckos-server-app/main.js:8
module.exports = require("#geckos.io/server");
^
Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/hgrzeskowiak/hugo-game/fresh-nx-geckos/nx-geckos-test/node_modules/#geckos.io/server/lib/index.js from /Users/hgrzeskowiak/hugo-game/fresh-nx-geckos/nx-geckos-test/dist/apps/geckos-server-app/main.js not supported.
Instead change the require of index.js in /Users/hgrzeskowiak/hugo-game/fresh-nx-geckos/nx-geckos-test/dist/apps/geckos-server-app/main.js to a dynamic import() which is available in all CommonJS modules.
at Object.#geckos.io/server (/Users/hgrzeskowiak/hugo-game/fresh-nx-geckos/nx-geckos-test/dist/apps/geckos-server-app/main.js:8:18)
at __webpack_require__ (/Users/hgrzeskowiak/hugo-game/fresh-nx-geckos/nx-geckos-test/dist/apps/geckos-server-app/main.js:32:41)
at /Users/hgrzeskowiak/hugo-game/fresh-nx-geckos/nx-geckos-test/dist/apps/geckos-server-app/main.js:45:18
at /Users/hgrzeskowiak/hugo-game/fresh-nx-geckos/nx-geckos-test/dist/apps/geckos-server-app/main.js:59:3
at Object.<anonymous> (/Users/hgrzeskowiak/hugo-game/fresh-nx-geckos/nx-geckos-test/dist/apps/geckos-server-app/main.js:64:12)
I tested quite a few Webpack config overrides and using type: "module" in package.json, but to no avail. The output main.js looks mostly the same no matter what webpack settings I change. Things I tried changing in the app's webpack override config:
module.exports = function(webpackConfig, context) {
webpackConfig.target = "async-node16";
webpackConfig.output.libraryTarget = "module";
webpackConfig.output.library = {type: "module"};
webpackConfig.output.chunkFormat = "module";
webpackConfig.experiments.outputModule = true;
console.log("webpack config:");
console.log(webpackConfig);
console.log("module rules:");
console.log(webpackConfig.module.rules);
return webpackConfig;
}
The console logs in the config verify that the script is being run.
The app works when I manually change the require to import in the transpiled output, but that's not a sustainable solution.
I suspect the error has something to do with Geckos being an ESM package, and Webpack only using require instead of import as it should, but I couldn't find any way of changing that behaviour.
Any ideas?
Node version 16.13.0
Nx version 13.4.1
Webpack (transitive dep of Nx): 5.65.0
Here's the cleanest solution I could find that works with Type Script versions older than 4.6 (which should add support for this feature). This is essentially patching ESM support into WebPack with older TypeScript versions (including latest at the time of writing).
A custom Webpack plugin that changes the type of the external module to import.
// TypeScript before version 4.6 does not support transpiling ESM imports to
// `import()`, but uses `require()` instead. NodeJS does not support the use
// of `require() for ECMAScript modules (ESM).
//
// Good reads:
// https://www.typescriptlang.org/docs/handbook/esm-node.html
// https://devblogs.microsoft.com/typescript/announcing-typescript-4-5/#esm-nodejs
/**
* A Webpack 5 plugin that can be passed a list of packages that are of type
* ESM. The typescript compiler will then be instructed to use the `import`
* external type.
*/
class ESMLoader {
static defaultOptions = {
esmPackages: "all"
};
constructor(options = {}) {
this.options = { ...ESMLoader.defaultOptions, ...options };
}
apply(compiler) {
compiler.hooks.compilation.tap(
"ECMAScript Module (ESM) Loader. Turns require() into import()",
(
compilation
) => {
compilation.hooks.buildModule.tap("Hello World Plugin", (module) => {
if (
module.type === "javascript/dynamic" &&
(
this.options.esmPackages === "all" ||
this.options.esmPackages.includes(module.request)
)
) {
// All types documented at
// https://webpack.js.org/configuration/externals/#externalstype
module.externalType = "import";
}
}
)
;
}
);
}
}
module.exports = function(webpackConfig, context) {
// NodeJS supports dynamic imports since version 12.
webpackConfig.target = "node16";
webpackConfig.plugins.push(
// Manually specify the ESM modules or leave blank for using `import()`
// on all packages.
//new ESMLoader()
new ESMLoader({esmPackages: "#geckos.io/server"})
);
return webpackConfig;
};
The custom webpack config can be set on an Nx app through the project.json:
{
"targets": {
"build": {
"executor": "#nrwl/node:build",
"options": {
...
"webpackConfig": "apps/your-app/webpackConfig.js"
},
...
This solution also requires tsconfig.json to have set the module type to something more modern than commonjs, e.g. es2020:
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "es2020",
"types": ["node"],
},
"exclude": ["**/*.spec.ts", "**/*.test.ts"],
"include": ["**/*.ts"]
}
Once this is done, the built file can be ran using the usual nx serve.

Gatsby + Jest - How to enable support for the experimental syntax 'jsx'?

Following Gatsby unit test docs:
https://www.gatsbyjs.com/docs/how-to/testing/unit-testing/#writing-tests
I got this error:
Details:
SyntaxError: ../Projects/gatsby/testing-first-steps/src/components/__tests__/header.js: Support for the experimental syntax 'jsx' isn't currently enabled (9:15):
7 | it("renders correctly", () => {
8 | const tree = renderer
> 9 | .create(<Header siteTitle="Default Starter" />)
| ^
10 | .toJSON()
11 | expect(tree).toMatchSnapshot()
12 | })
Add #babel/preset-react (https://git.io/JfeDR) to the 'presets' section of your Babel config to enable transformation.
If you want to leave it as-is, add #babel/plugin-syntax-jsx (https://git.io/vb4yA) to the 'plugins' section to enable parsing.
Solved! 🤦
https://www.gatsbyjs.com/docs/how-to/custom-configuration/babel/#how-to-use-a-custom-babelrc-file
Add this:
npm install --save-dev babel-preset-gatsby
then in .babelrc file add this:
{
"presets": [
[
"babel-preset-gatsby",
{
"targets": {
"browsers": [">0.25%", "not dead"]
}
}
]
]
}

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default

I'm trying to use Socket.io in my Laravel/Vue.js app. But I'm getting this error when running npm run dev.
Module not found: Error: Can't resolve 'path' in '/home/nicolas/LaravelProjects/Chess/node_modules/socket.io/dist'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
- install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "path": false }
webpack compiled with 9 errors
I tried changing the webpack.config.js file by adding resolve.fallback: { "path": false }, but it doesn't seem to help. It is possible that I'm doing it wrong since I have 4 webpack.config.js files in my project (I don't know why).
Maybe can I downgrade webpack? Thanks!
This fix worked for me (Vue 3):
In vue.config.js, add:
const { defineConfig } = require('#vue/cli-service')
const NodePolyfillPlugin = require("node-polyfill-webpack-plugin")
module.exports = defineConfig({
transpileDependencies: true,
configureWebpack: {
plugins: [
new NodePolyfillPlugin()
]
}
})
Followed by npm install node-polyfill-webpack-plugin
I had this problem in ReactJS with create-react-app(facebook) but other packages (crypto-browserify)
Solution:
First install the necessary packages in this problem "path-browserify" but in my case "crypto-browserify"
Modify webpack.config.js in reactjs with create-react-app this file is inside:
node_modules/react-scripts/config/webpack.config.js
Search module.exports and inside this function there is a return:
module.exports = function (webpackEnv) {
...
return {
...
resolve: {
...
fallback: {
// Here paste
path: require.resolve("path-browserify"),
// But in mi case I paste
crypto: require.resolve("crypto-browserify"),
}
}
}
}
Note: This solution works, but when the webpack project starts it shows warnings
Pd: I am not native speaker English, but I hope understand me.
I have the same issue in React (feb-2022) using Real (realm-web) from Mongo.
I solve this in two steps:
npm i stream-browserify crypto-browserify
create fallback object into webpack.config.js at node_modules/react-scripts/config/webpack.config.js
module.exports = function (webpackEnv) {
...
return {
...
resolve: {
...
fallback: { // not present by default
"crypto": false,
"stream": false
}
}
}
I have the same issue with crypto. Some say that adding a proper path in TS config (and installing a polyfill) should resolve the issue.
tsconfig.json
{
"compilerOptions": {
"paths": {
"crypto": [
"./node_modules/crypto-browserify"
],
}
Details https://github.com/angular/angular-cli/issues/20819
I'm still fighting with crypto, but above link might help in your struggles.
I had the same issue, Strangely an import {script} from 'laravel-mix' in my app.js. I removed it and everything went back to normal.
I could not get the other answers to work with React on a new project with rss-parser. The error messages aren't clear. I fixed it by adding this line to the webpack configuration:
resolve: {
extensions: ['.tsx', '.ts', '.js'],
fallback: { "http": false, "browser": false, "https": false,
"stream": false, "url": false, "buffer": false, "timers": false
}
},
Watch out for this import in your app.js. Removing it fixed my issue.
use the version of webpack 4.46.0 to remove the error
I had to delete this line in a Vue component to solve the problem:
import { ContextReplacementPlugin } from "webpack";
If you use create-react-app(cra)
You have to overwrite the default webpack file
to do that you need to install a package like "react-app-rewired" that
will help overwriting and merge your configuration with the ones were
added by react scripts
First
npm install --D react-app-rewired
create a new file in the root directory called "config-overrides.js"
Install(using npm) and Add the required dependencies to the created config file
npm i -D path-browserify
install other packages as the error message shows
const webpack = require('webpack');
module.exports = function override(config) {
const fallback = config.resolve.fallback || {};
Object.assign(fallback, {
path: require.resolve('path-browserify'),
add others as shown in the error if there are more
});
config.resolve.fallback = fallback;
config.plugins = (config.plugins || []).concat([
new webpack.ProvidePlugin({
process: 'process/browser',
Buffer: ['buffer', 'Buffer'],
}),
]);
return config;
};
Update your package.json scripts
"scripts": {
"build": "react-app-rewired build",
....
"start": "react-app-rewired start",
"test": "react-app-rewired test"
},
Also please note that a new version of react-scripts(newer than 5.0.1) might solve the issue.
had this issue in a react-app.
installation of stream-browserify crypto-browserify didn't work for me
went through with hjpithadia's answer in Reactjs with a slight change in webpack.config.js
install the package
npm install node-polyfill-webpack-plugin
find the webpack configuration file here
node_modules/react-scripts/config/webpack.config.js
import the package
const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");
search for module.exports
in plugin array add this new NodePolyfillPlugin(),
module.exports = function (webpackEnv) {
...
return {
...
plugins: [
new NodePolyfillPlugin(),
...
]
}
}
For React apps, if you don't need the module make sure webpack ignores it.
install craco https://craco.js.org/docs/getting-started/
create a craco.config.js in the root of your project, mine looks like this:
module.exports = {
webpack: {
configure: (webpackConfig) => {
webpackConfig.resolve.fallback = webpackConfig.resolve.fallback || {}
webpackConfig.resolve.fallback.zlib = false
webpackConfig.resolve.fallback.http = false
webpackConfig.resolve.fallback.https = false
webpackConfig.resolve.fallback.stream = false
webpackConfig.resolve.fallback.util = false
webpackConfig.resolve.fallback.crypto = false
return webpackConfig;
},
}
};
I resolved similar issue:
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "stream": require.resolve("stream-browserify") }'
- install 'stream-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "stream": false }
Installing the npm i stream-browserify --save-dev
Making the custom webpack.config.js file containing:
module.exports = {
resolve: {
fallback: { stream: require.resolve("stream-browserify") },
},
};
Installing the npm install #angular-builders/custom-webpack --save-dev
Assigning (angular.json: projects -> <proj_name> -> architect -> build -> options)
"customWebpackConfig": {
"path": "./webpack.config.js"
}
Changing the: build / serve / extract-i18n / test – as of your needs – to use custom Webpack config:
"builder": "#angular-builders/custom-webpack:browser",
I finally found the solution. With laravel, you have to change the webpack.mix.js file and not webpack.config.js.

Cannot test jest with monaco editor - unexpected token

Running jest on the application fails with:
Details:
/home/**/node_modules/monaco-editor/esm/vs/editor/editor.api.js:5
import { EDITOR_DEFAULTS } from './common/config/editorOptions.js';
^
SyntaxError: Unexpected token {
> 1 | import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
| ^
2 |
3 | /**
4 | * Get create function for the editor.
at ScriptTransformer._transformAndBuildScript (node_modules/#jest/transform/build/ScriptTransformer.js:537:17)
at ScriptTransformer.transform (node_modules/#jest/transform/build/ScriptTransformer.js:579:25)
at Object.<anonymous> (src/utils/editor-actions.js:1:1)
Application has installed packages for jest and babel-jest.
Babel config:
const presets = [
[
"#babel/env",
{
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1"
},
useBuiltIns: "usage",
corejs: 3,
}
],
"#babel/preset-react"
];
const plugins = [
"#babel/plugin-proposal-object-rest-spread",
"#babel/plugin-proposal-class-properties",
"babel-plugin-styled-components"
];
module.exports = { presets, plugins };
The import statement as suggested in the docs for lazy loading modules from monaco leads to the esm folder, which jest is not familiar with.
import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
By default, babel-jest would not transform node_modules and hence anything referencing the monaco-editor would error out. A possible solution is to include monaco-editor package into the compilation step by transformIgnorePatterns as mentioned in the docs
Add these to the jest config:
{
"transformIgnorePatterns": [
"node_modules\/(?!(monaco-editor)\/)"
]
}
PS: If you are using jest-dom, it might start complaining on not implmenting certain features from monaco-editor, you can mock it out with:
jest.mock("monaco-editor/esm/vs/editor/editor.api.js");
The only workaround that helped me in that issue (from here):
In folder __mocks__ create file react-monaco-editor.js with content:
import * as React from 'react';
export default function MonacoEditor() {
return <div />;
}
I have the same issue with Jest and Monaco and to make the tests pass I had to:
Add a moduleNameMapper for monaco-editor: #133 (comment)
Configure a setupTests.js like explained here: stackOverflow
I'm using:
"jest": "^24.9.0"
"babel-jest": "24.9",
"monaco-editor": "^0.20.0"
"react-monaco-editor": "0.33.0",
"monaco-editor-webpack-plugin": "^1.8.2",

Resources