Using TypeScript aliases in monorepo - vite

I am trying to configure monorepo for my Vue projects. Common practice in Vue is to have '#' alias which points to src folder in current project. I have this structure:
apps/
vue-app
src
components
Main.vue
libs/
vue-lib
src
components
ComponentA.vue
ComponentB.vue
ComponentA looks like this:
// some template
// some styles
<script>
import ComponentB from '#/components/ComponentB.vue'
// some logic
</script>
And Main.vue like this:
<script>
import ComponentA from 'libs/vue-lub/ComponentA.vue'
// some more logic
</script>
Both projects has their own tsconfig.json:
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#/*": ["./src/*"]
}
},
So, the problem here is quire tricky: ComponentA trying to resolve the import of the ComponentB using tsconfig from another project, so it obviously fails (there is no ComponentB in vue-app).
I already tried to create shared tsconfig at the root of the monorepo and use it via "extends", but no luck, even though it looked like it should've worked:
"baseUrl": ".",
"paths": {
"#vue-lib/*": ["./libs/vue-lib/src/*"]
}
ComponentA.vue:
import ComponentB from '#vue-lib/components/ComponentB.vue'
VSCode + Volar extention can resolve this path, but Vite can't. I think I should configure it manually too, but maybe there is a better way to do this? Also, despite being used in template section, Volar doesn't highlight the ComponentB as used when I import it like this.

Related

Persistent undefined error in typescript import export

