From db6e0c52026a25df27c8fe1a1232fedc30bddb9e Mon Sep 17 00:00:00 2001
From: David Marr <david.marr@contextlabs.com>
Date: Wed, 23 Oct 2024 11:33:35 -0400
Subject: [PATCH] chore(nuxt): Resolve pinia when added via layer or module

---
 packages/nuxt/__tests__/nuxt-layer.spec.ts    | 37 +++++++++++++++++++
 packages/nuxt/layer/nuxt.config.ts            | 22 +++++++++++
 packages/nuxt/layer/playground/app.vue        | 10 +++++
 packages/nuxt/layer/playground/nuxt.config.ts | 15 ++++++++
 packages/nuxt/layer/playground/xyz/store.ts   |  6 +++
 packages/nuxt/layer/stores/example.ts         |  6 +++
 packages/nuxt/playground/nuxt.config.ts       |  1 +
 packages/nuxt/src/module.ts                   | 20 ++++------
 packages/online-playground/package.json       |  2 +-
 9 files changed, 105 insertions(+), 14 deletions(-)
 create mode 100644 packages/nuxt/__tests__/nuxt-layer.spec.ts
 create mode 100644 packages/nuxt/layer/nuxt.config.ts
 create mode 100644 packages/nuxt/layer/playground/app.vue
 create mode 100644 packages/nuxt/layer/playground/nuxt.config.ts
 create mode 100644 packages/nuxt/layer/playground/xyz/store.ts
 create mode 100644 packages/nuxt/layer/stores/example.ts

