@nuxt/module-builder 0.0.0 โ†’ 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,18 +1,117 @@
1
- # Nuxt Module Builder
1
+ # ๐Ÿ“ฆ Nuxt Module Builder
2
2
 
3
- > Build Nuxt modules using [unjs/unbuild](https://github.com/unjs/unbuild).
3
+ > Complete solution to build Nuxt Modules.
4
4
 
5
- ## Usage
5
+ **๐Ÿงช This tool is still under heavy development for Nuxt3. Feedback is more than welcome!**
6
6
 
7
- - Install `@nuxt/module-builder` as a devDependency
8
- - Use `npx nuxt-build-module` to build module
7
+ ## Features
9
8
 
10
- Note: Module structure needs `src/module.ts` and optional `src/runtime/`
9
+ - Unified build with [unjs/unbuild](https://github.com/unjs/unbuild)
10
+ - Compatible with Nuxt 3 and Nuxt Kit
11
+ - Automated build config using last module spec
12
+ - Typescript and ESM support
13
+ - Auto generated CommonJS stubs
14
+ - Auto generated types and shims for `@nuxt/schema`
11
15
 
12
- ## Development
13
16
 
14
- - Clone this repository
15
- - Try changes using `yarn play` (it will build `playground/` to `playground/dist/`)
17
+ ## Project structure
18
+
19
+ Using module builder, requires a special project setup. You can check a full example [here](./example).
20
+
21
+ ### `src/module.ts`
22
+
23
+ This is the entrypoint for module definition.
24
+
25
+ A default export using `defineNuxtModule` and `ModuleOptions` type export is expected.
26
+
27
+ You could also optionally export `ModuleHooks` to annotate any custom hooks module uses.
28
+
29
+ ```js [src/module.ts]
30
+ import { defineNuxtModule } from '@nuxt/kit'
31
+
32
+ export interface ModuleOptions {
33
+ apiKey: string
34
+ }
35
+
36
+ export interface ModuleHooks {
37
+ 'my-module:init': any
38
+ }
39
+
40
+ export default defineNuxtModule<ModuleOptions>({
41
+ meta: {
42
+ name: 'my-module',
43
+ configKey: 'myModule'
44
+ },
45
+ defaults: {
46
+ apiKey: 'test'
47
+ },
48
+ async setup (moduleOptions, nuxt) {
49
+ // Write module logic in setup function
50
+ }
51
+ })
52
+ ```
53
+
54
+ ### `src/runtime/`
55
+
56
+ Any runtime file and code that we need to provide by module including plugins, composables and server api, should be in this directory.
57
+
58
+ Each file will be transformed individually using [unjs/mkdist](https://github.com/unjs/mkdist) to `dist/runtime/`.
59
+
60
+ <!-- TODO: Docs about how to address runtime from within setup -->
61
+
62
+ ### `package.json`:
63
+
64
+ A minimum `package.json` should look like this:
65
+
66
+ ```json [package.json]
67
+ {
68
+ "name": "my-module",
69
+ "license": "MIT",
70
+ "version": "1.0.0",
71
+ "exports": {
72
+ ".": {
73
+ "import": "./dist/module.mjs",
74
+ "require": "./dist/module.cjs"
75
+ }
76
+ },
77
+ "main": "./dist/module.cjs",
78
+ "types": "./dist/types.d.ts",
79
+ "files": [
80
+ "dist"
81
+ ],
82
+ "scripts": {
83
+ "prepack": "nuxt-module-build"
84
+ },
85
+ "dependencies": {
86
+ "@nuxt/kit": "npm:@nuxt/kit-edge@latest"
87
+ },
88
+ "devDependencies": {
89
+ "@nuxt/module-builder": "latest"
90
+ }
91
+ }
92
+ ```
93
+
94
+ ## Dist files
95
+
96
+ Module builder generates dist files in `dist/` directory:
97
+
98
+ - `module.mjs`: Module entrypoint build from `src/module`
99
+ - `module.json`: Module meta extracted from `module.mjs` + `package.json`
100
+ - `module.cjs`: ESM proxy to allow require module in CommonJS context
101
+ - `types.d.ts`: Exported types in addition to shims for `nuxt.config` auto completion.
102
+ - `runtime/*`: Individually transformed files using [unjs/mkdist](https://github.com/unjs/mkdist)
103
+ - Javascript and `.ts` files will be transformed to `.mjs` with extracted types on `.d.ts` file with same name
104
+ - `.vue` files will be transformed with extracted `.d.ts` file
105
+ - Other files will be copied as as
106
+
107
+
108
+
109
+ ## ๐Ÿ’ป Development
110
+
111
+ - Clone repository
112
+ - Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable` (use `npm i -g corepack` for Node.js < 16.10)
113
+ - Install dependencies using `yarn install`
114
+ - Try building [example module](./example) using `yarn example:build`
16
115
 
17
116
  ## License
18
117
 
@@ -1,10 +1,14 @@
1
- import { promises } from 'fs';
1
+ import { promises, existsSync } from 'fs';
2
+ import { pathToFileURL } from 'url';
2
3
  import { resolve } from 'pathe';
4
+ import consola from 'consola';
5
+ import { findExports } from 'mlly';
3
6
 
4
- async function buildModule(rootDir) {
7
+ async function buildModule(opts) {
5
8
  const { build } = await import('unbuild');
6
- await build(rootDir, false, {
9
+ await build(opts.rootDir, false, {
7
10
  declaration: true,
11
+ stub: opts.stub,
8
12
  entries: [
9
13
  "src/module",
10
14
  { input: "src/runtime/", outDir: "dist/runtime", ext: "mjs" }
@@ -20,19 +24,77 @@ async function buildModule(rootDir) {
20
24
  "@nuxt/kit-edge"
21
25
  ],
22
26
  hooks: {
23
- async "build:done"(ctx) {
27
+ async "rollup:done"(ctx) {
24
28
  await writeCJSStub(ctx.options.outDir);
29
+ const moduleEntryPath = resolve(ctx.options.outDir, "module.mjs");
30
+ const moduleFn = await import(pathToFileURL(moduleEntryPath).toString()).then((r) => r.default || r).catch((err) => {
31
+ consola.error(err);
32
+ consola.error("Cannot load module. Please check dist:", moduleEntryPath);
33
+ return null;
34
+ });
35
+ if (!moduleFn) {
36
+ return;
37
+ }
38
+ const moduleMeta = await moduleFn.getMeta();
39
+ if (ctx.pkg) {
40
+ if (!moduleMeta.name) {
41
+ moduleMeta.name = ctx.pkg.name;
42
+ }
43
+ if (!moduleMeta.version) {
44
+ moduleMeta.version = ctx.pkg.version;
45
+ }
46
+ }
47
+ const metaFile = resolve(ctx.options.outDir, "module.json");
48
+ await promises.writeFile(metaFile, JSON.stringify(moduleMeta, null, 2), "utf8");
49
+ await writeTypes(ctx.options.outDir, moduleMeta);
25
50
  }
26
51
  }
27
52
  });
28
53
  }
54
+ async function writeTypes(distDir, meta) {
55
+ const dtsFile = resolve(distDir, "types.d.ts");
56
+ if (existsSync(dtsFile)) {
57
+ return;
58
+ }
59
+ const moduleTypesFile = resolve(distDir, "module.d.ts");
60
+ const moduleTypes = await promises.readFile(moduleTypesFile, "utf8").catch(() => "");
61
+ const typeExports = findExports(moduleTypes);
62
+ const isStub = moduleTypes.includes("export *");
63
+ const hasModuleOptions = isStub || typeExports.find((exp) => exp.names.includes("ModuleOptions"));
64
+ const hasModuleHooks = isStub || typeExports.find((exp) => exp.names.includes("ModuleHooks"));
65
+ const schemaShims = [];
66
+ const moduleImports = [];
67
+ if (meta.configKey && hasModuleOptions) {
68
+ moduleImports.push("ModuleOptions");
69
+ schemaShims.push(` interface NuxtConfig { ['${meta.configKey}']?: Partial<ModuleOptions> }`);
70
+ schemaShims.push(` interface NuxtOptions { ['${meta.configKey}']?: ModuleOptions }`);
71
+ }
72
+ if (hasModuleHooks) {
73
+ moduleImports.push("ModuleHooks");
74
+ schemaShims.push(" interface NuxtHooks extends ModuleHooks {}");
75
+ }
76
+ const dtsContents = `
77
+ import { ${moduleImports.join(", ")} } from './module'
78
+
79
+ ${schemaShims.length ? `declare module '@nuxt/schema' {
80
+ ${schemaShims.join("\n")}
81
+ }
82
+ ` : ""}
83
+
84
+ export * from './module'
85
+ `;
86
+ await promises.writeFile(dtsFile, dtsContents, "utf8");
87
+ }
29
88
  async function writeCJSStub(distDir) {
30
89
  const cjsStubFile = resolve(distDir, "module.cjs");
31
- const cjsStub = `// CommonJS proxy to use native ESM
32
- module.exports = function(...args) {
90
+ if (existsSync(cjsStubFile)) {
91
+ return;
92
+ }
93
+ const cjsStub = `module.exports = function(...args) {
33
94
  return import('./module.mjs').then(m => m.default.call(this, ...args))
34
95
  }
35
- module.exports.meta = require('../package.json')
96
+ const _meta = module.exports.meta = require('./meta.json')
97
+ module.exports.getMeta = () => Promise.resolve(_meta)
36
98
  `;
37
99
  await promises.writeFile(cjsStubFile, cjsStub, "utf8");
38
100
  }
package/dist/cli.mjs CHANGED
@@ -1,13 +1,19 @@
1
- #!/bin/env node
1
+ #!/usr/bin/env node
2
2
  import mri from 'mri';
3
3
  import { resolve } from 'pathe';
4
4
  import { b as buildModule } from './chunks/build.mjs';
5
5
  import 'fs';
6
+ import 'url';
7
+ import 'consola';
8
+ import 'mlly';
6
9
 
7
10
  async function main() {
8
11
  const args = mri(process.argv.slice(2));
9
12
  const rootDir = resolve(args._[0] || ".");
10
- await buildModule(rootDir);
13
+ await buildModule({
14
+ rootDir,
15
+ stub: args.stub
16
+ });
11
17
  }
12
18
  main().catch((err) => {
13
19
  console.error(err);
package/dist/index.d.ts CHANGED
@@ -1,3 +1,7 @@
1
- declare function buildModule(rootDir: string): Promise<void>;
1
+ interface BuildModuleOptions {
2
+ rootDir: string;
3
+ stub?: boolean;
4
+ }
5
+ declare function buildModule(opts: BuildModuleOptions): Promise<void>;
2
6
 
3
- export { buildModule };
7
+ export { BuildModuleOptions, buildModule };
package/dist/index.mjs CHANGED
@@ -1,3 +1,6 @@
1
1
  export { b as buildModule } from './chunks/build.mjs';
2
2
  import 'fs';
3
+ import 'url';
3
4
  import 'pathe';
5
+ import 'consola';
6
+ import 'mlly';
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@nuxt/module-builder",
3
- "version": "0.0.0",
3
+ "version": "0.1.4",
4
+ "description": "Complete solution to build Nuxt Modules",
4
5
  "license": "MIT",
5
6
  "type": "module",
6
7
  "exports": {
@@ -10,28 +11,35 @@
10
11
  },
11
12
  "types": "./dist/index.d.ts",
12
13
  "bin": {
13
- "nuxt-build-module": "./dist/cli.mjs"
14
+ "nuxt-build-module": "./dist/cli.mjs",
15
+ "nuxt-module-build": "./dist/cli.mjs"
14
16
  },
17
+ "files": [
18
+ "dist"
19
+ ],
15
20
  "scripts": {
16
21
  "build": "unbuild",
17
- "cli": "jiti ./src/cli.ts",
22
+ "example:build": "yarn nuxt-module-build ./example",
18
23
  "lint": "eslint --ext .ts,.js,.mjs .",
24
+ "nuxt-module-build": "jiti ./src/cli.ts",
19
25
  "prepack": "yarn build",
20
- "play": "yarn cli ./playground",
21
26
  "release": "yarn test && standard-version && git push --follow-tags && npm publish",
22
27
  "test": "yarn lint"
23
28
  },
24
29
  "dependencies": {
30
+ "consola": "^2.15.3",
31
+ "mlly": "^0.3.19",
25
32
  "mri": "^1.2.0",
26
33
  "pathe": "^0.2.0",
27
- "unbuild": "^0.6.2"
34
+ "unbuild": "^0.6.7"
28
35
  },
29
36
  "devDependencies": {
30
37
  "@nuxt/kit": "npm:@nuxt/kit-edge@latest",
31
- "@nuxtjs/eslint-config-typescript": "^8.0.0",
32
- "@types/mri": "^1.1.1",
33
- "eslint": "^8.3.0",
38
+ "@nuxt/schema": "npm:@nuxt/schema-edge@latest",
39
+ "@nuxtjs/eslint-config-typescript": "latest",
40
+ "@types/mri": "latest",
41
+ "eslint": "latest",
34
42
  "jiti": "^1.12.9",
35
- "standard-version": "^9.3.2"
43
+ "standard-version": "latest"
36
44
  }
37
45
  }
package/.editorconfig DELETED
@@ -1,15 +0,0 @@
1
- root = true
2
-
3
- [*]
4
- end_of_line = lf
5
- insert_final_newline = true
6
- trim_trailing_whitespace = true
7
- charset = utf-8
8
-
9
- [*.js]
10
- indent_style = space
11
- indent_size = 2
12
-
13
- [{package.json,*.yml,*.cjson}]
14
- indent_style = space
15
- indent_size = 2
package/.eslintignore DELETED
@@ -1,3 +0,0 @@
1
- dist
2
- .nuxt
3
- .output
package/.eslintrc DELETED
@@ -1,5 +0,0 @@
1
- {
2
- "extends": [
3
- "@nuxtjs/eslint-config-typescript"
4
- ]
5
- }
@@ -1,23 +0,0 @@
1
- name: ci
2
-
3
- on:
4
- push:
5
- branches:
6
- - main
7
- pull_request:
8
- branches:
9
- - main
10
-
11
- jobs:
12
- ci:
13
- runs-on: ubuntu-latest
14
- steps:
15
- - uses: actions/checkout@v2
16
- - uses: actions/setup-node@v2
17
- with:
18
- node-version: 16
19
- cache: 'yarn'
20
- - run: yarn install
21
- - run: yarn lint
22
- - run: yarn build
23
- - run: yarn play
package/build.config.ts DELETED
@@ -1,12 +0,0 @@
1
- import { defineBuildConfig } from 'unbuild'
2
-
3
- export default defineBuildConfig({
4
- declaration: true,
5
- rollup: {
6
- emitCJS: false
7
- },
8
- entries: [
9
- './src/cli',
10
- './src/index'
11
- ]
12
- })
@@ -1,17 +0,0 @@
1
- {
2
- "private": true,
3
- "name": "mymodule",
4
- "main": "./dist/module.cjs",
5
- "types": "./dist/module.d.ts",
6
- "build": {
7
- "entries": [
8
- "./src/custom"
9
- ]
10
- },
11
- "exports": {
12
- ".": {
13
- "require": "./dist/module.cjs",
14
- "import": "./dist/module.mjs"
15
- }
16
- }
17
- }
@@ -1 +0,0 @@
1
- // Custom entry
@@ -1,5 +0,0 @@
1
- import { defineNuxtModule } from '@nuxt/kit'
2
-
3
- export default defineNuxtModule({
4
- setup () {}
5
- })
@@ -1,4 +0,0 @@
1
- // @ts-ignore
2
- import { defineNuxtPlugin } from '#app'
3
-
4
- export default defineNuxtPlugin((_nuxtApp) => {})
package/renovate.json DELETED
@@ -1,11 +0,0 @@
1
- {
2
- "extends": [
3
- "@nuxtjs"
4
- ],
5
- "baseBranches": [
6
- "main"
7
- ],
8
- "lockFileMaintenance": {
9
- "enabled": true
10
- }
11
- }
package/src/build.ts DELETED
@@ -1,40 +0,0 @@
1
- import { promises as fsp } from 'fs'
2
- import { resolve } from 'pathe'
3
-
4
- export async function buildModule (rootDir: string) {
5
- const { build } = await import('unbuild')
6
-
7
- await build(rootDir, false, {
8
- declaration: true,
9
- entries: [
10
- 'src/module',
11
- { input: 'src/runtime/', outDir: 'dist/runtime', ext: 'mjs' }
12
- ],
13
- rollup: {
14
- emitCJS: false,
15
- cjsBridge: true
16
- },
17
- externals: [
18
- '@nuxt/schema',
19
- '@nuxt/schema-edge',
20
- '@nuxt/kit',
21
- '@nuxt/kit-edge'
22
- ],
23
- hooks: {
24
- async 'build:done' (ctx) {
25
- await writeCJSStub(ctx.options.outDir)
26
- }
27
- }
28
- })
29
- }
30
-
31
- async function writeCJSStub (distDir: string) {
32
- const cjsStubFile = resolve(distDir, 'module.cjs')
33
- const cjsStub = `// CommonJS proxy to use native ESM
34
- module.exports = function(...args) {
35
- return import('./module.mjs').then(m => m.default.call(this, ...args))
36
- }
37
- module.exports.meta = require('../package.json')
38
- `
39
- await fsp.writeFile(cjsStubFile, cjsStub, 'utf8')
40
- }
package/src/cli.ts DELETED
@@ -1,17 +0,0 @@
1
- #!/bin/env node
2
-
3
- /* eslint-disable no-console */
4
- import mri from 'mri'
5
- import { resolve } from 'pathe'
6
- import { buildModule } from './build'
7
-
8
- async function main () {
9
- const args = mri(process.argv.slice(2))
10
- const rootDir = resolve(args._[0] || '.')
11
- await buildModule(rootDir)
12
- }
13
-
14
- main().catch((err) => {
15
- console.error(err)
16
- process.exit(1)
17
- })
package/src/index.ts DELETED
@@ -1 +0,0 @@
1
- export * from './build'
package/tsconfig.json DELETED
@@ -1,16 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "baseUrl": ".",
4
- "target": "ESNext",
5
- "module": "ESNext",
6
- "moduleResolution": "Node",
7
- "esModuleInterop": true,
8
- "declaration": true,
9
- "types": [
10
- "node"
11
- ]
12
- },
13
- "include": [
14
- "src"
15
- ]
16
- }