Rollup with d3 plugin : reference is not defined - javascript

I'm quite new using rollup to make custom d3 build. I'm trying to use the d3-annotation plugin but when the build is done, I get an error in my console:ReferenceError: d3Dispatch is not defined
In the builded file, it seems that all the property like d3Dispatch, d3Selection, etc. aren't "translated". The require lines disappear too (which is probably normal).
Here is rollup config file:
import { queue } from "d3-queue";
import { event, select, selectAll } from "d3-selection";
import { scaleLinear, scaleIdentity } from "d3-scale";
import { drag } from "d3-drag";
import { json } from "d3-request";
import { annotation, annotationCalloutCircle } from "d3-svg-annotation";
export {
queue,
event,
select,
selectAll,
scaleLinear,
scaleIdentity,
drag,
json,
annotation,
annotationCalloutCircle
}
Which it used with a gulp task:
gulp.task('d3-rollup', function() {
return rollup({
entry: 'js/custom.d3.js',
plugins: [
babel(),
nodeResolve({ jsnext: true }),
commonjs(),
rollup_uglify()
]
}).then(function(bundle) {
return bundle.write({
format: 'umd',
moduleName: 'd3',
dest: 'js/d3.min.js'
});
});
});
I just can't get what is wrong. Do I need to import another property ? Have you an idea ?

This was a bug in the es6/jsnext/module setup for the package.json of the project. It has been resolved in versions 1.6.0 and up.

Related

vitest crypto.randomUUID() is not a function

