Class constructor cannot be invoked without 'new' - javascript

Appreciate that this questions has been asked a few times, but almost all the cases that I've encountered have been the ones where someone tried to extend a non-native class. My case is different. I have a very simple base class called CObject which is as follows:
export class CObject extends BaseObject {
constructor() {
super();
}
static url(path: string): string { return ""; }
static wssUrl(): string { return ""; }
static callMethod(method, path: string, params: any, noConvertData?: boolean): Promise<any> { return null; }
static post(path: string, params: any, noConvertData?: boolean): Promise<any> {
return CObject.callMethod('post', path, params, noConvertData);
}
static put(path: string, params: any, noConvertData?: boolean): Promise<any> {
return CObject.callMethod('put', path, params, noConvertData);
}
static patch(path: string, params: any, noConvertData?: boolean): Promise<any> {
return CObject.callMethod('patch', path, params, noConvertData);
}
static get(path: string, params: any, noConvertData?: boolean): Promise<any> {
return CObject.callMethod('get', path, params, noConvertData);
}
static delete(path: string, params: any, noConvertData?: boolean): Promise<any> {
return CObject.callMethod('delete', path, params, noConvertData);
}
}
The entire hierarchy of classes including BaseObject, are just simple Typescript classes. However, when I extend a class from CObject and then try instantiating it, I get this dreaded error (4 days now!). The funny thing is that I can instantiate CObject on it's own without any issues. It's just derived classes that are giving the issue, even empty ones like this:
export class TestClass extends CObject {
constructor() {
super();
}
}
A point to note is that this code is shared between my Server (Node.js) and Client sides. The code works perfectly fine on the server side. No issues whatsoever.
I have tried looking at the babel generated code and it's just simple ES6 classes. All other TS generated classes work as fine and everything below CObject fails when it gets to calling the CObject constructor.
My .babelrc is given below:
{
"presets": [
"es2015-node5",
"react",
"stage-0",
"stage-1",
"bluebird"
],
"plugins": [
"transform-decorators-legacy",
"react-hot-loader/babel",
"transform-async-to-bluebird",
"transform-promise-to-bluebird",
"transform-runtime",
[
"module-alias",
[
{ "src": "./build/Server", "expose": "Server" },
{ "src": "./build/Shared", "expose": "Shared" },
{ "src": "./build/Client", "expose": "Client" }
]
]
],
"compact": "false"
}`
For client side compilation, my awesome-typescript-loader config in tsconfig.json is as follows:
EDIT: I was looking at the wrong ATL config. The full config is as follows:
"awesomeTypescriptLoaderOptions": {
"babelrc": true,
"useBabel": true,
"useWebpackText": true,
"useTranspileModule": true,
"doTypeCheck": true,
"forkChecker": true,
"presets": ["env", { "targets": "last 2 versions, ie 11", "modules": false }, { "exclude": ["transform-es2015-classes"] } ],
"babelOptions": {
"sourceMaps": true
},
"useCache": true
}
Client side webpack config is as follows:
var path = require('path');
var webpack = require('webpack');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
let outputDir = path.join(__dirname, "..", "dist", "Client");
console.log(`Output: ${outputDir}`);
module.exports = {
entry: "./src/Client/Browser/Src/Main.tsx",
output: {
filename: "client.js",
path: outputDir
},
target: 'web',
// Enable sourcemaps for debugging webpack's output.
devtool: "source-map",
resolve: {
// Add '.ts' and '.tsx' as resolvable extensions.
extensions: [".ts", ".tsx", ".js", ".json"],
plugins: [new TsconfigPathsPlugin({ configFile: "./tsconfig.json" })],
modules: [
"./node_modules",
"./src/Shared",
"./src/Client"
]
},
module: {
rules: [
// All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
{ test: /\.tsx?$/, loader: "awesome-typescript-loader" },
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" }
]
}
};
Any help will be appreciated. Thank you.
Edit: The exact error is:
ConfigSection.ts?26cc:18 Uncaught TypeError: Class constructor CObject cannot be invoked without 'new'
at new ConfigSection (ConfigSection.ts?26cc:18)
at Object../src/Shared/Model/Config/ShAlpha.ts (ShAlpha.ts:338)
at __webpack_require__ (bootstrap:19)

Ok, thanks to Oscar Paz, I have been able to fix the issue. Turns out that the culprit was my ATL config:
"awesomeTypescriptLoaderOptions": {
"babelrc": true,
"useBabel": true,
"useWebpackText": true,
"useTranspileModule": true,
"doTypeCheck": true,
"forkChecker": true,
"presets": ["env", { "targets": "last 2 versions, ie 11", "modules": false }, { "exclude": ["transform-es2015-classes"] } ],
"babelOptions": {
"sourceMaps": true
},
"useCache": true
}
More specifically, this line:
"presets": ["env", { "targets": "last 2 versions, ie 11", "modules": false }, { "exclude": ["transform-es2015-classes"] } ],
even though I'd set:
"babelrc": true,
Expecting the .babelrc to get used, which is what was getting used for the Node.js code. This was causing multiple definitions (both ES6 and ES5) of the classes derived from CObject to be generated. So CObject was getting generated correctly:
let CObject = exports.CObject = class CObject extends _BaseObject.BaseObject {} ...
The first definition of ConfigSection was also getting generated correctly:
let ConfigSection = ConfigSection_1 = class ConfigSection extends Shared_Core_CObject__WEBPACK_IMPORTED_MODULE_1__["CObject"] {} ...
But then further down:
var ConfigSection = ConfigSection_1 = function (_CObject) {
(0, _inherits3.default)(ConfigSection, _CObject); ...
This is what was causing the error. I don't know why ATL isn't ignoring those options and why those options cause this sort of code-gen. Perhaps, someone with a better understanding can shed some light.

For fellow Googlers, another cause of this error: on 04/2019, using the non maintained why-did-you-update npm React module caused this error.
Removing the module and its invocation fixed the bug.

I found removing semi-colons from the end of lines using require() (and in my case, right before an IIFE) caused this issue.
const MyClass = require("./myclass")
(() => { ... code ... })()
Once I added semi-colons on the end, the issue was resolved. YMMV

Related

rollup-plugin-babel not recognizing JSX

I am having issues with RollupJS API. For some reason, its not recognizing JSX syntax. Rollup (API) is giving me this error.
Error: Unexpected token (Note that you need plugins to import files that are not JavaScript)
2: import App from "./App";
3: const MyApp = (props) => {
4: return <View index={<App />} url={props.url} serverOptions={props.serverOptions}/>;
^
5: };
6: export default MyApp;
Here's the Rollup config.
export const loadBuildConfigurationOptions = (tsconfigOptions: object, root: Path = Process.Cwd()): RollupOptions => {
return <RollupOptions> {
input: Path.FromSegments(root, "src", "index.ts").toString(),
output: [
{
dir: Path.FromSegments(root, "dist").toString(),
format: "cjs"
}
],
external: [
"solid-js",
"solid-js/web",
"solidus"
],
plugins: [
typescript(tsconfigOptions),
nodeResolve({
preferBuiltins: true,
exportConditions: ["solid"],
extensions: [".js", ".jsx", ".ts", ".tsx"]
}),
nodePolyfill(),
babel({
babelHelpers: "bundled",
presets: [["solid", { generate: "ssr", hydratable: true }]],
}),
json(),
styles(),
copy({
targets: [
{ src: 'src/assets/**/*', dest: 'dist/src/assets' }
]
}),
],
preserveEntrySignatures: false,
treeshake: true,
};
}
I am using this in a build tool for a SolidJS SSR library I am developing. what is happening here is this function generates the appropriate Rollup configuration file to for the project being build by the user of this library. The returned Rollup configuration object is then being used by the Rollup JS API to build the actual application. Do I need to change the parameters in the babel plugin or something?
Okay. I figured it out. It’s quite silly really. I just had to make one change to the Babel plugin.
babel({
babelHelpers: "bundled",
presets: [["solid", { generate: "ssr", hydratable: true }]],
extensions: [“.js”, “.ts”, “.jsx”, “.tsx”],
}),
Adding the extensions option seemed to have fixed everything.

Babel module resolver not working with react-native

My babel module resolver is not working with React-Native (neither does intellij in VScode)
Here, Is my babel config
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'module-resolver',
{
root: ['./'],
alias: {
'#assets': './src/assets',
'#modules': './src/modules',
'#config': './src/config',
'#utils': './src/utils',
},
},
],
],
};
And jsconfig.json
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"#assets": ["./assets"],
"#modules": ["./modules"],
"#config": ["./config"],
"#utils": ["./utils"]
}
}
}
I changed import for one of my files and this is the error I get when I executed the build command from Xcode
Error: Error loading assets JSON from Metro. Ensure you've followed
all expo-updates installation steps correctly. Unable to resolve
module ../../modules/store/components/Filters from
src/utils/Router.js:
None of these files exist:
Where I imported the file like this
import Filters from '#modules/store/components/Filters';
I had the same problem, I just removed the '#' from my aliases and it seems working fine now.
Here is my babel.config.js
module.exports = function (api) { ■ File is a CommonJS module; it may be converted to an ES6 module.
api.cache(true);
return {
presets: ["babel-preset-expo"],
plugins: [
[
require.resolve("babel-plugin-module-resolver"),
{
root: ["./src/"],
alias: {
// define aliases to shorten the import paths
components: "./src/components",
containers: "./src/containers",
contexts: "./src/contexts",
interfaces: "./src/interfaces",
organizer: "./src/screens/organizer",
screens: "./src/screens",
},
extensions: [".js", ".jsx", ".tsx", ".ios.js", ".android.js"],
},
],
],
};
};
Try resetting the cache, if above suggested answers don't work
react-native start --reset-cache
This worked for me. For more info see here
Change your module-resolver's root to ['./src/']:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'module-resolver',
{
root: ['./src/'], // <-- here ✅
alias: {
'#assets': './src/assets',
'#modules': './src/modules',
'#config': './src/config',
'#utils': './src/utils',
},
},
],
],
};

Rollup is not generating typescript sourcemap

I am using rollup with svelte + typescript + scss. My problem is that I am not able to generate source maps.
Following is my rollup config file:
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 typescript from '#rollup/plugin-typescript'
import alias from '#rollup/plugin-alias'
const production = !process.env.ROLLUP_WATCH
const path = require('path').resolve(__dirname, 'src')
const svelteOptions = require('./svelte.config')
function serve() {
let server
function toExit() {
if (server) server.kill(0)
}
return {
writeBundle() {
if (server) return
server = require('child_process').spawn(
'yarn',
['run', 'start', '--', '--dev'],
{
stdio: ['ignore', 'inherit', 'inherit'],
shell: true,
}
)
process.on('SIGTERM', toExit)
process.on('exit', toExit)
},
}
}
export default {
input: 'src/main.ts',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/build/bundle.js',
},
plugins: [
alias({
entries: [
{ find: '#app', replacement: `${path}` },
{ find: '#components', replacement: `${path}/components` },
{ find: '#includes', replacement: `${path}/includes` },
{ find: '#styles', replacement: `${path}/styles` },
{ find: '#pages', replacement: `${path}/pages` },
],
}),
svelte(svelteOptions),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration -
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
browser: true,
dedupe: ['svelte'],
}),
commonjs(),
typescript({ sourceMap: !production }),
// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('public'),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser(),
],
watch: {
clearScreen: false,
},
}
I am not sure what exactly am I doing wrong. Here is the link to code I am using.
Any help will be deeply appreciated!
This is what worked for me: you need to set sourceMap: false in the typescript rollup plugin options.
export default {
input: 'src/main.ts',
output: {
sourcemap: true,
format: 'iife',
...
},
plugins: [
...
svelte(...),
typescript({ sourceMap: false }),
...
]
}
It turns out rollup's sourcemap collapser conflicts with the typescript's plugin sourcemap generator. That's why it works on prod builds but not in dev builds (because originally it is sourceMap: !production). Just let rollup do the heavy lifting.
As also mentioned by others, it seems like the combination of TypeScript and Rollup leads to the problem. Disabling the source map in TypeScript only fixes the problem of mapping Svelte to TypeScript. However you only receive a source map showing source in the compiled JavaScript, not in the original TypeScript. I finally found a solution, that worked for me: Just add the Option inlineSources: true to the TypeScript options:
typescript({ sourceMap: !production, inlineSources: !production }),
This circumvents the problem by simply not creating a duplicate SourceMap, but by copying the source code from TypeScript into the SourceMap.
For anyone using terser, not svelte, this solved the same problem for me:
import sourcemaps from 'rollup-plugin-sourcemaps';
import { terser } from 'rollup-plugin-terser';
import typescript from '#rollup/plugin-typescript';
export default [
{
input: 'dist/index.js',
output: [
{
file: 'dist/cjs/index.js',
format: 'cjs'
},
{
file: 'dist/fesm2015/index.js',
format: 'es'
}
],
plugins: [
sourcemaps(),
terser(),
typescript({ sourceMap: true, inlineSources: true })
]
}
];
Apparently rollup-plugin-sourcemaps is needed to do the magic necessary to utilize the map files generated by the TypeScript compiler and feed them to terser.
For me, I am able to map, by making sourcemap: "inline"
In the /build/index.esm.js file will have mapping inside.
export default {
input: "src/index.ts",
output: [
{
file: 'build/index.esm.js',
format: 'es',
sourcemap: "inline"
},
],
plugins: [
typescript({ sourceMap: false, inlineSources: true }),
]
}
I was having a similar issue with Karma, rollup, and typescript. I fixed it by adding "sourceRoot":"/base/" to my tsconfig.json file.
Before: map file entries pointed to /src/.
After: map file entries pointed to /base/src/ and everything worked.
// tsconfig.rollup.json
"compilerOptions": {
"module": "ES2022",
"esModuleInterop": true,
"target": "ES2022",
"moduleResolution": "classic",
"sourceMap": true,
"sourceRoot": "/base/"
...
}
// rollup.config.js
import typescript from '#rollup/plugin-typescript';
export default [
{
input: './src/test/test_context.spec.ts',
output: {
file: './dist/test/test_context.spec.js',
format: 'es',
sourcemap: 'inline'
},
plugins: [
typescript({
tsconfig: './tsconfig.rollup.json'
})
]
}
];

Karma unit test for ES6 modules with babel

I'm following instructions from karma-babel-preprocessor to set up unit tests in a project I'm currently working, but I always the error
'require is not defined'
My karma.conf.js is as follows:
files: [
{ pattern: './test/unit/*.spec.js', watched: true },
{ pattern: './src/js/es6_modules/*.js', watched: false },
],
preprocessors: {
'./src/js/es6_modules/*.js': ['babel'],
'./test/unit/*.spec.js': ['babel'] //, 'coverage'
},
babelPreprocessor: {
options: {
presets: ['es2015'],
sourceMap: 'inline'
},
filename: function (file) {
return file.originalPath.replace(/\.js$/, '.es5.js');
},
sourceFileName: function (file) {
return file.originalPath;
}
}
The scripts in src/js/es6_modules jave ES6 classes exported. Something like:
export default class MyClass {
}
And my spec file would need to import this
import { MyClass } from "../../src/js/es6_modules/myclass";
I have seen some thread here at SO that said I would need to use browserify, but I can't find any doc (or example) on how to use it together with babel in karma. Does anyone know to configure this properly?
I fixed it using browserify instead of babel, and using a babelify transform
preprocessors: {
'./src/js/es6_modules/*.js': ['browserify'],
'./test/unit/*.spec.js': ['browserify']
},
browserify: {
debug: true,
"transform": [
[
"babelify",
{
presets: ["es2015"]
}
]
]
},

Exported TypeScript Class not included in WebPack bundle if not used directly

I'm converting a javascript project with Angular 1.x to WebPack and TypeScript (using ts-loader). I got it mostly working, but I'm running into trouble when ts-loader seems to be optimizing my scripts out of the bundle when the exports are not directly used.
Here's a sample project demonstrating the issue (npm install, webpack, then load index.html and watch the console).
https://github.com/bbottema/webpack-typescript
The logging from ClassA is showing up, but angular is reporting ClassB missing (provider). If you look in bundle.js you'll notice ClassB missing entirely. The difference is ClassA begin use directly after importing, and ClassB is only referenced by type for compilation.
Is it a bug, or is there a way to force ClassB to be included? Or am I going about it wrong? Angular 2 would probably solve this issue, but that's a step too large right now.
Relevant scripts from the project above:
package.json
{
"devDependencies": {
"typescript": "^1.7.5",
"ts-loader": "^0.8.1"
},
"dependencies": {
"angular": "1.4.9"
}
}
webpack.config.js
var path = require('path');
module.exports = {
entry: {
app: './src/entry.ts'
},
output: {
filename: './dist/bundle.js'
},
resolve: {
root: [
path.resolve('./src/my_modules'),
path.resolve('node_modules')
],
extensions: ['', '.ts', '.js']
},
module: {
loaders: [{
test: /\.tsx?$/,
loader: 'ts-loader'
}]
}
};
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "commonjs"
},
"exclude": [
"node_modules"
]
}
index.html
<!doctype html>
<html ng-app="myApp">
<body>
<script src="dist/bundle.js"></script>
</body>
</html>
entry.js
declare var require: any;
'use strict';
import ClassA = require('ClassA');
import ClassB = require('ClassB');
var a:ClassA = new ClassA(); // direct use, this works
var angular = require('angular');
angular.module('myApp', []).
// this compiles as it should, but in runtime the provider will not be packaged and angular will throw an error
run(function(myProvider: ClassB) {
}
);
ClassA.ts
// this line will be logged just fine
console.log('ClassA.ts: if you see this, then ClassA.ts was packaged properly');
class ClassA {
}
export = ClassA;
ClassB.ts
declare var require: any;
// this line is never logged
console.log('ClassB.ts: if you see this, then ClassB.ts was packaged properly');
class ClassB {
}
var angular = require(angular);
angular.module('myApp').service(new ClassB());
export = ClassB;
Turns out you have to signal WebPack to explicitly include a module by adding an extra require call without import statement.
I'm not ready to mangle my .ts files by adding duplicate imports, so I made a generic solution for that using the preprocessor loader:
{
"line": false,
"file": true,
"callbacks": {
"fileName": "all",
"scope": "line",
"callback": "(function fixTs(line, fileName, lineNumber) { return line.replace(/^(import.*(require\\(.*?\\)))/g, '$2;$1'); })"
}]
}
As a proof of concept, this regex version is very limited it only support the following format:
import ClassA = require('ClassA');
// becomes
require('ClassA');import ClassA = require('ClassA');
But it works for me. Similarly, I'm adding the require shim:
{
"fileName": "all",
"scope": "source",
"callback": "(function fixTs(source, fileName) { return 'declare var require: any;' + source; })"
}
I made a sample project with this solution.

Categories