Search code examples
typescriptvue.jsdependenciesmonorepo

Can't build Vue.js app with Typescript project references


I'm attempting to utilize Typescript project references to build a Vue app in a monorepo. My current project structure is as follows:

client/
  package.json
  tsconfig.json
  src/
    ...

server/
  package.json
  tsconfig.json
  src/
    ...

shared/
  package.json
  tsconfig.json
  preferences.ts
  permissions.ts
  interfaces/
    ...

client/tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "strictNullChecks": false,
    "strictPropertyInitialization": false,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "noImplicitAny": false,
    "baseUrl": ".",
    "types": ["mocha", "chai", "vuetify", "webpack-env"],
    "paths": {
      "@/*": ["src/*"],
      "@shared/*": ["../shared/*"]
    },
    "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ],
  "exclude": ["node_modules"],
  "references": [
    { "path": "../shared" }
  ]
}

shared/tsconfig.json

{
    "compilerOptions": {
        "target": "esnext",
        "module": "esnext",
        "declaration": true,
        "declarationMap": true,
        "rootDir": "src",
        "outDir": "./dist",
        "composite": true
    }
}

The only errors I get are when I reference preferences or permissions in the shared folder. A few things to note:

  • If I reference something in shared/interface from client, it doesn't raise any issues. It only raises an issue if I reference a file directly in the root of shared.
  • Intellisense does not detect any issues in vscode.
 INFO  Starting development server...
Starting type checking service...
Using 1 worker with 2048MB memory limit
98% after emitting CopyPlugin

 ERROR  Failed to compile with 7 errors                                                                                                              11:14:37 AM
These dependencies were not found:

* @shared/permission in ./src/router/index.ts, ./node_modules/cache-loader/dist/cjs.js??ref--14-0!./node_modules/babel-loader/lib!./node_modules/ts-loader??ref--14-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/views/Home/Index.vue?vue&type=script&lang=ts& and 1 other
* @shared/preference in ./node_modules/cache-loader/dist/cjs.js??ref--14-0!./node_modules/babel-loader/lib!./node_modules/ts-loader??ref--14-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/Navigation.vue?vue&type=script&lang=ts&, ./node_modules/cache-loader/dist/cjs.js??ref--14-0!./node_modules/babel-loader/lib!./node_modules/ts-loader??ref--14-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/views/Account/Preferences.vue?vue&type=script&lang=ts& and 2 others

To install them, you can run: npm install --save @shared/permission @shared/preference
No type errors found
Version: typescript 3.9.9
Time: 6921ms

Any ideas on how to fix these errors?


Solution

  • What ended up working for me was to configure Webpack (which Vue uses under the hood) to resolve my alias "@shared" to the correct path.

    To do this, you need to edit your vue.config.js like so:

    const path = require('path');
    
    module.exports = {
      resolve: {
        alias: {
          "@shared": path.resolve(__dirname, '../shared/dist')
        }
      }
    };
    

    (Source: https://github.com/TypeStrong/ts-loader/blob/main/REFERENCES.md#setup-your-codebase-to-consume-the-project)

    Notice - just like using module-alias - if you specified an outDir (tsconfig.json) in your shared project, you need to point the alias path to the files located in there. For me this meant appending /dist to the path.

    However, when starting the dev-server I got an error telling me that ESLint is not configured for my @shared path (which is correct). So the last thing missing was to exclude my @shared path from ESLint. For this, all you need to do is create a .eslintignore file in your client directory where you point to the shared directory:

    ../shared
    

    I hope this works for you, even if I might be a little late to the question. :)