I am using the Visx library to build charts in Nextjs. I am using the Visx scales, for which I import them as follows:
import { scaleBand, scaleLinear, scaleOrdinal } from "#visx/scale"
Internally, Visx uses d3's scales and is using "require" import to access them, so I get the following Nextjs error:
Error: require() of ES Module \node_modules\d3-scale\src\index.js from \node_modules\#visx\scale\lib\scales\band.js not supported. Instead change the require of index.js in \node_modules\#visx\scale\lib\scales\band.js to a dynamic import() which is available in all CommonJS modules.
I know the error is self-explanatory, but I would like to know if there is another solution besides changing the library's files or, in any case, what is the best one.
I also tried changing the imports of Visx scales, but I got another error:
Cannot use import statement outside a module
Related
I have built an application with Angular 12.
I have a JS module called dynamic_module.js which is not available at build time which I want to import and use in the app. However, dynamic_module.js uses rxjs and other imports - all of which are already used in the Angular application and so included in the built webpack. dynamic_module is not an Angular / webpack artifact or anything complicated - it is a simple JavaScript file located on the same server but not available at build time .
When I try to import "dynamic_module.js" using the import(<path_to_dynamic_module.js> ) function - (I'm assuming this method is hi-jacked by webpack) I get an error:
"Error: Cannot find module '<path_to_dynamic_module.js>' ".
I expected this because the dynamic_module.js is not available when the app was built.
So, I tried the method of inserting a <script> element into the header -
e.g. <script type="module" src="<url_of_dynamic_module.js>"></script>
this loads the module but reports the error :
Failed to resolve module specifier "rxjs". Relative
references must start with either "/", "./", or "../".
I also tried this without the import of rxjs in the module, and it works ok.
And if I try using SystemJS with the babel transpiler and try to import the dynamic_module.js, I get an error when System JS tries to load the rxjs module it goes to http.
Error: Fetch error: 404 Not Found Instantiating
http://localhost:4400/rxjs
This also works when the import is removed from dynamic_module.js.
My question is : Can modules dynamically loaded with SystemJS (or any other method) import other modules that are already loaded by webpack - without duplication or reloading via http?
If this is not possible, I could make all the necessary module files available via http for SystemJS to load (I have done this with the 'babel' transpiler modules for SystemJS) . Would that cause two copies of the modules (ie. rxjs in this example) to be loaded into the browser - could this be a serious problem (space/performance/clashes ...)?
Here is a very simple example of the module - this can load by any method if the import is removed, but fails in if the import is included.
dynamic_module.js
import { Observable} from 'rxjs';
export class MyClass{
hello( msg ) {
console.log('[MODULE] Hello World');
console.log(msg);
}
}
Thanks for any advice!
Ok, after some research I have solved my problem:
Let me describe concisely what the issue I had was:
I was trying to import a module (dynamic_module.js) into an Angular
application at run time,
that module had a dependency on a module that was already bundled in
the Angular webpack (rxjs)
I used SystemJS to import my dynamic module
SystemJS tried to resolve my dynamic_module's dependencies by
reloading modules from the server.
I felt that this was unnecessary because the modules were already present in the client application - and anyway, the http requests failed because the dependencies were not to be found where it was looking for them.
The solution is to let SystemJS know in advance that the dependencies are already available. This is done using the SystemJS.set() method: for example in my case the key steps were:
import * as rxjs from "rxjs";
SystemJS.set('rxjs', SystemJS.newModule(rxjs));
SystemJS.import( <url_of_module> ).then( module=>.....});
I am unsure whether I am supposed to use the require version or the import version.
It doesn't state that in the documentation and I found a statement in a Github issue that
Mixing import and require is definitely discouraged. The only way for Rollup to handle require statements is with rollup-plugin-commonjs, but that plugin will skip any files with import or export statements.
which could be interpreted as: "You need to still use require otherwise the common-js plugin will ignore your file and things will not work." or as "always use import everything else would constitute mixing". So that really confused me.
Context
I am trying to import a CommonJS library (Citation-js) into a javascript module (really typescript but I hope this is not relevant here). Now the documentation of common-js tells me to do
const Cite = require('common-js');
which tells me that it is a commonjs library (right?). Therefore I added
import commonjs from "rollup-plugin-commonjs";
import { nodeResolve } from "#rollup/plugin-node-resolve";
to my rollup config and put plugins: [commonjs(), typescript(), nodeResolve()] into the configuration.
Now vscode stops underlining everything and building the website with rollup works again. But the compiled javascript simply states require('common-js') and my browser complains that require is undefined.
Uncaught ReferenceError: require is not defined
So I tried
import Cite from 'common-js';
instead. But that resulted in the rollup build failing with
[!] Error: Unexpected token (Note that you need #rollup/plugin-json to import JSON files)
node_modules/#citation-js/core/package.json (2:8)
1: {
2: "name": "#citation-js/core",
^
Now I could of course install that plugin. But I am not sure that is right, since the whole point of a tool like rollup should be that dependencies of dependencies should be resolved automatically right?
I have also tried
Can't import npm modules in commonjs with rollup : "require is not defined"
This seemed like it would fix my problem: Using Older Require Module With Rollup
But:
the rollup-plugin-node-builtins is apparently not maintained (npm protested with security vulnerabilities and I found this: https://github.com/rollup/rollup/issues/2881). EDIT: There is a new package rollup-plugin-polyfill-node replacing that I guess.
resolve is no longer a member of #rollup/plugin-node-resolve so I assume that this has become nodeResolve which I am already using...
EDIT: installing #rollup/plugin-json actually lets me build the site again (with a bunch of warnings)
(!) Missing shims for Node.js built-ins (which is not fixed by the rollup-plugin-polyfill-node above)
(!) Missing global variable names
(!) Circular dependencies
(!) Unresolved dependencies
not sure what to do about these warnings
I'm trying to import the twitter-text package into a React/ES6 environment, and I'm not able to figure out what exactly is exported and keep getting ...is not exported from 'twitter-text'. compile errors.
Doc states that the twttr.txt namespace is exported, but all the examples I can find are for node and use require(). It installed fine via npm install twitter-text and it's finding refs, for example import { parseTweet } from 'twitter-text'; is grabbing actual function and class refs from the package, but still the no export error when it compiles.
I also tried to get the global twttr.txt using just import 'twitter-text'; but I'm getting the same error.
The library is default-exporting an object unfortunately, which means that you need to use
import twttr from 'twitter-text'
twttr.parseTweet(…)
Named exports do not seem to be available.
This is a strange issue, but I'm trying to require an es6 module into a section of my application that is using es5.
es6file.js
import moment from 'moment'
etc...
es5file.js
var config = require('../../../es6file')
etc...
and I keep getting an error of Unexpected token import
This, of course, makes sense. But I'm wondering if there is an easy way to allow myself to import this file without updating my entire application to handle imports instead of requires.
Right now I pull in all my own es6 modules and create a bundle using Rollup.
Recently I started using VueJS, which now has an ES6 Module which can be pulled in just like my own modules. Rollup does some treeshaking on it, but I don't know if that is a very good idea? I don't know what it is doing, so I would rather it does nothing!
Instead I just add vue at the end of my HTML:
<script src="dist/bundle.js"></script>
I love the convenience of having everything as one bundled file, but should I really treeshake the entire Vue app, is there a command in Rollup that I can not treeshake just this one module?
EDIT
I have found the --external option, which seems good as it would just keep the import for vue and bundle the rest, but it does not seem to work!
When I use rollup --format=iife --external=../node_modules/vue/dist/vue.esm.browser.js --file=dist/bundle.js -- src/main.js it says Error: Could not resolve '../node_modules/vue/dist/vue.esm.browser.js' from src/app.js.
In my main.js it has import Vue from '../node_modules/vue/dist/vue.esm.browser.js; which works fine for the app. I want to make Vue an external, but it won't work!
To prevent Rollup from treeshaking a particular module, you can simply import it blindly (instead of a part of it), so that Rollup thinks the module performs some side effect:
import 'vue'
Of course you can still import some bits in parallel, so that you can rename the default export for example:
import 'vue'
import Vue from 'vue'
As for your --external option, you probably just need to wrap the path value with quotes:
--external='../node_modules/vue/dist/vue.esm.browser.js'
Note that you should probably switch to Rollup configuration file (instead of CLI options) to make your life easier. You will also be able to use rollup plugins, e.g. rollup-plugin-alias to manage the exact location of the Vue file you want to use.