diff --git a/packages/nuxt/__tests__/nuxt-layer.spec.ts b/packages/nuxt/__tests__/nuxt-layer.spec.ts
new file mode 100644
index 0000000000..a844c11a60
--- /dev/null
+++ b/packages/nuxt/__tests__/nuxt-layer.spec.ts
@@ -0,0 +1,37 @@
+/**
+ * @vitest-env node
+ */
+import { fileURLToPath } from 'node:url'
+import path from 'node:path'
+import { describe, it, expect } from 'vitest'
+import { setup, $fetch } from '@nuxt/test-utils'
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url))
+
+await setup({
+  server: true,
+  rootDir: path.join(__dirname, '../layer/playground'),
+  nuxtConfig: {
+    hooks: {
+      'vite:extendConfig'(config, { isClient }) {
+        config.define!.__BROWSER__ = isClient
+      },
+    },
+    vite: {
+      define: {
+        __DEV__: false,
+        __TEST__: true,
+        __FEATURE_PROD_DEVTOOLS__: false,
+        __USE_DEVTOOLS__: false,
+      },
+    },
+  },
+})
+
+describe('works with nuxt layers', async () => {
+  it('loads stores when extending', async () => {
+    const html = await $fetch('/')
+    expect(html).toContain('Base store: 3')
+    expect(html).toContain('App store: xyz')
+  })
+})
diff --git a/packages/nuxt/layer/nuxt.config.ts b/packages/nuxt/layer/nuxt.config.ts
new file mode 100644
index 0000000000..60e8eacd15
--- /dev/null
+++ b/packages/nuxt/layer/nuxt.config.ts
@@ -0,0 +1,22 @@
+import { dirname, join } from 'node:path'
+import { fileURLToPath } from 'node:url'
+import { defineNuxtConfig } from 'nuxt/config'
+import piniaModule from '../src/module'
+
+const currentDir = dirname(fileURLToPath(import.meta.url))
+
+export default defineNuxtConfig({
+  modules: [piniaModule],
+
+  pinia: {
+    storesDirs: [join(currentDir, 'stores')],
+  },
+
+  vite: {
+    define: {
+      __DEV__: JSON.stringify(process.env.NODE_ENV !== 'production'),
+      __USE_DEVTOOLS__: true,
+      __TEST__: false,
+    },
+  },
+})
diff --git a/packages/nuxt/layer/playground/app.vue b/packages/nuxt/layer/playground/app.vue
new file mode 100644
index 0000000000..4bdbfbe983
--- /dev/null
+++ b/packages/nuxt/layer/playground/app.vue
@@ -0,0 +1,10 @@
+<script lang="ts" setup>
+const baseStore = useExampleStore();
+const appStore = useXYZStore();
+</script>
+<template>
+  <div>
+    <p>Base store: {{ baseStore.example }}</p>
+    <p>App store: {{ appStore.foo }}</p>
+  </div>
+</template>
\ No newline at end of file
diff --git a/packages/nuxt/layer/playground/nuxt.config.ts b/packages/nuxt/layer/playground/nuxt.config.ts
new file mode 100644
index 0000000000..2883b6efb9
--- /dev/null
+++ b/packages/nuxt/layer/playground/nuxt.config.ts
@@ -0,0 +1,15 @@
+import { defineNuxtConfig } from 'nuxt/config'
+
+export default defineNuxtConfig({
+  extends: ['..'],
+  pinia: {
+    storesDirs: ['xyz'],
+  },
+  vite: {
+    define: {
+      __DEV__: JSON.stringify(process.env.NODE_ENV !== 'production'),
+      __USE_DEVTOOLS__: true,
+      __TEST__: false,
+    },
+  },
+})
diff --git a/packages/nuxt/layer/playground/xyz/store.ts b/packages/nuxt/layer/playground/xyz/store.ts
new file mode 100644
index 0000000000..27db71a48f
--- /dev/null
+++ b/packages/nuxt/layer/playground/xyz/store.ts
@@ -0,0 +1,6 @@
+export const useXYZStore = defineStore('xyz', () => {
+  const foo = ref<string>('xyz')
+  return {
+    foo,
+  }
+})
diff --git a/packages/nuxt/layer/stores/example.ts b/packages/nuxt/layer/stores/example.ts
new file mode 100644
index 0000000000..deaeb69457
--- /dev/null
+++ b/packages/nuxt/layer/stores/example.ts
@@ -0,0 +1,6 @@
+export const useExampleStore = defineStore('example', () => {
+  const example = ref<number>(3)
+  return {
+    example,
+  }
+})
diff --git a/packages/nuxt/playground/nuxt.config.ts b/packages/nuxt/playground/nuxt.config.ts
index 1431c79015..f6f7becb4e 100644
--- a/packages/nuxt/playground/nuxt.config.ts
+++ b/packages/nuxt/playground/nuxt.config.ts
@@ -9,6 +9,7 @@ export default defineNuxtConfig({
   },
 
   modules: [piniaModule],
+  // extends: ['../layer'],
 
   pinia: {
     storesDirs: ['./stores/**', './domain/*/stores'],
diff --git a/packages/nuxt/src/module.ts b/packages/nuxt/src/module.ts
index 08148ad940..3aab7f8f07 100644
--- a/packages/nuxt/src/module.ts
+++ b/packages/nuxt/src/module.ts
@@ -7,7 +7,7 @@ import {
   isNuxt2,
   addImports,
   createResolver,
-  resolveModule,
+  resolvePath,
   addImportsDir,
 } from '@nuxt/kit'
 import type { NuxtModule } from '@nuxt/schema'
@@ -44,8 +44,7 @@ const module: NuxtModule<ModuleOptions> = defineNuxtModule<ModuleOptions>({
   defaults: {
     disableVuex: true,
   },
-  setup(options, nuxt) {
-    // configure transpilation
+  async setup(options, nuxt) {
     const { resolve } = createResolver(import.meta.url)
     const runtimeDir = fileURLToPath(new URL('./runtime', import.meta.url))
 
@@ -64,12 +63,9 @@ const module: NuxtModule<ModuleOptions> = defineNuxtModule<ModuleOptions>({
     nuxt.options.build.transpile.push(resolve(runtimeDir))
 
     // Make sure we use the mjs build for pinia
-    nuxt.options.alias.pinia =
-      nuxt.options.alias.pinia ||
-      // FIXME: remove this deprecated call. Ensure it works in Nuxt 2 to 3
-      resolveModule('pinia/dist/pinia.mjs', {
-        paths: [nuxt.options.rootDir, import.meta.url],
-      })
+    if (!nuxt.options.alias.pinia) {
+      nuxt.options.alias.pinia = await resolvePath('pinia/dist/pinia.mjs')
+    }
 
     nuxt.hook('prepare:types', ({ references }) => {
       references.push({ types: '@pinia/nuxt' })
@@ -100,10 +96,8 @@ const module: NuxtModule<ModuleOptions> = defineNuxtModule<ModuleOptions>({
       options.storesDirs = [resolve(nuxt.options.srcDir, 'stores')]
     }
 
-    if (options.storesDirs) {
-      for (const storeDir of options.storesDirs) {
-        addImportsDir(resolve(nuxt.options.rootDir, storeDir))
-      }
+    for (const storeDir of options.storesDirs) {
+      addImportsDir(resolve(nuxt.options.rootDir, storeDir))
     }
   },
 })
diff --git a/packages/online-playground/package.json b/packages/online-playground/package.json
index af6df38e6b..12fd5a7eb6 100644
--- a/packages/online-playground/package.json
+++ b/packages/online-playground/package.json
@@ -1,5 +1,5 @@
 {
-  "name": "@pinia/playground",
+  "name": "@pinia/online-playground",
   "version": "0.0.0",
   "type": "module",
   "private": true,