There's already a LOT of questions about typescript in multiple files.. for instance, this one,
Typescript import/export
Interesting question and answer, I simplified and tested it, see below.. but whatever I try, I still get
Uncaught TypeError: Cannot read properties of undefined (reading 'A')
.. as does any other example of import/export in TypeScript I found online. Whatever I do, whatever object I try export (class, function, const) with or without using a module: I get the same error.
Maybe there is something wrong in my NPM/TSC/React configuration ? Should I change e.g. tsconfig.js when i want to use more than one typescript file in a project ? I'm lost, what do I miss ?
tsconfig.json
{ // TypeScript configuration file: provides options to the TypeScript
// compiler (tsc) and makes VSCode recognize this folder as a TS project,
// enabling the VSCode build tasks "tsc: build" and "tsc: watch".
"compilerOptions": {
"target": "es5", // Compatible with older browsers
"module": "umd", // Compatible with both Node.js and browser
"moduleResolution": "node", // Tell tsc to look in node_modules for modules
"sourceMap": true, // Creates *.js.map files
"jsx": "react", // Causes inline XML (JSX code) to be expanded
"strict": true, // Strict types, eg. prohibits `var x=0; x=null`
"alwaysStrict": true // Enable JavaScript's "use strict" mode
},
"include": ["**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}
first.tsx
const A ={
val: 'A'
}
export { A }
app.tsx
import { A } from "./first";
// ... other code
function reportPerson()
{
console.log(A);
}
.. Both files translate to .js with TSC, but A is reported by the Google Chrome console as undefined,
Both tsx files are in the same directory, TSC converts them both to JS without any issue.
What's going on ?
Thanks everyone for the advice (I didn't solve the above minimal example either..)
In order to properly link my stuff together, I've now put Parcel 2 to work,
https://www.npmjs.com/package/parcel
npm i parcel
This is basically a bundler, that allows separate ts files to be concatenated after they are compiled to Javascript and it will put everything in a \dist directory,
parcel build src/index.html
Based on a small react example, I put my first "modulized" little app in TypeScript to work. Then, with the help of expert advise, I proceeded with twgl.js, which is a great toolkit for Webgl2.
npm install twgl.js
This javascript library even has sub-modules.. and everything links fine now, I can access (all of?) twgl with
import * as twgl from "./twgl-full.js";

How to use TypeScript import statement instead of <reference path...> in a Web application (ASP.NET Core)?

Context
I have (had) a working version typescript Hello World in my Web application (ASP.NET Core)
Using typscript compiler via NuGet package "Microsoft.TypeScript.MSBuild" Version="4.4.2" and tsconfig.json. (see below)
I've wanted to use a 3rd party lib, and successfully added "#types/lodash": "^4.14.175" via packages.json (see below)
I've added /// <reference path="../node_modules/#types/lodash/index.d.ts"/> (see below)
All works, but the line /// <reference path="..." is underlined green and ESLint says
Do not use triple slash reference for index.d.ts, use import instead.
OK, I am going to use export/import later anyway, so I've edited the triple slash reference line to be a comment, and added the line import * as _ from "lodash" which compiles fine, but when running in chrome causes runtime error:
Cannot use import statement outside a module
so I changed my <script tag to the following: <script type="module" src="~/js/app.js"></script>
However this causes the following chrome runtime error:
Failed to resolve module specifier "lodash". Relative references must start with either "/", "./", or "../".
Question
Now I am stuck, and with my very limited knowledge somehow I guess some step/transformation is missing, but what? I've tried to include some path in my .ts file's import statement (causing compile errors). Compile time I would like to use the working import referring to the #typings, but runtime the lodash.js is coming from cdn, the two nothing to do with each other...
app.ts
// commented out / <reference path="../node_modules/#types/lodash/index.d.ts"/>
import * as _ from "lodash"
console.log(_.camelCase("Hello"));
emitted app.js
// commented out / <reference path="../node_modules/#types/lodash/index.d.ts"/>
import * as _ from "lodash";
console.log(_.camelCase("Hello"));
//# sourceMappingURL=app.js.map
index.html
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.21/lodash.min.js"></script>
<script type="module" src="~/js/app.js"></script>
tsconfig.json
{
"compileOnSave": true,
"compilerOptions": {
"noImplicitAny": false,
"noEmitOnError": true,
"removeComments": false,
"sourceMap": true,
"target": "es6",
"module": "ES6",
"outDir": "wwwroot/js"
},
"exclude": [
"node_modules",
"wwwroot"
]
}
packages.json
{
"version": "1.0.0",
"name": "asp.net",
"private": true,
"devDependencies": {
"#types/lodash": "^4.14.175"
}
}
Try to modify the tsconfig.json
// tsconfig.json
{
...
#types: ["node_modules/"] // or typings
}
Or use ES5 require
const _ = require("lodash");
Found the following possible solutions
The required files need to be copied over to wwwroot folder, where they can be accessed when the application runs.
For this you'd need either use the bundler to bundle the files together (should be in default ASP.NET Core project template) or use task runners such as Gulp or Grunt to run tasks on build/publishing, which does that for you. See ASP.NET Core Docs on Gulp examples.
Original answer: https://stackoverflow.com/a/43513137/13747848
Note: Please give credit to original respondent!
Edit
For the error
Uncaught TypeError: Failed to resolve module specifier "lodash". Relative references must start with either "/", "./", or "../".
As of 2021, please consider the following statement by Márton Salomváry (Jan 2018):
Unfortunately even most libraries authored or published in ES6 module format will not work because they target transpilers and rely on the Node.js ecosystem. Why is that a problem? Using bare module paths like import _ from 'lodash' is currently invalid, browsers don’t know what to do with them.
And also the statement by Jake Archibald (May 2017):
"Bare" import specifiers aren't currently supported.
Valid module specifiers must match one of the following:
A full non-relative URL.
Starts with /.
Starts with ./.
Starts with ../.
And javascript.info:
In the browser, import must get either a relative or absolute URL. Modules without any path are called “bare” modules. Such modules are not allowed in import.
Certain environments, like Node.js or bundle tools allow bare modules, without any path, as they have their own ways for finding modules and hooks to fine-tune them. But browsers do not support bare modules yet.
Bundlers facilitate the use of "Bare Imports" which is not supported by the browser yet. Unless you bundle your code, I recommend using the solution proposed by #Asler. Besides, a lot of work is currently being done to study the implementation of "Bare Imports" in the browser, please follow this link if you want to monitor the overall progress.
Original answer: https://stackoverflow.com/a/66484496/13747848
Note: Please give credit to original respondent!
If you don't wish to use any bundling tools, you will need to provide a path to the lodash folder within node_modules, relative to the JavaScript file that you have the import statement in.
If you do not wish to use a bundler, it would also be worthwhile importing from the specific file, the function you need. For example:
import _each from '../node_modules/lodash/each'
Original answer: https://stackoverflow.com/a/52558858/13747848
Note: Please give credit to original respondent!

Module not found with corresponding type declarations using Typescript with Next.js

I have a next.js project that I am trying to add typescript to.
My folder structure is as follows:
api
aggregation.ts
interfaces
index.ts
components
Component1
index.js
index.module.css
Component2
index.js
index.module.css
pages
page1
index.js
index.module.css
I have an alias for interfaces in next.config.js
config.resolve.alias.interfaces = path.join(__dirname, 'interfaces');
Now the actual issue
index.ts in interfaces exports interfaces such as
export interface Order {
store: Store;
orderNumber: string;
totals: Totals;
customer: Customer;
currency: Currency;
paymentMethod: PaymentMethod;
items: OrderProduct[];
createdAt: string;
orderId: string;
}
And I'm trying to import them into aggregation.ts like
import { Order } from 'interfaces';
And am getting
Cannot find module 'interfaces' or its corresponding type declarations.
Which is also causing the builds to fail.
I have installed
"#types/node": "^16.0.1",
"#types/react": "^17.0.14",
"typescript": "^4.3.5",
And next has generated next-env.d.ts correctly with
/// <reference types="next" />
/// <reference types="next/types/global" />
Any ideas on how to fix the Cannot find module issue? I have a feeling it may have something to do with my folder structure or my build step. But I am also getting syntax highlighting indicating the import errors so it is probable typescript config related.
Any advice would be appreciated!
You can configure module aliases in your tsconfig.json using the baseUrl option to import directly from the root (and also use the paths option for further aliases configuration).
// tsconfig.json
{
"compilerOptions": {
"baseUrl": "."
}
}
Allowing you to use the following import.
import { Order } from 'interfaces';
From the Absolute Imports and Module path aliases documentation:
Next.js automatically supports the tsconfig.json and jsconfig.json
"paths" and "baseUrl" options since Next.js 9.4.
These options allow you to configure module aliases, for example a
common pattern is aliasing certain directories to use absolute paths.
One useful feature of these options is that they integrate
automatically into certain editors, for example VSCode.
The baseUrl configuration option allows you to import directly from
the root of the project.

Import module with absolute path using jsconfig.json not working in Node JS

It is difficult to refer the modules using relative path in the project. To achieve this we tried to using jsconfig.json on the client (react) project to refer from the absolute path. Below is my jsconfig.json file. It is working fine.
{
"compilerOptions": {
"baseUrl": "./src"
}
}
I am not able to achieve the same on server ( node js ) project. Getting the error messages
cannot find module
Any reference would be appreciated.
You can use baseUrl along with paths to fix the errors.
Paths allow us to aggregate a list directories under a predefined name and drastically reduce the length of the imports.
Here is a template on how to setup them your jsconfig.json.
jsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#routes/*": [
"./routes/*"
],
"#models/*": [
"./models/*"
],
"#datetime/*": [
"./utils/datetime/*"
]
}
}
}
We are aggregating all the files in the models folder under the name #models. The same is the case for routes and datetime. We would be able to reference the folders using #routes, #models, and #datetime in the import statement.
So, after you've setup your jsconfig, you need to change the relative paths to absolute paths. For example:
server.js
// Before jsconfig
import adminRoutes from "../../src/routes/admin"
// After jsconfig
import adminRoutes from "#routes/admin"
I hope it helps!
Read the source for more details.

