How to tune babel loader to properly import a module named macro.js when using CRA - javascript

I'm using a library vtk.js. VTK has a special design of classes (https://kitware.github.io/vtk-js/docs/develop_class.html). When I write a class I need to import macro.js module which exposes several base methods such as getters/setters/newInstance etc (https://github.com/Kitware/vtk-js/blob/master/Sources/macro.js).
Looks like CRA uses some special loader for macro.js files. I get an error when trying to import such a file (SyntaxError: Cannot use import statement outside a module). If I copy an original file macro.js from #kitware/vtk.js to my local source folder I still get an error. Even if I remove all the contents of macro.js file I get an error (The macro imported from "../macro" must be wrapped in "createMacro" which you can get from "babel-plugin-macros". Please refer to the documentation to see how to do this properly: https://github.com/kentcdodds/babel-plugin-macros/blob/master/other/docs/author.md#writing-a-macro). However, when I rename macro.js to macro2.js the error is gone.
Is there some way how can I disable this macro loader?

Related

How to include a global file type declaration in a TypeScript (Node.js) package

I'm working on a package that I am planning to publish publicly on npmjs. Let's call it the "text package".
I would like that by default when installing that package, you can import .txt files directly and get the correct type (out of the box), like this:
import text from './file.txt'
The text variable would be of type string because the package would have defined its type, using something like this (in a global.d.ts):
declare module '*.txt' {
export const text: string;
export default text;
}
If I include that global.d.ts in my package, and that I import something from this package, then I will automatically get the correct type when importing a .txt file.
But the problem is sometimes I would just need to import a .txt file without importing anything from the "text package", which is why I was wondering if there is some sort of way, as you install a package to install a global type that does not require to import anything else for the type to apply.
In other words, as soon as you install my "txt package" the declare module '*.txt' would apply to my entire project out of the box.
Is there even a way to do this, or whoever installs my package would have to declare their own global type (e.g., declarations.d.ts) to be able to import .txt files globally?
I know that even if the import type works, it will still require Webpack or another bundler to really work but this question is just about the type.
The short answer is:
TypeScript does not support Global types without importing the file referring to the type.
More details:
One example that I found doing this was Next.js - when creating a TypeScript app using npx create-next-app#latest --typescript you can start importing *.css files (for example) and get the correct type.
Where I got confused is that I originally thought that the type was coming from the next-env.d.ts but even when I deleted the file, *.css import was still working in Visual Studio code. But the reason it was, is because a file in the pages directory were importing Next.js' index.d.ts file.
Basically, in Visual Studio Code, as soon as your import a type somewhere in your project, if it's global, it will be accessible everywhere.
Workaround
So what can be done with the current TypeScript capabilities? To support new file types, you will need a file loader such as Webpack. The logical thing to do would be to add a reference to the file type declaration in the file loader itself. This way, as soon as you configure your file loader to be able to import the file, you will inherit the type:
create a txt.d.ts in our package's source directory (e.g. src) - you can use any name for the file, it's not important
if you are using eslint, add an entry to ignore the type file (e.g. 'src/*.d.ts' in your ignorePatterns option
Since you are adding a d.ts file in your source that is not managed by tsc, you need to add a script that will perform the following actions:
Copy txt.d.ts in the target directory of the compiled files for your package
Add this line at the top of your package's file loader (e.g. loader/index.d.ts: /// <reference types="../txt" />\r\n - this will link the declaration file back into your package. Note that you can add this reference to any file of your package.
This workaround will only work once you import the file referencing back to the declaration - this is the only way TypeScript can be made aware that this type exists (see https://github.com/microsoft/TypeScript/issues/49124).
Another alternative could also be to add manual steps (in a readme file) to add a global type declaration file.
to bundle global types, do the following. form typescript
specify default typings directory at typeRoots. .e.g "typeRoots": ["./src/types"].
create a file /src/types/global.d.ts in the specified directory
declare your types in the file inside declare global {} and make sure to have export {} if you don't already export anything.

import() in ts is not dynamic? what's the cause?

According to MDN, import() is a function-like dynamic method. However, I found it not dynamic in my ts project.
Say I have an appleShare.json:
{
price: 123
}
And then, there's an index.ts:
console.log("update the price to 456...")
// manually modify the json file content making price 456
let currentPrice = await import("./appleShare.json").then(obj=obj.price)
console.log(currentPrice)
I ran index.ts directly in vs-code, the result in console:
update the price to 456...
123
I expect 456, but got 123. From my limited knowledge I guess there are two possible reasons:
I have a misunderstanding in import() and dynamic importing.
My understanding is right but vs-code compiled all the code to js before executing them. So, I will never get the newly modified price.
I want to ask, what's exactly the cause of the issue, and how to resolve it?
The "dynamic" import() has the following different behaviors from the regular import which is often referred to as the "static" import.
You can construct a module filename in code and can then load that module from the filename you built. You cannot dynamically build module filenames with the regular import. Filenames for the regular import must be statically specified so they are known by anyone who parses the file, but does not run the code in it. This static declaration enables code analysis for things like tree-shaking and bundling. The dynamic import cannot be used as effectively with features like that.
The import() can happen anywhere in your code (not only at the top of your module). The regular import cannot be just anywhere in your code. In this sense, it is "dynamically" loaded upon demand, not only at the beginning of the module.
A dynamic import() statement can be used to load an ESM module into a CommonJS module. The regular import statement cannot be used in a CommonJS Module at all.
Modules, even dynamically loaded ones are cached. Once they are loaded, subsequent import() statements using the same filename just load the module from the cache, they do not re-read the file. That's why your subsequent import() is not picking up the modified JSON.
If you want to re-read the file, then don't use import - use something like fs.promises.readFile() and then parse the JSON. This will read a fresh copy of the data each time you call it.

React added to existing webpage does not render components from multiple files

I want to add some functionality to my existing website with React.
I followed this tutorial. I came to a point where I wanted to separate classes from single js file to one for each class.
Then I used
import InputField from './InputField';
Which gave me this error:
Uncaught SyntaxError: Unexpected token import
When I imported my classes the same way in an example which was created via this tutorial, it worked perfectly.
I also tried with require(), but that gave me an error message saying that require() is not defined.
So how to divide classes from single file to multiple files on an existing website that has React as an addition? Am I forced to write all code in one file, if I just add React to website? I suspect, that it does not compile as it somehow should. (I am just starting with React)
You either have to use native ES modules or use a bundler like webpack or Rollup

Text to speech for Angular apps - "allowJs is not set" issue

I'm having trouble integrating this speech-to-text package into my Angular app. I've added the import statement:
import spoken from "../../../node_modules/spoken/build/spoken.js";
My project is able to find the spoken.js module but it tells me that "allows is not set".
If I set that value to true in my tsconfig.json file, I then get multiple .js related errors in other files, and I'm unable to build the project. Has anyone encountered something like
this before?
If you want to import the module at runtime but not check it with TypeScript, try removing the .js extension from the import path.
One way would also be to disable type checks for JS files via "checkJs": false in your tsconfig.json.
Or you could also include the file in scripts array in angular.json file and in your controller, just declare that variable:
declare const spoken: any;
(feel free to use something more specific instead of any :])

What is the Purpose of Import Modules Without Export or Consumption within File

I have seen this following pattern within index.js file and I am left scratching my head. What would be the purpose of the following code below, considering:
The imported module is not being consumed within this module/file
There is no export of the imported module
The following code is all there is within the index.js file (yes, just one line):
import '../modules/index.js';
To elaborate, the index.js file is importing from '../modules/index.js'. That is it, there is no other code within the file whatsoever.
The only reason I'm aware of where one might want to do an import without utilizing anything imported is when the imported file has some form of side effect that happens simply by evaluating the code, such as defining a global variable. In this case, simply importing the code will cause that code to be run. If you can indicate more about the contents of modules/index.js we might be able to get to a more defined answer of what's happening in this case.

Categories

Resources