vite.config.ts
import { sveltekit } from '#sveltejs/kit/vite';
const config = {
plugins: [sveltekit()],
test: {
include: ['**/*.spec.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
environment: 'jsdom',
globals: true,
setupFiles: 'src/setupTests.ts'
}
};
export default config;
src/setupTests.ts
import '#testing-library/jest-dom/extend-expect';
MyComponent.svelte
onMount(() => {
postElementId = crypto.randomUUID();
...
});
Error
TypeError: crypto.randomUUID is not a function
I've got a component that uses the crypto api to create a random id and works as intended, but when I want to test it, everytime I do this error pops up, any help is appreciated!
Just checking, did you:
import crypto from 'node:crypto';
at some point?
My vitest error was window.crypto.randomUUID() is not a function.
So, I added setupFiles to vite.config.js
test: {
setupFiles: [
'./test/_setup/globalSetup.js'
],
...
Then, in globalSetup.js file I added these 2 lines:
import {randomUUID} from 'node:crypto';
window.crypto.randomUUID = randomUUID;
And it seems to have done the trick.

Jest with angular unable to turn on coverage because of es6

I'm trying to set up an angular project to work with jest. So far it works with the following config
// jest.config.js
module.exports = {
// other stuff
preset: "jest-preset-angular",
setupFilesAfterEnv: ["<rootDir>/setup-jest.ts"],
globalSetup: "jest-preset-angular/global-setup",
globals: {
"ts-jest": {
tsconfig: "<rootDir>/tsconfig.spec.json",
stringifyContentPathRegex: "\\.html$",
useESM: true,
},
},
};
And the following in my setup-jest.ts
import 'jest-preset-angular/setup-jest';
import './jest-global-mocks';
Problem is that as soon as I introduce any code that brings in an ES module, it blows up (even though I've tried following the ESM support page on the jest-preset-angular docs). So far, I've just dealt with this by finding alternative packages. But when I try to turn on --coverage, I get this.
import { __decorate } from "tslib";
^^^^^^
SyntaxError: Cannot use import statement outside a module
1 | import { TestBed } from '#angular/core/testing';
> 2 | import { AppModule } from './app.module';
| ^
3 | import { APP_BASE_HREF } from '#angular/common';
4 |
5 | describe('The app module', () => {
I've tried dissecting jest-preset-angular and extracting the settings that seem like they should apply to projects using ES6, which has led me to making these changes:
// jest.config.js
module.exports = {
// other stuff
setupFilesAfterEnv: ["<rootDir>/setup-jest.ts"],
transformIgnorePatterns: ["/node_modules/(?!tslib)"],
transform: {
"^.+\\.(ts|html|svg)$": "jest-preset-angular",
},
extensionsToTreatAsEsm: [".ts"],
globals: {
"ts-jest": {
tsconfig: "<rootDir>/tsconfig.spec.json",
stringifyContentPathRegex: "\\.html$",
useESM: true,
},
},
};
And now its failing on the core angular mjs files
/Users/benwainwright1/repos/ng-budget/node_modules/#testing-library/angular/fesm2020/testing-library-angular.mjs:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import * as i0 from '#angular/core';
^^^^^^
SyntaxError: Cannot use import statement outside a module
This is even more confusing for me because as far as I can see
the transform key doesn't specify .mjs, so .mjs files should be left alone
I'm using node v16 and jest v28, which should automatically treat .mjs files as modules

Fetch file in library (rollup)

I'm building javascript library (more something like widget) which will have some UI within. I'm adding HTML elements to DOM by javascript. To add this HTML I have following code:
async insertWidgetMarkup() {
try {
const response = await fetch('src/html/form.html')
this.rootElement.innerHTML = await response.text()
} catch (e) {
console.error('Error gathering form HTML.', e)
}
}
I build entire thing with rollup
// rollup.config.js
import commonjs from '#rollup/plugin-commonjs';
export default {
input: 'main.js',
output: {
dir: 'dist',
format: 'cjs',
name: 'search_widget.js'
},
plugins: [commonjs()]
};
// package.json
"scripts": {
"build": "rollup --config --watch",
My issue is that in bundled file I have await fetch('src/html/form.html'); therefore it won't work in other applications. Can I somehow tell rollup to resolve this so it will have HTML in bundled file? Or if no - what other options I have, what is typical approach for that?
Instead of fetching, you can import the file directly with the rollup-plugin-html.
Setup rollup config to use the plugin like this
import commonjs from '#rollup/plugin-commonjs';
import html from 'rollup-plugin-html';
export default {
input: 'main.js',
output: {
format: 'umd',
name: 'search_widget',
file: 'dist/search_widget.js'
},
plugins: [
commonjs(),
html({
include: '**/*.html'
})
]
};
Then in your source file, use import like this
import html from 'src/html/form.html'
insertWidgetMarkup() {
try {
this.rootElement.innerHTML = html
} catch (e) {
console.error('Error gathering form HTML.', e)
}
}
Rollup will bundle the html files now.

Rollup.js - have PostCSS process whole bundle.css instead of individual files from rollup-plugin-svelte

I've tried several guides and many configurations, but can't get my rollup, postcss, and svelte bundle process to work quite right.
Right now the svelte plugin is extracting the css from my .svelte files and emitting it to the posctcss plugin, but it's doing it one file at a time instead of the entire bundle. This makes it so some functions in the purgecss and nanocss postcss plugins don't completely work because they need the entire bundle to do things like remove duplicate/redundant/unused css rules.
// rollup.config.js
import svelte from 'rollup-plugin-svelte'
import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import livereload from 'rollup-plugin-livereload'
import { terser } from 'rollup-plugin-terser'
import rollup_start_dev from './rollup_start_dev'
import builtins from 'rollup-plugin-node-builtins'
import postcss from 'rollup-plugin-postcss'
const production = !process.env.ROLLUP_WATCH
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/bundle.js',
},
plugins: [
svelte({
dev: !production,
emitCss: true,
}),
postcss({
extract: true,
sourceMap: true,
}),
builtins(),
resolve({
browser: true,
dedupe: importee =>
importee === 'svelte' || importee.startsWith('svelte/'),
}),
commonjs(),
!production && rollup_start_dev,
!production && livereload('public'),
production && terser(),
],
watch: {
clearScreen: false,
},
}
// postcss.config.js
const production = !process.env.ROLLUP_WATCH
const purgecss = require('#fullhuman/postcss-purgecss')
module.exports = {
plugins: [
require('postcss-import')(),
require('tailwindcss'),
require('autoprefixer'),
production &&
purgecss({
content: ['./src/**/*.svelte', './src/**/*.html', './public/**/*.html'],
css: ['./src/**/*.css'],
whitelistPatterns: [/svelte-/],
defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || [],
}),
production &&
require('cssnano')({
preset: 'default',
}),
],
}
How can I have rollup pass the entire bundle.css to postcss instead of one "file" at a time?
I had the same problem, preprocess goes file by file, so I had to actually include all my mixins and vars in every file, which is absolutely not a good solution.
So for me the first solution was to remove postcss from sveltePreprocess, not emit the css file and to use postcss on the css bundle, that you get in the css function from svelte.
You can then or (1) use postcss directly in the css function of svelte, and then emit the resulting css file in your dist directory, or (2) you can emit this file in a CSS directory, and have postcss-cli watch this directory and bundle everything
Solution 1
// rollup.config.js
// rollup.config.js
import svelte from 'rollup-plugin-svelte';
import resolve from 'rollup-plugin-node-resolve';
import postcss from 'postcss';
import postcssConfig from './postcss.config.js';
const postcssPlugins = postcssConfig({});
const postcssProcessor = postcss(postcssPlugins);
export default {
input: 'src/main.js',
output: {
file: 'public/bundle.js',
format: 'iife',
},
plugins: [
svelte({
emitCss: false,
css: async (css) => {
const result = await postcssProcessor.process(css.code);
css.code = result.css;
css.write('public/bundle.css');
},
}),
resolve(),
],
};
and my postcss.config.js which returns a function that return an array of plugins:
export default (options) => {
const plugins = [
require('postcss-preset-env')()
];
if (options.isProd) {
plugins.push(require('cssnano')({ autoprefixer: false }));
}
return plugins;
};
Solution 2
// rollup.config.js
import svelte from 'rollup-plugin-svelte';
import resolve from 'rollup-plugin-node-resolve';
export default {
input: 'src/main.js',
output: {
file: 'public/bundle.js',
format: 'iife',
},
plugins: [
svelte({
emitCss: false,
css: async (css) => {
css.write('css/svelte-bundle.css');
},
}),
resolve(),
],
};
// package.json
{
//...
"scripts": {
"dev": "npm-run-all --parallel js:watch css:watch",
"js:watch": "rollup -c -w",
"css:watch": "postcss css/app.css --dir dist/ --watch",
},
}
/* css/app.css */
#import 'vars.css';
#import 'mixins.css';
/* all other code ... */
/* and svelte-bundle, which will trigger a bundling with postcss everytime it is emitted */
#import 'svelte-bundle.css';
Conclusion
All in all, I don't like this methods, for exemple because I can't use nesting, as svelte throws an error if the css is not valid.
I would prefer being able to use rollup-plugin-postcss after rollup-plugin-svelte, with emitCss set to false and the possibility to use rollup's this.emitFile in svelte css function, because since once the bundled file is emitted, we should be able to process it.
It seems there are some issues talking about using emitfile, let's hope it will happen sooner than later https://github.com/sveltejs/rollup-plugin-svelte/issues/71
Can't say for sure, but when i compare your setup with mine the most striking difference is that i have:
css: css => {
css.write('public/build/bundle.css');
}
in the svelte options additionally.
My whole svelte option looks like this:
svelte({
preprocess: sveltePreprocess({ postcss: true }),
dev: !production,
css: css => {
css.write('public/build/bundle.css');
}
})
Note, i'm using sveltePreprocess which would make your postcss superfluous, but i don't think that is causing your issue.

Unexpected "Uncaught TypeError: XXX is not a constructor" errors with Babel and ES6

I am giving a try to Webpack, and am giving a try to the instructions in this tutorial, give or take a few custom things.
This is simple code, really, but I'm quite puzzled about this error, and feel this is something silly that I missed.
I defined two ES6 classes, each corresponding to a Handlebars template, and my app's entrypoint is supposed to replace the placeholder HTML in the index file by their contents:
Entrypoint:
import './bloj.less'
// If we have a link, render the Button component on it
if (document.querySelectorAll('a').length) {
require.ensure([], () => {
const Button = require('./Components/Button.js');
const button = new Button('9gag.com');
button.render('a');
}, 'button');
}
// If we have a title, render the Header component on it
if (document.querySelectorAll('h1').length) {
require.ensure([], () => {
const Header = require('./Components/Header.js');
new Header().render('h1');
}, 'header');
}
Index:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1>My title</h1>
<a>Click me</a>
<script src="build/bloj.js"></script>
</body>
</html>
Button:
import $ from 'jquery';
import './Button.less';
export default class Button {
constructor(link) {
this.link = link;
}
onClick(event) {
event.preventDefault();
alert(this.link);
}
render(node) {
const text = $(node).text();
var compiled = require('./Button.hbs');
// Render our button
$(node).html(
compiled({"text": text, "link": this.link})
);
// Attach our listeners
$('.button').click(this.onClick.bind(this));
}
}
Header:
import $ from 'jquery';
import './Header.less';
export default class Header {
render(node) {
const text = $(node).text();
var compiled = require('./Header.hbs');
// Render the header
$(node).html(
compiled({"text": text})
);
}
}
Sadly, it does not work, and I get both these errors when displaying the page:
Uncaught TypeError: Header is not a constructor
Uncaught TypeError: Button is not a constructor
What could I be missing?
Here is my webpack configuration:
var path = require('path');
var webpack = require('webpack');
var CleanPlugin = require('clean-webpack-plugin');
var ExtractPlugin = require('extract-text-webpack-plugin');
var production = process.env.NODE_ENV === 'production';
var appName = 'bloj';
var entryPoint = './src/bloj.js';
var outputDir = './build/';
var publicDir = './build/';
// ************************************************************************** //
var plugins = [
//new ExtractPlugin(appName + '.css', {allChunks: true}),
new CleanPlugin(outputDir),
new webpack.optimize.CommonsChunkPlugin({
name: 'main',
children: true,
minChunks: 2
})
];
if (production) {
plugins = plugins.concat([
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.MinChunkSizePlugin({
minChunkSize: 51200 // 50ko
}),
new webpack.optimize.UglifyJsPlugin({
mangle: true,
compress: {
warnings: false // Suppress uglification warnings
}
}),
new webpack.DefinePlugin({
__SERVER__: false,
__DEVELOPMENT__: false,
__DEVTOOLS__: false,
'process.env': {
BABEL_ENV: JSON.stringify(process.env.NODE_ENV)
}
})
]);
}
module.exports = {
entry: entryPoint,
output: {
path: outputDir,
filename: appName + '.js',
chunkFilename: '[name].js',
publicPath: publicDir
},
debug: !production,
devtool: production ? false : 'eval',
module: {
loaders: [
{
test: /\.js/,
loader: "babel",
include: path.resolve(__dirname, 'src'),
query: {
presets: ['es2015']
}
},
{
test: /\.less/,
//loader: ExtractPlugin.extract('style', 'css!less')
loader: "style!css!less"
},
{
test: /\.html/,
loader: 'html'
},
{
test: /\.hbs/,
loader: "handlebars-template-loader"
}
]
},
plugins: plugins,
node: {
fs: "empty" // Avoids Handlebars error messages
}
};
What could I be missing?
Babel assigns default exports to the default property. So if you use require to import ES6 modules, you need to access the default property:
const Button = require('./Components/Button.js').default;
I realize that you already have an answer. However I had a similar issue to which I found an answer. Starting my own question and answering it seems weird.
So I'm just going to leave this here.
I had the same error as you got. However, I managed to solve it by changing my
export default {Class}
to
export default Class
I don't know why I wrapped the Class in an object but I remember having seen it somewhere so I just started using it.
So instead of the default returning a Class it returned an object like this {Class: Class}.
This is completely valid yet it will break webpack+babel.
EDIT: I've since come to know why this probably breaks babel+webpack. The export default is meant to only have 1 export. A javascript-object can contain many properties. Which means it can have more than 1 export. (See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export).
For multiple exports use: export {definition1, definition2}.
Use-case: I've used this in a situation where I've created a library which exported different types of an editor (while the underlying code was the same, the appearance of the editor changes depending on which export you use).
You can just put export var __useDefault = true; just after exporting your Class.
export default class Header {
...
}
export var __useDefault = true;
I was able to fix this by adding babel-plugin-add-module-exports to the .babelrc file
npm install babel-plugin-add-module-exports --save-dev
{
"presets": ["#babel/env"],
"plugins": ["add-module-exports"]
}
this adds
module.exports = exports.default;
to the last line when compiling the class with babel.
Although this is not the cause of your particular issue, I ran into a very similar problem when trying to rip babel out of an existing node app that was using ES6's import and export syntax, so this post is to help out anyone else struggling with this in the future.
Babel will resolve any circular dependencies between one module and another, so you can use ES6's import and export with reckless abandon. However, if you need to get rid of babel and use native node, you will need to replace any import and exports with require. This can reintroduce a latent circular reference issues that babel was taking care of in the background. If you find yourself in this situation, look for an area in your code that looks like this:
File A:
const B = require('B');
class A {
constructor() {
this.b = new B();
}
}
module.exports = A;
File B:
const A = require('A'); // this line causes the error
class B {
constructor() {
this.a = new A();
}
}
module.exports = B;
There are several different ways to resolve this issue depending on how you structured your code. The easiest way is probably to pass B a reference to A instead of creating a new instance of class A. You could also dynamically resolve the reference when loading A. There are a myriad of other alternatives, but this is a good place to get started.
It's not the problem in this particular question, but for some reasons, babel does not hoist classes in the same file.
So if you declare your class Token at the top of the file, and write later new Token(), it will run.
If you declare your class after the constructor call, you will have the xxx is not a constructor error
I had the same error message and discovered that the cause was circular import statements. That is: I had two files that imported each other, wherein one file contained an export default class that contained a method that was dependent upon an export function from the other file.
My solution was to move one of the dependencies (functions) out of the class and into a utils.js file, which was a more appropriate place for it anyway!
This is the way I am using / importing my classes:
Utils.class.js
export default class Utils {
somefunction(val) {
return val
}
}
Using Utils into my controllers:
import {default as U} from '../helpers/Utils.class';
const Utils = new U();
console.log(Utils.somefunction(123));

Categories

Resources