npm package: @mega-apps/nuxt-plugin-mom
Description: Auto import mom modules and components for Mega Apps.
Author: sunzhifeng
Latest version: 1.2.11

`Mom Nuxt Modules` 技术实现核心组件。

# @mega-apps/nuxt-plugin-mom

> Module to scan and auto import Mega Mom Modules for Nuxt 2.13+

<p align="left">
  <a href="https://www.npmjs.com/package/@mega-apps/nuxt-plugin-mom"><img src="https://badgen.net/npm/dm/@mega-apps/nuxt-plugin-mom" alt="Downloads"></a>
  <a href="https://www.npmjs.com/package/@mega-apps/nuxt-plugin-mom"><img src="https://badgen.net/npm/v/@mega-apps/nuxt-plugin-mom" alt="Version"></a>
  <a href="https://www.npmjs.com/package/@mega-apps/nuxt-plugin-mom"><img src="https://badgen.net/npm/license/@mega-apps/nuxt-plugin-mom" alt="License"></a>
</p>

`Mom Nuxt Modules` 技术实现核心组件。

<img src="./images/nuxt-plugin-mom.jpg" width="800" alt="nuxt-plugin-mom" align=center />

## 1.1. 特性

* 完全兼容Nuxt 2.15.3+框架
* 支持Nuxt `components` 的自动扫描处理
  + Automatically scan `components/` directory
  + No need to manually import components anymore
  + Multiple paths with customizable prefixes and lookup/ignore patterns
  + Lazy loading (Async components)
  + Production code-splitting optimization (loader)
  + Hot reloading
  + Module integration
  + Fully tested
* 支持自动扫描 Mega Mom 模块中的子目录
  + 支持子目录扫描逻辑设置
  + 支持文件及目录在Windows/Unix/Linux/macOS的名称检测
* 支持自动注入`$MOM_ENV` 变量
* 支持开发模式下的配置变化的检测，热更新
* 支持开启日志模式，输出详细的处理过程

## 1.2. 安装

```bash
npm i -D @mega-apps/nuxt-plugin-mom
```

## 1.3. 快速使用

Set the `momModules` option in `nuxt.config` :

```js
// nuxt.config.js

export default {
    ...

    // *** 关键部分 ***
    // 是否开启Mom调试
    momDebug: false,
    // 可以指定哪些目录作为Mom的模块用于集成构建，更多细节，查看 `momModules` 部分
    momModules: [{
        // Mom Module 的路径
        path: "node_modules/@mega-apps/mom-core-vue",
        // 应用于 Mom Module 的组件前缀
        prefix: "MomCore",
        // Mom Module 的特殊设置，可以过滤不需要的文件或文件夹，及处理行为
        options: {
            // 子文件名称，参见Mom Module的目录结构
            components: {
                enabled: true,
                pattern: ["components/app-tags-view"],
                patternOverwrite: false
            }
        }
    }],

    // *** 附加部分 ***
    // 以下内容，一般不需要；@mega-apps/cli 提供的基础nuxt.config.js 已经内置了
    // 针对momModules 没有生效的情况
    // Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
    buildModules: [
        // Mom提供的注入Nuxt的模块
        '@mega-apps/nuxt-plugin-mom',
    ],
}
```

## 1.4. 参数选项

以下是支持的 `nuxt.config.js` 中的配置

```ts
/// 以下是定义文件内容参见

declare module '@nuxt/types/config/index' {
  interface NuxtOptions {
    // 是否开启Mom调试
    momDebug: boolean;
    // 可以指定哪些目录作为Mom的模块用于集成构建
    momModules: boolean | Options | Options['dirs'];
    // 可以指定mom临时构建的目录名称
    momBuildDirName: string;
    // 可以指定mom构建的路径
    momBuildDir: string;
    // 可以指定哪些目录名称将参与资源整合; 属于附加操作，
    // momModules中常规的文件夹有：app, store, pages, api, components
    // eg. 如momModules中的非常规文件夹名称(如: packages, types)
    // 默认是严格区分大小写的
    momModuleIncludeDirNames: string[];

    // 可以指定哪些目录名称将不参与资源整合; 属于附加操作，
    // momModules中常规的文件夹有：app, store, pages, api, components
    // eg. 不需要 pages 目录
    // 默认是严格区分大小写的
    momModuleExcludeDirNames: string[];

    // 附加的关心的文件及目录路径模式
    // 有的时候，希望外部干预这些模式，提供此方式来解决该问题
    // eg. 希望.env 文件加入集成融合整合种；
    momModuleCaseFilePatterns: string[];

    // @readonly mom 记录变更之前的nuxt原先的src目录地址
    momNuxtOrgSrcDir: string;
  }
}

declare module '@nuxt/types/config/hooks' {
  interface NuxtOptionsHooks {
    'momModules:alias'?: momModulesNuxtAliasHook;
    'momModules:dir:config'?: momModulesNuxtDirConfigHook;
    'momModules:dirs'?: momModulesDirHook;
    'momModules:extend'?: momModulesExtendHook;
    'momModules:caseFilePatterns'?: momModulesCaseFilePatternsHook;
  }
}
```

