pnpm & vue & vite monorepo - 解析工作空间包内别名路径的导入

Ron*_*onZ 7 typescript vue.js monorepo pnpm vite

我正在使用 pnpm、typescript、vue 和 vite 使用共享组件和样式构建 UI 应用程序的 monorepo。

在尝试利用 pnpm 的工作区生态系统来简化开发体验和部署时,我在将包导入应用程序时遇到了使用别名路径的问题。

这是我的文件夹结构:


    src/
    |
    |- apps/
    |   |- app1/
    |   |   |- env/
    |   |   |- node_modules/
    |   |   |- src/
    |   |   |   |- plugins/
    |   |   |   |   |- some-logic.ts
    |   |   |   |- styles/
    |   |   |   |   |- app.scss
    |   |   |   |- views/
    |   |   |   |   |- HomeView.vue
    |   |   |   ...
    |   |   |   |- App.vue
    |   |   |   |- main.ts
    |   |   |
    |   |   |- index.html
    |   |   |- package.json
    |   |   |- tsconfig.json
    |   |   |- vite.config.ts
    |
    |- packages/
    |   |- shared-ui/
    |   |   |- node_modules/
    |   |   |- src/
    |   |   |   |- components/
    |   |   |   |   |- Header.vue
    |   |   |   |- plugins/
    |   |   |   |   |- another-logic.ts
    |   |   |   |- styles/
    |   |   |   |   |- header.scss
    |   |   |- package.json
    |   |   |- tsconfig.json
    |
    |- node_modules/
    ...
    |- package.json
    |- pnpm-lock.yaml
    |- pnpm-workspace.yaml
    |- tsconfig.base.json
    ...
    |- package.json
    |- pnpm-lock.yaml
    |- pnpm-workspace.yaml
    |- tsconfig.base.json

Run Code Online (Sandbox Code Playgroud)

HomeView.vue在我的应用程序中导入了Header.vue我的shared-ui包的组件:


    src/
    |
    |- apps/
    |   |- app1/
    |   |   |- env/
    |   |   |- node_modules/
    |   |   |- src/
    |   |   |   |- plugins/
    |   |   |   |   |- some-logic.ts
    |   |   |   |- styles/
    |   |   |   |   |- app.scss
    |   |   |   |- views/
    |   |   |   |   |- HomeView.vue
    |   |   |   ...
    |   |   |   |- App.vue
    |   |   |   |- main.ts
    |   |   |
    |   |   |- index.html
    |   |   |- package.json
    |   |   |- tsconfig.json
    |   |   |- vite.config.ts
    |
    |- packages/
    |   |- shared-ui/
    |   |   |- node_modules/
    |   |   |- src/
    |   |   |   |- components/
    |   |   |   |   |- Header.vue
    |   |   |   |- plugins/
    |   |   |   |   |- another-logic.ts
    |   |   |   |- styles/
    |   |   |   |   |- header.scss
    |   |   |- package.json
    |   |   |- tsconfig.json
    |
    |- node_modules/
    ...
    |- package.json
    |- pnpm-lock.yaml
    |- pnpm-workspace.yaml
    |- tsconfig.base.json
    ...
    |- package.json
    |- pnpm-lock.yaml
    |- pnpm-workspace.yaml
    |- tsconfig.base.json

Run Code Online (Sandbox Code Playgroud)

正如您在上面看到的,@/充当src应用程序文件夹的路径别名。这按预期工作。问题从Header组件开始:


    <script setup lang="ts">
    import stuff from '@/plugins/some-logic.ts'
    import Header from '@namespace/shared-ui/src/components/Header.vue';
    
    stuff();
    </script>
    
    <template>
        <div class="container">
            <Header />
        </div>
    </template>
    
    <style lang="scss">
    @import '@/styles/app.scss';
    </style>

Run Code Online (Sandbox Code Playgroud)

我的猜测是,因为 vite 的入口点是,并且在 vite 的配置中,我创建了tosrc/apps/app1/的别名,它也尝试解析包的 ,并导致错误的导入,如下所述:@src/@


    <script setup lang="ts">
    import moreStuff from '@/plugins/another-logic.ts' // doesn't work
    
    
    moreStuff();
    </script>
    
    <template>
        <div class="header">
            ...
        </div>
    </template>
    
    <style lang="scss">
    // @import '@/styles/header.scss'; // doesn't work
    @import '../styles/header.scss'; // works
    </style>

Run Code Online (Sandbox Code Playgroud)

根包.json


    import/no-unresolved    Unable to resolve path to module '@/plugins/another-logic.ts'
    import/no-unresolved    [vite] Internal server error: [sass] ENOENT: no such file or directory, open '/namespace/apps/app1/src/styles/header.scss'

Run Code Online (Sandbox Code Playgroud)

