"The keyword 'interface' is reserved" when using LernaJS - javascript

Can not seem to run NextJs in development (next dev) when using Lerna. I can get other files to pull in just fine (e.g images) but it doens't seem to process TS on the fly using this method. Anybody have any thoughts on this?
ModuleParseError: Module parse failed: The keyword 'interface' is reserved (3:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| import React from "react";
|
> interface Props {
| name: string;
| }
packages/shared/components/Example.tsx
import React from "react";
interface Props {
name: string;
}
export const Example = ({ name }: Props) => {
return <div>Name: {name}</div>;
};
packages/web/pages/index.tsx
import { Example } from "shared/components/Example";

This is something that is being worked on/considered and supposedly might actually work already in some cases, but I was not able to make baseUrl work for me.
In the mean time per Jacob Rask's suggestion you should use next-transpile-modules. I was struggling with this issue myself, and this finally worked!

Related

Typescript not compiling enum in symlinked folder

EDIT: Unfortunately this seems like a known issue that cannot be solved without messing with create-react-app, although I could be wrong :( https://github.com/facebook/create-react-app/issues/3547#issuecomment-593764097
I am working on a react project using typescript and firebase functions, with my firebase functions project folder inside the project folder for the react app. As there are lots of enums and interfaces that I want to keep consistent between my frontend (the react app) and my backend (the firebase functions), I use a symlink to share a folder containing files common between these two projects. This works fine with interfaces, but causes errors when I try to use an enum exported from this symlinked folder:
ERROR in ./functions/src/shared-types/roles.ts 3:0
Module parse failed: The keyword 'enum' is reserved (3:0)
File was processed with these loaders:
* ./node_modules/#pmmmwh/react-refresh-webpack-plugin/loader/index.js
* ./node_modules/source-map-loader/dist/cjs.js
You may need an additional loader to handle the result of these loaders.
| __webpack_require__.$Refresh$.runtime = require('/Users/joel/my-project/node_modules/react-refresh/runtime.js');
|
> enum Roles {
| Admin = 'Admin',
| Access = 'Access',
Repro
Starting from a fresh create-react-app with typescript support, add a folder called shared-types at the same level as src and put a file in it called MyEnum.ts:
// shared-types/MyEnum.ts
enum MyEnum {
Foo = "foo",
Bar = "bar"
}
export default MyEnum;
Then, make a symlink between that folder and another one also called shared-types inside src:
$ ln -s /path/to/project/shared-types /path/to/project/src/shared-types
Then, import and use MyEnum in App.tsx:
// src/App.tsx
import React from 'react';
import './App.css';
import MyEnum from "./shared-types/MyEnum";
function App() {
return (
<div className="App">
<h1>{MyEnum.Bar}</h1>
</div>
);
}
export default App;
Finally, just run npm start:
ERROR in ./shared-types/MyEnum.ts 3:0
Module parse failed: The keyword 'enum' is reserved (3:0)
File was processed with these loaders:
* ./node_modules/#pmmmwh/react-refresh-webpack-plugin/loader/index.js
* ./node_modules/source-map-loader/dist/cjs.js
You may need an additional loader to handle the result of these loaders.
| __webpack_require__.$Refresh$.runtime = require('/Users/joel/repro/node_modules/react-refresh/runtime.js');
|
> enum MyEnum {
| Foo = 'foo',
| Bar = 'bar',
Things that aren't causing it
It's not that typescript is ignoring the shared-types folder, as everything compiles fine if you add an interface to that folder and use it in App.tsx. Plus, running tsc --listFilesOnly will return a list including /path/to/project/src/shared-types/MyEnum.tsc.
It's not that my version of typescript doesn't support enums or that enums are disabled, as everything works fine if you add an enum to App.tsx itself.
Thanks in advance for the help! And feel free to suggest better ways of sharing files between these two projects in the comments if there are any!
It turns out that create-react-app doesn't support symlinks under src at all! The fact that the interface stuff worked at all seems to be a fluke.
https://github.com/facebook/create-react-app/issues/3547
This seems to have been a known issue for four years, but there is no blessed solution to it yet. 🫤

Testing components with Jest using css modules

I'm working on a project in React using CSS modules for stylings.
I would like to test a component using Jest and React Testing Library, but when I try to render it I get this error:
Test suite failed to run
cssModule has no keys
3 | export default (style: {[key: string]: string}):any => {
4 | block.setSettings({throwOnError: true, modifierDelimiter: '--'});
> 5 | return block(style);
| ^
6 | };
7 |
block is an override from a function exported by the library bem-css-modules which I use for keeping BEM nomenclature while implementing css-modules.
I have managed to log the exact style (imported by the .module.scss file) which is passed to this function, and I have found that it is actually empty when rendering the component with react-testing-library:
import React from 'react';
import MyIcon from 'shared/components/myIcon/myIcon.component';
import styles from './myButton.module.scss';
import block from 'utils/bemCssModulesConfig';
console.log('styles', styles) // this logs "styles, {}" so it's empty object
const bem = block(styles);
This is the moduleNameMapper I am currently using:
"moduleNameMapper": {
"^.+\\.(scss|sass|css|less)$": "identity-obj-proxy"
}
I have already tryed using custom proxies copied from the internet or using external libraries as moduleNameMappers.

Exporting from one library if web, another library if native in React Native

So I am trying to use Victory Charts (https://formidable.com/open-source/victory) and would prefer to not just use a webview, as they've got a native implementation.
However, I am trying to use the library with React Native Web, and it does not work at all, I get the following error:
/Users/myname/Desktop/Projects/myproject/Frontend/Expo/node_modules/victory-native/lib/components/victory-axis.js 10:22
Module parse failed: Unexpected token (10:22)
You may need an appropriate loader to handle this file type.
|
| export default class extends VictoryAxis {
> static defaultProps = Object.assign({}, VictoryAxis.defaultProps, {
| axisComponent: <LineSegment/>,
| axisLabelComponent: <VictoryLabel/>,
My guess is that I'll need to use two "wrapper" files, Victory.js and Victory.web.js for importing.
Here is my Victory.web.js file so far:
Victory = require('victory');
export default Victory;
This does not work.
I have also tried:
import { VictoryPie } from 'victory';
export VictoryPie;
Which gives me the error:
/Users/myname/Desktop/Projects/myproject/Frontend/Expo/src/components/utility/Victory.web.js
SyntaxError: /Users/myname/Desktop/Projects/myproject/Frontend/Expo/src/components/utility/Victory.web.js: Unexpected token (3:17)
1 | import { VictoryPie } from 'victory';
2 |
> 3 | export VictoryPie;
I just want to be able to use this library on both React Native and React Native Web without it throwing errors. Is there any way to do so?
Not sure if this is the best way to do it, but this way worked for me:
export const VictoryPie = require('victory').VictoryPie;

Pulling in types for use in a .d.ts file with declare module without making it a module file

I am attempting to write a type declaration for an NPM package (or more specifically an untyped directory within a package) my project depends on.
The package itself is react-big-calendar and it doesn't bundle its own types, however there is #types/react-big-calendar which provides types for the main package, but not for the react-big-calendar/lib/addons/dragAndDrop "sub-package" it has in itself.
The above gets me working import BigCalendar from 'react-big-calendar' which is great, and I want to also get working import withDragAndDrop from 'react-big-calendar/lib/addons/dragAndDrop' so I figured I'd just declare module my way there.
I cannot place the declare module statement in any TSX file, because it has to be in its own file which is not an ES module, but it also cannot be an import+export free TS file, because I am also using CRA which enforces isolatedModules and so disallows non-module TS/X files.
I can and should place it in a .d.ts file, like this:
declare module 'react-big-calendar/lib/addons/dragAndDrop' {
function withDragAndDrop(calendar: any): any;
export = withDragAndDrop;
}
This looks fine, but is not much of an improvement typing-wise. The function I am looking to type basically takes a React component and returns it with some extra props. But even to just type is as a function which takes the specific BigCalendar component and returns it is a problem, because I cannot use an import statement (to pull in the component type) in the d.ts file. If I do, it turns into a module file and that breaks the declare module statement.
I am looking for something like this:
declare module 'react-big-calendar/lib/addons/dragAndDrop' {
function withDragAndDrop(calendar: BigCalendar): typeof BigCalendar & {
props: {
extraProp1: string;
// …
extraPropN: string;
}
};
export = withDragAndDrop;
}
With that I should be able to use the HOC like this: const DragAndDropCalendar = withDragAndDrop(BigCalendar); followed by <DragAndDropCalendar originalProp={value} extraProp1={value} />.
The thing that is missing is pulling in the types to the .d.ts file in a way which doesn't turn it into a module breaking the declare module statement stripping me of types, bringing me to square one again.
What options do I have there? I tried to use require but that returns any and I couldn't figure out if <reference is the right tool here or not.
I figured out how to import the original component types (React Big Calendar in this case, but the solution is generic) in the typings (which in this case are for the RBC drag and drop addon).
withDragAndDrop.d.ts:
declare module 'react-big-calendar/lib/addons/dragAndDrop' {
import BigCalendar, { BigCalendarProps, Event } from 'react-big-calendar';
type withDragAndDropProps<TEvent> = {
onEventDrop: (args: { event: TEvent, start: stringOrDate, end: stringOrDate, allDay: boolean }) => void;
onEventResize: (args: { event: TEvent, start: stringOrDate, end: stringOrDate, allDay: boolean }) => void;
};
declare class DragAndDropCalendar<TEvent extends Event = Event, TResource extends object = object>
extends React.Component<BigCalendarProps<TEvent, TResource> & withDragAndDropProps<TEvent>>, {}
function withDragAndDrop(calendar: typeof BigCalendar): typeof DragAndDropCalendar;
export = withDragAndDrop;
};
Usage:
import withDragAndDrop from 'react-big-calendar/lib/addons/dragAndDrop';
import "react-big-calendar/lib/addons/dragAndDrop/styles.css";
const DragAndDropCalendar = withDragAndDrop(BigCalendar);
// TSX:
<DragAndDropCalendar<MyEvent> … onEventDrop onEventResize />

Dynamically import all component sub directories without using full path

I am using Next.js for React. I like how Arc (other react boilerplate) dynamically imports components without requiring developer to specify path.
import { Input, Label, Field, HomePage, PageTemplate } from 'components'
Folder structure may look somewhat like this:
components
|_ index.js
|_ atoms
|_ Input
|__ index.js
|_ molecules
|_ organisms
|_ templates
and I'd like to import it like:
import { Input } from 'components'
Code that is used for dynamic import: components/index.js
const req = require.context('.', true, /\.\/[^/]+\/[^/]+\/index\.js$/)
req.keys().forEach((key) => {
const componentName = key.replace(/^.+\/([^/]+)\/index\.js/, '$1')
module.exports[componentName] = req(key).default
})
However it doesn't work. The error I get:
Module not found: Error: Cannot resolve module 'components'...
The issue is that require.context is not available on serverside.
I suppose I need to specify this path to be imported like this in loader config. Can anybody share a hint on how is this done properly?
I don't think there is a simple and reliable way to do what you want with Next.js
The standard/"correct" answer is to use a relative path to import your local components. It is a bit more boilerplate, but I think you'll ultimately find it to be less work than fighting with Next.js to make it do things the Arc way.
To followup on #Robsonsjre's suggestion:
Why dont you make your /components/index.js export all components in the folder?
I think there is an implied "you write that index.js file". For your example, it would look something like this:
export {default as Input } from './atoms/Input';
export {default as Foo } from './molecules/Foo';
// etc
The catch is that you'd have to remember to update this file every time you add or remove a component. It's probably possible to automate that, but I'm not aware of any system to do it off the top of my head.
This way is not exactly what you want, but works similar, well for performance because its only object pointers to imported components
//Input.js
class Input extends Component {
render() {
return <div>'input'</div>
}
}
export default Input
//index.js
export { default as Input } from './Input/Input'
//otherComponent.js
import { Input } from './components' //path to folder components

Categories