### 1.4.1. momModules 选项

```ts
export interface ScanDir {
  // 路径
  path: string
  // 匹配模式，参照glob
  pattern?: string | string[]
  // 用于components特性，忽略哪些
  ignore?: string[]
  // 用于components特性，设置组件的前缀
  prefix?: string
  // 用于components特性，是否设置成全局组件
  global?: boolean | 'dev'
  // 用于components特性，路径前缀
  pathPrefix?: boolean
  // 优先级
  level?: number
}

export interface ComponentsDir extends ScanDir {
  // 是否监听变化
  watch?: boolean
  // 支持的文件扩展，默认是 [vue, js, ts, tsx]
  extensions?: string[]
  // 是否透传
  transpile?: 'auto' | boolean
}

export interface BaseNormalDirOptions {
  // 是否可用
  enabled?: boolean,
  // 是否开启覆盖
  overwrite?: boolean,
  // 匹配模式
  pattern?: string | string[]
  // 匹配模式是否覆盖系统中的
  patternOverwrite?: boolean
}

```

### 1.4.2. Mom关心的文件及目录路径

``` ts
/**
 * 获得Mom关心的文件及目录路径
 * @param nuxt
 * @param others
 */
export const getCaseMomModulesFilePaths = async (nuxt: any, others: string[] = []) => {
  const preParePatterns = // 注意次序非常重要，**、* 一般要放到最开头
    [
      ...others,
      ...['!package.json'],
      ...['!dist'],
      /// Runtime data
      ...[
        '*.pid',
        '*.seed',
        '*.pid.lock',
      ].map(e => `!${e}`),
      /// macOS
      ...['.DS_Store'].map(e => `!${e}`),
      /// dotenv environment variables file
      ...['.env'].map(e => `!${e}`),
      /// node
      ...['.node_repl_history'].map(e => `!${e}`),
      /// jscoverage/JSCover
      ...['lib-cov'].map(e => `!${e}`),
      /// jspm_packages
      ...['jspm_packages'].map(e => `!${e}`),
      /// npm
      ...['node_modules', 'npm'].map(e => `!${e}`),
      ...['.yarnrc', '.npmrc'].map(e => `!${e}`),
      ...[
        'yarn.lock',
        'package.lock',
        'package-lock.json',
        'npm-debug.log*',
        'yarn-debug.log*',
        'yarn-error.log*',
        '.yarn-integrity'
      ].map(e => `!${e}`),
      /// git
      ...['.git', '.github', '.gitignore', '.gitattributes'].map(e => `!${e}`),
      /// ide
      ...['.idea', '.vscode', 'lsp', '.swp', 'jsconfig.json'].map(e => `!${e}`),
      /// conf
      ...['*.conf'].map(e => `!${e}`),
      /// docker
      ...['Dockerfile', 'docker', '.dockerignore'].map(e => `!${e}`),
      /// md
      ...['!*.md'],
      /// LICENSE
      ...['!LICENSE'],
      /// babel
      ...['.babelrc', 'babel.config.js'].map(e => `!${e}`),
      /// TypeScript
      ...['tsconfig.json'].map(e => `!${e}`),
      /// editorconfig
      ...['.editorconfig'].map(e => `!${e}`),
      /// eslint files
      ...[
        '.eslintrc',
        '.eslintrc.json',
        '.eslintrc.yaml',
        '.eslintrc.yml',
        '.eslintrc.js',
        '.eslintignore',
        '.eslintcache',
      ].map(e => `!${e}`),
      /// stylelint files
      ...[
        '.stylelintignore',
        '.stylelintrc',
        '.stylelintrc.json',
        '.stylelintrc.yaml',
        '.stylelintrc.yml',
        '.stylelintrc.js',
        'stylelint.config.js'
      ].map(e => `!${e}`),
      /// lslint files
      ...['', '.json', '.yaml', '.yml', '.js', '.ts']
        .map(e => `.ls-lint${e}`)
        .map(e => `!${e}`),
      /// husky
      ...['.huskyrc.js', '.huskyrc'].map(e => `!${e}`),
      /// prettierrc
      ...['.prettierignore', 'prettier.config.js', '.prettierrc'].map(e => `!${e}`),
      ...['', '.json', '.yaml', '.yml', '.js', '.ts']
        .map(e => `.prettierrc${e}`)
        .map(e => `!${e}`),
      /// commitlint files
      ...['commitlint.config.js'].map(e => `!${e}`),
      /// jest
      ...['jest.config.js'].map(e => `!${e}`),
      /// # parcel-bundler cache (https://parceljs.org/)
      ...['.cache'].map(e => `!${e}`),
      /// vuepress
      ...['.vuepress'].map(e => `!${e}`),
      /// nuxt && next
      ...['.js', '.ts'].map(e => `nuxt.config${e}`).map(e => `!${e}`),
      ...['.nuxtrc'].map(e => `!${e}`),
      ...['!.nuxt', '!.next'].concat(
        nuxt ? [`!${nuxt?.options?.momBuildDirName}`] : []
      ),
      ...(nuxt?.options?.momModuleCaseFilePatterns || [])
    ];

  await nuxt.callHook('momModules:caseFilePatterns', preParePatterns, nuxt);

  return preParePatterns
}
```

