Repository: nuxt/nuxt.js
Pull request #7374 (2020-05-16 13:20:11)

feat: components
<!--- Provide a general summary of your changes in the title above -->

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (a non-breaking change which fixes an issue)
- [x] New feature (a non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)


## Description

👀

**Core fix:** Don't use module handler fn name as unique key so we can do unique module check by default. This is important as one may add components module to modules/buildModules section

## Checklist:
<!--- Put an `x` in all the boxes that apply. -->
<!--- If your change requires a documentation PR, please link it appropriately -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly. (PR: #)
- [ ] I have added tests to cover my changes (if not applicable, please state why)
- [ ] All new and existing tests are passing.



codecov-io: # [Codecov](https://codecov.io/gh/nuxt/nuxt.js/pull/7374?src=pr&el=h1) Report
> Merging [#7374](https://codecov.io/gh/nuxt/nuxt.js/pull/7374?src=pr&el=desc) into [dev](https://codecov.io/gh/nuxt/nuxt.js/commit/925abf8123460c754f4da4e351af82ba531591e9&el=desc) will **decrease** coverage by `0.01%`.
> The diff coverage is `66.66%`.

[![Impacted file tree graph](https://codecov.io/gh/nuxt/nuxt.js/pull/7374/graphs/tree.svg?width=650&height=150&src=pr&token=nGD1PtMB3M)](https://codecov.io/gh/nuxt/nuxt.js/pull/7374?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##              dev    #7374      +/-   ##
==========================================
- Coverage   70.62%   70.61%   -0.02%     
==========================================
  Files          88       88              
  Lines        3602     3604       +2     
  Branches      976      978       +2     
==========================================
+ Hits         2544     2545       +1     
- Misses        858      859       +1     
  Partials      200      200              
```

| Flag | Coverage Δ | |
|---|---|---|
| #unittests | `70.61% <66.66%> (-0.02%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/nuxt/nuxt.js/pull/7374?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [packages/config/src/options.js](https://codecov.io/gh/nuxt/nuxt.js/pull/7374/diff?src=pr&el=tree#diff-cGFja2FnZXMvY29uZmlnL3NyYy9vcHRpb25zLmpz) | `97.63% <50.00%> (-0.46%)` | :arrow_down: |
| [packages/core/src/module.js](https://codecov.io/gh/nuxt/nuxt.js/pull/7374/diff?src=pr&el=tree#diff-cGFja2FnZXMvY29yZS9zcmMvbW9kdWxlLmpz) | `94.25% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/nuxt/nuxt.js/pull/7374?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/nuxt/nuxt.js/pull/7374?src=pr&el=footer). Last update [925abf8...36cf0ef](https://codecov.io/gh/nuxt/nuxt.js/pull/7374?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

Atinux: Added the reference in upcoming docs: https://github.com/nuxt/docs/pull/1922/commits/46c6ba8a29ecbc1553d8adf08e8d1a96a796ffab

Patch:
diff --git a/distributions/nuxt/package.json b/distributions/nuxt/package.json
index e22733bd8..3e5caaa45 100644
--- a/distributions/nuxt/package.json
+++ b/distributions/nuxt/package.json
@@ -60,6 +60,7 @@
   "dependencies": {
     "@nuxt/builder": "2.12.1",
     "@nuxt/cli": "2.12.1",
+    "@nuxt/components": "^0.2.2",
     "@nuxt/core": "2.12.1",
     "@nuxt/generator": "2.12.1",
     "@nuxt/loading-screen": "^1.2.0",
diff --git a/packages/config/src/options.js b/packages/config/src/options.js
index 81b7a8b2a..553de8939 100644
--- a/packages/config/src/options.js
+++ b/packages/config/src/options.js
@@ -448,6 +448,11 @@ export function getNuxtConfig (_options) {
       .map(([path, handler]) => ({ path, handler }))
   }
 
+  // Components module
+  if (options.components) {
+    options.buildModules.push('@nuxt/components')
+  }
+
   // Generate staticAssets
   const { staticAssets } = options.generate
   if (!staticAssets.version) {
diff --git a/packages/core/src/module.js b/packages/core/src/module.js
index 1c8979e2f..a8b1aa84b 100644
--- a/packages/core/src/module.js
+++ b/packages/core/src/module.js
@@ -112,10 +112,10 @@ export default class ModuleContainer {
   }
 
   requireModule (moduleOpts) {
-    return this.addModule(moduleOpts, true /* require once */)
+    return this.addModule(moduleOpts)
   }
 
-  async addModule (moduleOpts, requireOnce) {
+  async addModule (moduleOpts) {
     let src
     let options
     let handler
@@ -176,15 +176,10 @@ export default class ModuleContainer {
       throw new TypeError('Module should export a function: ' + src)
     }
 
-    // Resolve module meta
-    let key = (handler.meta && handler.meta.name) || handler.name
-    if (!key || key === 'default') {
-      key = src
-    }
-
-    // Update requiredModules
+    // Ensure module is required once
+    const key = (handler.meta && handler.meta.name) || src
     if (typeof key === 'string') {
-      if (requireOnce && this.requiredModules[key]) {
+      if (this.requiredModules[key]) {
         return
       }
       this.requiredModules[key] = { src, options, handler }
diff --git a/yarn.lock b/yarn.lock
index 32758fefe..7060093ef 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1819,6 +1819,11 @@
     "@nodelib/fs.scandir" "2.1.3"
     fastq "^1.6.0"
 
+"@nuxt/components@^0.2.2":
+  version "0.2.2"
+  resolved "https://registry.npmjs.org/@nuxt/components/-/components-0.2.2.tgz#194f65574dc40aacf8d0f132a134168ce1b58c83"
+  integrity sha512-mTDZLmfx65fuI8haXZLeh425vSrCAHRGyK3G6Ckr/QSgmle9HDuaQX1Jl/yEEvBxiUzcPp1fhMexNMn2mvkofg==
+
 "@nuxt/devalue@^1.2.4":
   version "1.2.4"
   resolved "https://registry.npmjs.org/@nuxt/devalue/-/devalue-1.2.4.tgz#69eca032b7481fd3c019a78ade65d642da3f2f35"


Test patch:
diff --git a/packages/core/test/module.test.js b/packages/core/test/module.test.js
index 766d648fe..55304fe2a 100644
--- a/packages/core/test/module.test.js
+++ b/packages/core/test/module.test.js
@@ -317,7 +317,7 @@ describe('core: module', () => {
     module.requireModule(moduleOpts)
 
     expect(module.addModule).toBeCalledTimes(1)
-    expect(module.addModule).toBeCalledWith(moduleOpts, true)
+    expect(module.addModule).toBeCalledWith(moduleOpts)
   })
 
   test('should add string module', async () => {
@@ -402,21 +402,17 @@ describe('core: module', () => {
     })
 
     const result = await module.addModule({
-      src: 'moduleTest',
+      src: 'pathToModule',
       options: { test: true },
-      handler: function objectModule (options) {
-        return Promise.resolve(options)
-      }
+      handler: opts => opts
     })
 
     expect(requireModule).not.toBeCalled()
     expect(module.requiredModules).toEqual({
-      objectModule: {
-        handler: expect.any(Function),
-        options: {
-          test: true
-        },
-        src: 'moduleTest'
+      pathToModule: {
+        src: 'pathToModule',
+        options: { test: true },
+        handler: expect.any(Function)
       }
     })
     expect(result).toEqual({ test: true })
diff --git a/test/dev/basic.ssr.test.js b/test/dev/basic.ssr.test.js
index 38daff8c8..61b7cdef2 100644
--- a/test/dev/basic.ssr.test.js
+++ b/test/dev/basic.ssr.test.js
@@ -370,6 +370,11 @@ describe('basic ssr', () => {
     expect(html).toContain('<h1>Nested symlink page</h1>')
   })
 
+  test('/components', async () => {
+    const { html } = await nuxt.server.renderRoute('/components')
+    expect(html).toContain('Auto discovered component!')
+  })
+
   // Close server and ask nuxt to stop listening to file changes
   afterAll(async () => {
     await nuxt.close()
diff --git a/test/fixtures/basic/components/MyComponent.vue b/test/fixtures/basic/components/MyComponent.vue
new file mode 100644
index 000000000..833d8e378
--- /dev/null
+++ b/test/fixtures/basic/components/MyComponent.vue
@@ -0,0 +1,3 @@
+<template>
+  <div>Auto discovered component!</div>
+</template>
diff --git a/test/fixtures/basic/nuxt.config.js b/test/fixtures/basic/nuxt.config.js
index 652c45d19..bb9e1da49 100644
--- a/test/fixtures/basic/nuxt.config.js
+++ b/test/fixtures/basic/nuxt.config.js
@@ -63,6 +63,7 @@ export default {
     '': true
   },
   pageTransition: false,
+  components: true,
   plugins: [
     '~/plugins/vuex-module',
     '~/plugins/dir-plugin',
diff --git a/test/fixtures/basic/pages/components.vue b/test/fixtures/basic/pages/components.vue
new file mode 100644
index 000000000..e2fa36c30
--- /dev/null
+++ b/test/fixtures/basic/pages/components.vue
@@ -0,0 +1,5 @@
+<template>
+  <div>
+    <MyComponent />
+  </div>
+</template>