eslint rule #nrwl/nx/enforce-module-boundaries fails

Intro
I was very confused with that rule when I recently ported the Ng code base to Nx 12.x. I hope this post helps others who begin migrating from Ng to Nx.
The code base above is a rather small single repo which is now used in production. When using Nx it's a good practice to follow the recommendations for monorepo to be able to use the monorepo benefits in the future as the code base is growing. (E.g. here I'm avoiding the overexposing of the code in the current repo).
I put the code base above into my-org/apps/my-small-repo. By linting I was confused by the failure of the rule #nrwl/nx/enforce-module-boundaries. So I tried different possibilities of mapping the src/app of my-org/apps/my-small-repo where either compiler or linter or both just failed.
I figured out the following solutions.
Solution 1
Just put
"compilerOptions": {
"baseUrl": "src"
},
into the root of apps/my-small-repo/tsconfig.json and replace all of your imports inside of apps/my-small-repo with imports beginning with app.
Example for a DashboardComponent:
import { DashboardComponent } from 'app/components/dashboard/dashboard.component';
Probably a better solution
This solution is tested on nx 13.x, but it probably works on previous versions of nx also.
Put
"app/*": ["apps/my-org/src/app/*"]
to the paths in compilerOptions of your tsconfig.base.json in the repo root. Then put "allowCircularSelfDependency": true, to the rule #nrwl/nx/enforce-module-boundaries in the repo root.
We decided for "allowCircularSelfDependency": true, to avoid working with ugly relative paths like like e.g. this one ../../../../../ in the app. And we also want to have library namespaces in tsconfig.base.json only.
Documentation of the rule
https://github.com/nrwl/nx/blob/master/packages/eslint-plugin-nx/src/rules/enforce-module-boundaries.ts
For those who are coming here without this getting resolved. (nx monorepo usage)
Trouble shooting the 2 errors (TS error and lint error):
First the Alias error:
Cannot find module '#account/components/something' or its corresponding type declarations.
On your base tsconfig.base.json (not tsconfig.json under your apps as it gets overrided), add:
"compilerOptions":{
...
baseUrl:"." // Try "src" as well incase of boiler plates or if your resolved path (on the error) is missing an src.
path: {
"#account/*": ["app/*"],
"#account/components/*": ["app/components/*"]
}
},
The above will resolve:
import { authMiddleware } from '#account/components/something';
from
import { authMiddleware } from '../../../components/something';
For lint error:
Projects should use relative imports to import from other files within the same project - eslint rule #nrwl/nx/enforce-module-boundaries fails`
Add "allowCircularSelfDependency": true.
"#nrwl/nx/enforce-module-boundaries": [
"error",
{
"allowCircularSelfDependency": true, -> This may solve the lint error.
"allow": ["#account/**"], -> // White list the lint error.
...
}
Whitelist the folders: Add "allow": [#foldername]
"#nrwl/nx/enforce-module-boundaries": [
"error",
{
"allow": ["#account/**"], -> // White list the lint error.
...
}
That should fix it.
To get this working:
On your base tsconfig.base.json or your local tsconfig.json.
I suggest to do it on the tsconfig.base.json
Considering your path apps/my-org/src/app/*
"compilerOptions":{
...
baseUrl:"src"
path: {
"#app/*": ["app/*"] // << Here is the change
}
},
Import in your code files from this apps/my-org/src/app/*
to this #app/*

Resources