## 1.5. 关于 `Mom Module`

所谓 `Mom Module` , 就是以目录为基本组成单元（例如，node_modules/a， 或任意目录），作为模块（也称为资源模块）。

### 1.5.1. 内置支持的目录结构

以下是当前支持的 `Mom Module` 的目录结构，将参与构建集成

```js
// Mom
api

// Nuxt default
app
assets
components

// Mom
config
configs

// Mom
direactive
framework
frameworks

// Nuxt default
layouts

// Mom
lib
libs

// Nuxt default
locales
middleware

// Mom
mixins
mock

// Nuxt default
pages
plugins
public

// Mom
router
routers

// Nuxt default
static
store
test

// Mom
setting
settings
util
utils
vendor
vendors
```

### 1.5.2. 特别说明，components 只有明确 {enable：true} 才有效

```js
// nuxt.config.js

export default {
    ...

    // *** 关键部分 ***
    // 可以指定哪些目录作为Mom的模块用于集成构建，更多细节，查看 `momModules` 部分
    momModules: [{
        // Mom Module 的路径
        path: "node_modules/@mega-apps/mom-core-vue",
        // 应用于 Mom Module 的组件前缀
        prefix: "MomCore",
        // Mom Module 的特殊设置，可以过滤不需要的文件或文件夹，及处理行为
        options: {
            // 子文件名称，参见Mom Module的目录结构, components 必须指定 enabled: true 才生效
            components: {
                enabled: true
            }
        }
    }],

}
```

### 1.5.3. 过滤不需要的文件/目录

举例：

* 不需要Mom模块中的 xxxx/pages/a 目录下面的所有文件
* 不需要Mom模块中的 xxxx/b.js 文件

eg.

```js
// nuxt.config.js

export default {
    ...

    // *** 关键部分 ***
    // 可以指定哪些目录作为Mom的模块用于集成构建，更多细节，查看 `momModules` 部分
    momModules: [{
        // Mom Module 的路径
        path: "node_modules/umom-base",
        options: {
            // 子文件名称，参见Mom Module的目录结构, components 必须指定 enabled: true 才生效
            // 只对 node_modules/umom-base/pages 目录有效
            pages: { // 过滤 node_modules/umom-base/pages下面的文件及目录
                // 举例：不需要Mom模块中的 pages/a 目录下面的所有文件
                // 规则完全参照：https://www.npmjs.com/package/globby
                // 特别要注意： "!pages/a" 与 ”!pages/a/*" 同样效果，但是 "!pages/a/" 将不会起效果
                pattern: ["pages/","!pages/a"],

                // 以下是默认值    
                ... {
                    // enabled: true, // 配置是否可用
                    // patternOverwrite: false // 是否覆盖原有的内置的glob的pattern参数，覆盖的化，需要自己写pattern
                }

            }，
            ".": { // 只过滤 node_modules/umom-base/ 下面的文件，不涉及目录
              // 例如： node_modules/umom-base/ 下面，包含 a.js, b.js, c.js, d.js 四个文件，但集成的时候不需要b.js
              pattern: ['!b.js'],

                // 以下是默认值    
                ... {
                    // enabled: true, // 配置是否可用
                    // patternOverwrite: false // 是否覆盖原有的内置的glob的pattern参数，覆盖的化，需要自己写pattern
                }
            }
        }
    }],

}

```

