Resolve .jsx extensions on imports in node - node.js

I have a CRA project in which I've added SSR.
It's supper dummy, it has this structure:
|- App.js
|- Header
|- Header.jsx
|- Header.scss
The App just contains the Header, which is imported without specifying the extension.
import React, { Component } from 'react';
import './App.css';
import Header from './Header/Header';
class App extends Component {
render() {
return (
<Header />
);
}
}
export default App;
With npm start all runs successfully. If I compile the code and run it with node instead, it breaks with this error Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
There seem to be a problem when resolving imports without an extension. It finds the .scss file instead of the .jsx. Specifying the extension on import or removing conlicting files (i.e. Header.scss) solves the issue.
However, I would like to keep using imports without extension, as I normally do in CRA.
I don't know how to specify this on my settings.
I've just pushed this simple example so you can run it yourself: https://github.com/dnaranjo89/resolve_extensions_ssr

Related

The example tabulator for angular does not work: unrecognized type library

The following error occurs after installing tabulator with the "npm install tabulator-tables - save" command:
Error TS2306 (TS) The file '../ClientApp/node_modules/#types/tabulator-tables/index.d.ts' is not a module.
The error is reported on the import statement:
import {Tabulator} from 'tabulator-tables';
I'm trying to use "tabulator" in an Angular 5.2.5 project created with Visual Studio 2019
import { Component, Input, OnChanges, SimpleChanges } from '#angular/core';
import Tabulator from 'tabulator-tables'; <-- ERROR !!!!!!
/**
* This is a wrapper class for the tabulator JS library.
* For more info see http://tabulator.info
*/
#Component({
selector: 'app-tabulator-table',
templateUrl: './tabulator-table.component.html',
styleUrls: ['./tabulator-table.component.css']
})
export class TabulatorTableComponent implements OnChanges {
Just add:
export default Tabulator;
To the top of the #types/tabulator-tables/index.d.ts file.
There is some issues with adding types for tabulator, this is because type annotations not being exported, but there is a way to use them.
After installation of types for tabulator (npm install --save #types/tabulator-tables), you should open (or create it, if it's not exists) file index.d.ts inside directory src, and copy following code into it:
declare module 'tabulator-tables' {
export = Tabulator;
}
You need to ensure that you have "allowSyntheticDefaultImports": true inside compilerOptions of file tsconfig.json or tsconfig.app.json (depends on your project), and tsconfig.spec.ts (it needs for unit testing).
Very important to unload and start over ng serve after editing of tsconfig.
After that all typings should work. Just in case I created simple Angular example, hope this helps.
Most answers modify the #types/tabulator-tables library, which has been rejecting pull requests for years in the name of compatibility. I found a less invasive workaround:
Allow TypeScript to get Type definitions in src/ (or use your own path instead of src everywhere below):
tsconfig.json (as of TS 4.3, but typeRoots has existed for years):
{
"compilerOptions": {
"typeRoots": ["src/#types", "node_modules/#types"], /* src/#types to override tabulator-tables definition. */
}
}
Create src/tabulator-tables.d.ts, with the same contents that people normally add the top of #types/tabulator-tables/src/index.d.ts:. Not src/#types, and the name must match [library-name].d.ts so that the Tabulator class is defined there.
src/tabulator-tables.d.ts:
declare module "tabulator-tables" {
export = Tabulator;
}
npm install --save #types/tabulator-tables
Add a file tabulator-tables.d.ts in /src/app
declare module "tabulator-tables" { export default Tabulator; }
Important error when use export = Tabulator;

NodeJS How to import JS file into TypeScript

I'm new with TypeScript. I'm currently learning NodeJS Loopback 4 framework which use Typescript language. And my question is how to import some function, class which has been exported in JS file into my TS file. After search several way but it still doesn't work with me.
Here's example:
// /src/index.ts
import {plus} from './lib/test';
console.log(plus(1,2));
// /src/lib/test.js
export function plus(x, y) {
return x + y;
}
I also try using definition typescript like this
// /src/lib/test.d.ts
export declare function plus(x: number, y: number): number;
But still got error when import this function in index.ts file
Error: Cannot find module './lib/test'
at Function.Module._resolveFilename (module.js:543:15)
It looks like the tsconfig.json doesn't have 'allowJs' enabled because it exports declarations.
Is there a reason you are not wanting this to be a typescript file? If you change test.js to test.ts, by making it a .ts should allow it to be recognised in your index file.
UPDATE
Full chat history to get to this point can be found here.
Repository used to test found here
OK so easy solution as #maaz-syed-adeeb mentions will work:
import { path } from './lib/test.js'
The reason the extension is important is because the definition file takes priority over a javascript file in a typescript environment. That is why the module import was blowing up.
To avoid specifying the .js extension you can also setup your directory structure like this:
src
|- index.ts
|- lib
|- test.js
|- test.d.ts
|- index.[js|ts]
in ./lib/index file export all from test:
//./src/lib/index.[js|ts]
export * from './test'
and then import all from lib:
// ./src/index.ts
import { path } from './lib'
// or
import { path } from './lib/test.js'
If you are using a blend of javascript and typescript (say you are moving over to typescript with an existing code base), you will need to update your tsconfig.json to include so you don't get the warnings in your IDE:
{
"compilerOptions": {
"allowJs": true,
"declaration": false
}
}
This is so your javascript files will be transpiled to your destination directory along with the typescript files.

node_modules import from a directory inside what is specified in "main" (package.json)?

Is it possible to import from something other that what "main" points to?
In my library that is installed into node_modules, I have the main set to
lib/index.js
so (using es2015 imports - source was ts compiled js), I can do
import { FunctionA, FunctionB } from 'MyTestLibrary';
This works because these functions are exported inside of index.js under libs.
I also have an index inside a directory which exports functionC and functionD, the structure is here
/lib/otherdir/index.js
so if I do an import like so
import { FunctionC, FunctionD } from 'MyTestLibrary/otherdir';
my IDE does not complain but running the application I get a
Cannot find module MyTestLibrary/otherdir
Everything is exported as it should be.
You can access the directory directly like this:
import { FunctionC, FunctionD } from 'MyTestLibrary/lib/otherdir'

next.js and webpack resolve.modules

I am building a React app using next.js, and I am playing around with the webpack config, in the next.config.js file.
Specifically, I'd like to have nicer imports using webpack's resolve.modules config.
However, when I add the following line in the next.config.js file :
config.resolve.modules
.concat(['styles','static','components','imports'])
and then
import FooBar from 'components/index/FooBar", for example in a pages/index.js file, it still won't work. FooBar is not found.
The component exists, and the import works fine if I use a relative path. However I'd like to have nicer imports, and I know it is possible with webpack (see react-boilerplate for example).
Am I doing something wrong with webpack ? Maybe it's a real bug ?
Check the NextJS example with-absolute-imports
const path = require('path')
module.exports = {
webpack (config, options) {
config.resolve.alias['components'] = path.join(__dirname, 'components')
return config
}
}
Alternatively, should work by adding this to next.config.js file:
config.resolve.modules.push(path.resolve('./'));
(and it doesn't require any babel plugin)
resolve.modules will look into the directories you configured for the modules you import. So when import components/index/FooBar it will look in:
styles/components/index/FooBar
static/components/index/FooBar
components/components/index/FooBar
imports/components/index/FooBar
A relative path looks further, but that's not relevant here and the path remains the same, just climbing up the directory tree (see resolve.modules).
Presumably none of these paths match your component. To get component/index/FooBar you need to import just index/FooBar.
import FooBar from 'index/FooBar';

Typescript AMD external module loading, angular is not defined

I know that there are some similar questions on this topic already, but somehow none of them helped.
I want to use angular.js in a project which uses requirejs and Typescript.
I have a module, where I use angular to create a service module:
/// <reference path="../../../typings/angularjs/angular.d.ts" />
...
var services = angular.module('services', []);
...
export = services;
This code compiles withouth error, but in the created js file, there is angular.js dependency is not there:
define(["require", "exports"], function(require, exports) {
...
}
And when I run the application, the browser complains: Uncaught ReferenceError: angular is not defined
My guess is, that somehow I should import the angular besides referencing it, but none of the path's I tried works.
Here is my require.js configuration, in case it is needed:
require.config({
paths: {
angular: '../lib/angular/angular',
...
},
shim: {
angular : {exports : 'angular'},
...
}
)}
Can u help me, what is missing here?
Thanks.
When you use a reference comment:
/// <reference path="../../../typings/angularjs/angular.d.ts" />
You are telling the compiler "I will ensure this dependency is available at runtime".
If you want the module to be loaded, you need to use an import instead...
import angular = require('angular');
The zero-set-up way of doing this is to place the angular.d.ts file next to the actual angular.js file, so the path you specify in the import statement is the same either way - otherwise, use your require config to shimmy the path.
Have you tried adding the following to the top of your file
/// <amd-dependency path="angular"/>
This should make ts compiler add angular to the define list.

Resources