Topic: MDBVue - Better Typescript Support

jammerxd2 priority asked 3 months ago


Expected behavior

Components are not dependent on index.free.ts or index.pro.ts

Additionally, components should not be traversing all the way to the src folder to make imports.

Example:

src/components/free/forms/MDBInput.vue: import vMdbClickOutside from "../../../../src/directives/free/mdbClickOutside"; can be changed to import vMdbClickOutside from "../../../directives/free/mdbClickOutside";

Pro Example: src/copmonents/pro/navigation/MDBSideNav.vue: import MDBScrollbar from "../../../../src/components/pro/methods/MDBScrollbar.vue"; can be changed to import MDBScrollbar from "../methods/MDBScrollbar.vue";

Actual behavior

A few components make imports from the index.free.ts or index.pro.ts files - which in turn causes a circular dependency which then causes issues when trying to run a type check in typescript (using vue-tsc for example).

Additionally, many components traverse the relative directory tree all the way up to the src folder, necessitating another nested src folder inside of the kit.

Fixes

The following files require the imports relying on index.free or index.pro to be changed to be relative references otherwise the index.free.ts and index.pro.ts files create a circular dependency when compiling the typescript.

src/components/free/components/MDBDropdownMenu.vue

Line 56: import { MDBInput } from "../../../index.free"; to import MDBInput from "../forms/MDBInput.vue";

src/components/free/navigation/MDBNavbarToggler.vue

Line 23: import { MDBIcon } from "../../../index.free"; to import MDBIcon from "../content-styles/MDBIcon.vue";

src/components/pro/components/forms/MDBTimepickerFooter.vue

Line 49: import { mdbRipple as vMdbRipple } from "../../../../index.free"; to import vMdbRipple from "../../../../directives/free/mdbRipple"

src/components/pro/components/forms/MDBTimepicker/MDBTimepickerHeader.vue

Line 180: import { mdbRipple as vMdbRipple } from "../../../../index.free"; to import vMdbRipple from "../../../../directives/free/mdbRipple"

src/components/pro/navigation/MDBSideNavMenu.vue

Line 43: import { MDBInput } from "../../../index.free"; to import MDBInput from "../../free/forms/MDBInput.vue";

Use MDB in a vuejs project

If you're new to typescript, chances are your app was created with vite or create-app and has typescript enabled. By default, typescript uses 'strict' typechecking, which is more stringent and enforces stronger requirements for developers. The MDB library (at least vuejs version) has very poor support for typescript and requires the following flags be turned OFF via tsconfig.json:

"strict": false,
"noUnusedLocals": false,
"noUnusedParameters": false,

The issue I ran into is I didn't want to set these flags in my main app, only for the MDB vuejs library. Furthermore, doing this allows me to reduce the size of my built application, and allows the vite builder to split the js files up better - basing off of the individual imports, rather than always importing all and using the 550kb main file.

To setup a nested tsconfig.json project structure, we will need to make a project structure that looks like:

| tsconfig.json
| src
    | tsconfig.json
    | mdb5-vue-ui-kit
         | tsconfig.json

Start by creating a blank vuejs app - npm create vite@latest - and enable typescript.

Create a new folder in the src folder - mdb5-vue-ui-kit (or mdb5-vue-ui-kit-pro-advanced or whatever tier of the kit you have).