### 1.5.4. 如何添加不在内置目录名单的目录

```js
// nuxt.config.js

export default {
    ...

    // *** 关键部分 ***
    // 是否开启Mom调试
    momDebug: false,
    // 可以指定哪些目录作为Mom的模块用于集成构建，更多细节，查看 `momModules` 部分
    momModules: [{
        // Mom Module 的路径
        path: "node_modules/@mega-apps/mom-core-vue",
        // 应用于 Mom Module 的组件前缀
        prefix: "MomCore",
        // Mom Module 的特殊设置，可以过滤不需要的文件或文件夹，及处理行为
        options: {
            // 子文件名称，参见Mom Module的目录结构
            components: {
                enabled: true,
                pattern: ["components/app-tags-view"],
                patternOverwrite: false
            }
        }
    }],

    // 将你需要参与资源整合的文件夹名称添加到下面， 例如：下面的代码
    momModuleIncludeDirNames: ["platform", "help", "doc"],

}
```

### 1.5.5. 如何变更或过滤集成到构建目录 `.nuxt_mom` 目录的文件/目录

#### 1.5.5.1. `momModuleCaseFilePatterns` 选项

`momModuleCaseFilePatterns` 选项，会影响到所有Module。

```js
// nuxt.config.js

export default {
    ...

    // *** 关键部分 ***
    // 是否开启Mom调试
    momDebug: false,
    // 可以指定哪些目录作为Mom的模块用于集成构建，更多细节，查看 `momModules` 部分
    momModules: [{
        // Mom Module 的路径
        path: "node_modules/@mega-apps/mom-core-vue",
        // 应用于 Mom Module 的组件前缀
        prefix: "MomCore",
        // Mom Module 的特殊设置，可以过滤不需要的文件或文件夹，及处理行为
        options: {
            // 子文件名称，参见Mom Module的目录结构
            components: {
                enabled: true,
                pattern: ["components/app-tags-view"],
                patternOverwrite: false
            }
        }
    }],

    // 将你要变更（新增、删除）的文件或类型添加到如下配置
    // 规则参照：https://en.wikipedia.org/wiki/Glob_(programming)
    momModuleCaseFilePatterns: ["*.md", "!../markdown"],

}
```

#### 1.5.5.2. `momModules:caseFilePatterns` 选项

`momModules:caseFilePatterns` 是指定钩子函数，用来方便根据Nuxt的状态，修改模式

```js
// nuxt.config.js

export default {
    ...

    // *** 关键部分 ***
    // 是否开启Mom调试
    momDebug: false,
    // 可以指定哪些目录作为Mom的模块用于集成构建，更多细节，查看 `momModules` 部分
    momModules: [{
        // Mom Module 的路径
        path: "node_modules/@mega-apps/mom-core-vue",
        // 应用于 Mom Module 的组件前缀
        prefix: "MomCore",
        // Mom Module 的特殊设置，可以过滤不需要的文件或文件夹，及处理行为
        options: {
            // 子文件名称，参见Mom Module的目录结构
            components: {
                enabled: true,
                pattern: ["components/app-tags-view"],
                patternOverwrite: false
            }
        }
    }],


    hooks: {
        // 将你要变更（新增、删除）的文件或类型添加到如下配置
        // 规则参照：https://en.wikipedia.org/wiki/Glob_(programming)
        "momModules:caseFilePatterns": async (patterns, nuxt) => {
            // patterns 是数组，通过变更数组的值来处理
            // 可以拿到nuxt的状态
        },
    }
}
```

### 1.5.6. 如何移除内置目录名单的目录

#### 1.5.6.1. 第一种，对所有MomModule有效