pnpm-workspace.yaml


    {
      "name": "namespace",
      "private": true,
      "type": "module",
      "packageManager": "pnpm@8.6.9",
      "browserslist": [
        "> 1%",
        "last 2 versions",
        "not dead",
        "not ie <= 11"
      ],
      "devDependencies": {
        "@types/node": "~20.3.3",
        "@typescript-eslint/eslint-plugin": "~5.61.0",
        "@typescript-eslint/parser": "~5.61.0",
        "eslint": "~8.44.0",
        "eslint-config-prettier": "~8.8.0",
        "eslint-import-resolver-typescript": "~3.5.5",
        "eslint-plugin-import": "~2.27.5",
        "eslint-plugin-prettier": "~4.2.1",
        "eslint-plugin-vue": "~9.15.1",
        "prettier": "~2.8.8",
        "ts-node": "~10.9.1",
        "typescript": "~5.1.6",
        "vite": "~4.3.9",
        "vite-plugin-eslint": "~1.8.1",
        "vue-eslint-parser": "~9.3.1"
      }
    }

Run Code Online (Sandbox Code Playgroud)

tsconfig.base.json


    packages:
      - 'apps/*'
      - 'packages/*'

Run Code Online (Sandbox Code Playgroud)

应用程序/app1/package.json

{
  "compilerOptions": {
    "target": "es6",
    "module": "esnext",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "isolatedModules": true,
    "strict": true,
    "jsx": "preserve",
    "experimentalDecorators": true,
    "noEmit": false,
    "skipLibCheck": true,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "useDefineForClassFields": true,
    "sourceMap": true,
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  },
  "references": [
    {
      "path": "./packages/shared-ui"
    }
  ],
  "exclude": [
    "**/node_modules",
    "packages/**/dist"
  ]
}
Run Code Online (Sandbox Code Playgroud)

应用程序/app1/tsconfig.json


    {
      "name": "@namespace/app1",
      "private": true,
      "type": "module",
      "packageManager": "pnpm@8.6.9",
      "scripts": {
        "serve": "vite"
      },
      "dependencies": {
        "@namespace/shared-ui": "workspace:*",
        "@vee-validate/zod": "~4.10.8",
        "axios": "~1.4.0",
        "pinia": "~2.1.4",
        "vee-validate": "~4.10.8",
        "vite-plugin-vuetify": "~1.0.2",
        "vue": "~3.3.4",
        "vue-router": "~4.2.4",
        "vuetify": "~3.3.6",
        "zod": "~3.21.4"
      },
      "devDependencies": {
        "@vitejs/plugin-vue": "~4.2.3",
        "sass": "~1.64.1",
        "vite-tsconfig-paths": "~4.2.0"
      }
    }

Run Code Online (Sandbox Code Playgroud)

应用程序/app1/vite.config.ts


    {
      "extends": "../../tsconfig.base.json",
      "compilerOptions": {
        "baseUrl": "./",
        "outDir": "./dist/",
        "paths": {
          "@/*": [
            "src/*"
          ]
        },
        "typeRoots": [
          "./node_modules/@types",
          "./src/types"
        ]
      },
      "include": [
        "src/**/*.ts",
        "src/**/*.d.ts",
        "src/**/*.tsx",
        "src/**/*.vue",
        "vite.config.ts"
      ]
    }

Run Code Online (Sandbox Code Playgroud)

包/shared-ui/package.json


    import { type UserConfigExport, defineConfig } from 'vite';
    import eslint from 'vite-plugin-eslint';
    import vuetify from 'vite-plugin-vuetify';
    import tsconfigPaths from 'vite-tsconfig-paths';
    
    import vue from '@vitejs/plugin-vue';
    
    export default defineConfig(({ mode }) => {
        const isDevelopment = mode === 'development';
        const config: UserConfigExport = {
            root: `${process.cwd()}/`,
            envDir: `${process.cwd()}/env/`,
            plugins: [tsconfigPaths(), eslint(), vue(), vuetify()],
            resolve: {
                alias: {
                    '@/': `${process.cwd()}/src/`,
                    vue: 'vue/dist/vue.esm-bundler.js'
                }
            }
        };
    
        if (isDevelopment) {
            config.server = {
                host: true,
                port: Number(process.env.PORT)
            };
        }
    
        return config;
    });

Run Code Online (Sandbox Code Playgroud)

包/shared-ui/tsconfig.json


    {
      "name": "@namespace/shared-ui",
      "private": true,
      "type": "module",
      "packageManager": "pnpm@8.6.9",
      "dependencies": {
        "axios": "~1.4.0"
      },
      "devDependencies": {
        "@vee-validate/zod": "~4.10.8",
        "vee-validate": "~4.10.8",
        "vue": "~3.3.4",
        "vuetify": "~3.3.6",
        "zod": "~3.21.4"
      }
    }

Run Code Online (Sandbox Code Playgroud)

Ron*_*onZ 0

如以下 URL 中所述,vite( 和rollup) 显然不支持使用数组解析别名,而仅支持使用字符串。目前的解决方案是为每个应用程序/包选择不同的别名。

https://github.com/vercel/turbo/discussions/620#discussioncomment-2136195