Copy only the src folder into the folder just created in the app - you should have src/mdb5-vui-ui-kit/src (yes it's intentionally nested into the src folder again)

Placing the ui kit source files inside the src folder of the app is required to avoid the typescript compiler (and vscode) from complaining about the source files not being in the rootDir of the project.

Create a tsconfig.json file inside the src/mdb5-vue-ui-kit/src folder:

src/mdb5-vue-ui-kit/src/tsconfig.json:

{
    "compilerOptions": {
        "strict": false,
        "noUnusedLocals": false,
        "noUnusedParameters": false,
        "noFallthroughCasesInSwitch": false,
        "allowSyntheticDefaultImports": true,
        "useDefineForClassFields": true,
        "rootDir": ".",
        "outDir": "../../../../dist/mdb5-vue-ui-kit",
        "composite": true,

        "target": "ES2020",
        "module": "ESNext",
        "lib": ["ES2020", "DOM", "DOM.Iterable"],
        "skipLibCheck": true,

        // Bundler mode 
        "moduleResolution": "bundler",
        "resolveJsonModule": true,
        "isolatedModules": true,
    },
    "include": ["./**/*.ts", "./**/*.tsx", "./**/*.vue"]
}

Create a tsconfig.json file inside the app src folder: src/tsconfig.json:

{
    "compilerOptions": {
      "rootDir": ".",
      "outDir": "../dist",
      "composite": true,

      "target": "ES2020",
      "module": "ESNext",
      "lib": ["ES2020", "DOM", "DOM.Iterable"],
      "skipLibCheck": true,

      // Bundler mode 
      "moduleResolution": "bundler",
      "resolveJsonModule": true,
      "isolatedModules": true,
      "strict": true,
      "noUnusedLocals": true,
      "noUnusedParameters": true,
      "noFallthroughCasesInSwitch": true,
      "allowSyntheticDefaultImports": true,
      "useDefineForClassFields": true,
      "paths": {
        "@/*": ["./*"],
        "@mdb/*": ["./mdb5-vue-ui-kit/src/*"]
      }
    },
    "references": [
      { "path": "./mdb5-vue-ui-kit/src" },
      { "path": "../tsconfig.node.json" }
    ],
    "include": ["*.ts","*.vue", "*.tsx","./**/*.ts", "./**/*.tsx", "./**/*.vue", "./mdb5-vue-ui-kit/src/**/*.ts", "./mdb5-vue-ui-kit/src/**/*.vue", "./mdb5-vue-ui-kit/src/**/*.tsx"],
  }

The key note here is the references array - the array is a list of other typescript "project" files that this tsconfig.json is dependent on. Each referenced "project" will have it's files compiled using it's own tsconfig.json options.

Adding the mdb5-vue-ui-kit/src files to the include array tells the typescript compiler to include those files as part of the project, but because of the project reference, the mdb5-vue-ui-kit\src\tsconfig.json file will get used.

Next, update the tsconfig.json in the project root to look like the following:

tsconfig.json:

{
    "compilerOptions": {
      "rootDir": ".",

      "target": "ES2020",
      "useDefineForClassFields": true,
      "module": "ESNext",
      "lib": ["ES2020", "DOM", "DOM.Iterable"],
      "skipLibCheck": true,

      // Bundler mode 
      "moduleResolution": "bundler",
      "resolveJsonModule": true,
      "isolatedModules": true,
      "noEmit": true,
      "strict": true,
      "noUnusedLocals": true,
      "noUnusedParameters": true,
      "noFallthroughCasesInSwitch": true,
      "allowSyntheticDefaultImports": true,
      "paths": {
        "@/*":["./src/*"],
        "@mdb/*": ["./src/mdb5-vue-ui-kit/src/*"]
      }
    },
    "files": [],
    "references": [
      { "path": "./src/mdb5-vue-ui-kit/src" },
      { "path": "./src" },
      { "path": "./tsconfig.node.json" }
    ]
}

And finally the vite.config.ts file:

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
      '@mdb':fileURLToPath(new URL('./src/mdb5-vue-ui-kit/src',import.meta.url))
    }
  }
})

Install Dependencies

The MDB vue ui kit has several other packages that are required to be installed, at the time of writing they are:

  • @popperjs/core
  • chart.js
  • chartjs-plugin-datalabels
  • deepmerge
  • vue3-perfect-scrollbar

There are also other dev dependencies:

  • sass
  • @types/node
  • @types/chart.js

All Done

Now instead of importing components from 'mdb-vue-ui-kit' or the index file, components can be individually imported from their respective .vue files - and without typescript compile errors when strict checking is on.

For example: src/components/HelloWorld.vue (as taken from the sample vue app):

<script setup lang="ts">
import MDBContainer from '../mdb5-vue-ui-kit/src/components/free/layout/MDBContainer.vue';
import MDBRow from '../mdb5-vue-ui-kit/src/components/free/layout/MDBRow.vue';
import MDBCol from '../mdb5-vue-ui-kit/src/components/free/layout/MDBCol.vue';
</script>

<template>
    <MDBContainer>
        <MDBRow>
            <MDBCol sz="12">
                <h1 class="text-center">HELLO WORLD</h1>
            </MDBCol>
        </MDBRow>
    </MDBContainer>
</template>

Additionally, import the main scss file in src/main.ts: import './mdb5-vue-ui-kit/src/scss/index.pro.scss' or import './mdb5-vue-ui-kit/src/scss/index.pro.dark.scss' for the dark version

Thank You

If you made it this far in reading through everything, congratulations! And thank you for taking the time to read through all this.


jammerxd2 priority commented 3 months ago

And my sources: https://stackoverflow.com/questions/68262454/angular-monorepo-error-ts6059-file-ng-youtube-api-service-ngtypecheck-ts-is-n/76500288#76500288

https://stackoverflow.com/questions/55753163/package-json-is-not-under-rootdir/61467483#61467483

This one was by far the most useful: https://stackoverflow.com/questions/60896829/monorepo-with-rootdirs-produces-unwanted-sudirectories-such-as-src-in-outdi/61513685#61513685


Bartosz Cylwik staff answered 3 months ago


Hi! Thank you for that message! We are planning to update the typescript support for the next release. I'm also adding the issue with importing files to our list to check.

Best Regards!


jammerxd2 priority commented 3 months ago

So long as the functionality/project layout I mentioned above remains working :)



Please insert min. 20 characters.

FREE CONSULTATION

Hire our experts to build a dedicated project. We'll analyze your business requirements, for free.

Status

Answered

Specification of the issue

  • ForumUser: Priority
  • Premium support: Yes
  • Technology: MDB Vue
  • MDB Version: MDB5 4.1.1
  • Device: Any
  • Browser: Any
  • OS: Any
  • Provided sample code: Yes
  • Provided link: No