```js
// nuxt.config.js

export default {
    ...

    // *** 关键部分 ***
    // 是否开启Mom调试
    momDebug: false,
    // 可以指定哪些目录作为Mom的模块用于集成构建，更多细节，查看 `momModules` 部分
    momModules: [{
        // Mom Module 的路径
        path: "node_modules/@mega-apps/mom-core-vue",
        // 应用于 Mom Module 的组件前缀
        prefix: "MomCore",
        // Mom Module 的特殊设置，可以过滤不需要的文件或文件夹，及处理行为
        options: {
            // 子文件名称，参见Mom Module的目录结构
            components: {
                enabled: true,
                pattern: ["components/app-tags-view"],
                patternOverwrite: false
            }
        }
    }],

    // 将你需要不参与资源整合的文件夹名称添加到下面， 例如：下面的代码
    momModuleExcludeDirNames: ["app", "static", "test"],

}
```

#### 1.5.6.2. 第二种，只对某个MomModule有效

```js
// nuxt.config.js

export default {
    ...

    // *** 关键部分 ***
    // 是否开启Mom调试
    momDebug: false,
    // 可以指定哪些目录作为Mom的模块用于集成构建，更多细节，查看 `momModules` 部分
    momModules: [{
        // Mom Module 的路径
        path: "node_modules/@mega-apps/mom-core-vue",
        // 应用于 Mom Module 的组件前缀
        prefix: "MomCore",
        // Mom Module 的特殊设置，可以过滤不需要的文件或文件夹，及处理行为
        options: {
            // 子文件名称，参见Mom Module的目录结构
            components: {
                enabled: true,
                pattern: ["components/app-tags-view"],
                patternOverwrite: false
            },

            // 以下 static，app, test 目录将不参与资源集成构建
            static: {
                enabled: false
            },
            app: {
                enabled: false
            },
            test: {
                enabled: false
            },
        }
    }],
}
```

## 1.6. `components` 特性

**Note:** If using nuxt `2.10...2.13` , you have to also manually install and add `@nuxt/components` to `buildModules` inside `nuxt.config` .

**Create your components:**

```bash
| components/
---| ComponentFoo.vue
---| ComponentBar.vue
```

**Use them whenever you want, they will be auto imported in `.vue` files :**

```html
<template>
    <ComponentFoo />
    <component-bar />
</template>
```

No need anymore to manually import them in the `script` section!

See [live demo](https://codesandbox.io/s/nuxt-components-cou9k) or [video example](https://www.youtube.com/watch?v=lQ8OBrgVVr8).

### 1.6.1. Lazy Imports

Nuxt by default does code-slitting per page and components. But sometimes we also need to lazy load them:
* Component size is rather big (or has big dependencies imported) like a text-editor
* Component is rendered conditionally with `v-if` or being in a modal

In order to [lazy load](https://webpack.js.org/guides/lazy-loading/) a component, all we need to do is to add `Lazy` prefix to component name.

You now can easily import a component on-demand:

```html
<template>
    <LazyComponentFoo v-if="foo" />
    <button @click="loadFoo">
        Load Foo
    </button>
</template>

<script>
    export default {
        data() {
            return {
                foo: null
            }
        },
        methods: {
            async loadFoo() {
                this.foo = await this.$axios.$get('foo')
            }
        }
    }
</script>
```

### 1.6.2. Nested Components

If you have components in nested directories:

```bash
| components/
---| my/
---| form/
------| TextArea.vue
````

The component name will contain its path:

```html
<MyFormTextArea />
```

For clarity, it is recommended that component file name matches its name. You can also use `MyFormTextArea.vue` as name with same directory structure.

If for any reason different prefix is desired, we can add specific directory with the `prefix` option: (See [directories](#directories) section)

```js
components: [
    '~/components/',
    {
        path: '~/components/foo/',
        prefix: 'foo'
    }
]
```

### 1.6.3. Overwriting Components

It is possible to have a way to overwrite components using the [level](#level) option. This is very useful for modules and theme authors.

Considering this structure:

```bash
| node_modules/
---| my-theme/
------| components/
---------| Header.vue
| components/
---| Header.vue
```

Then defining in the `nuxt.config` :

```js
components: [
    '~/components', // default level is 0
    {
        path: 'node_modules/my-theme/components',
        level: 1
    }
]
```

Our `components/Header.vue` will overwrite our theme component since the lowest level overwrites.

更多内容可参见: [@nuxt/components](https://github.com/nuxt/components)

## 1.7. 路线

## License

[MIT](./LICENSE)