@zigrivers/scaffold 3.6.0 → 3.8.0
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 +127 -12
- package/content/knowledge/backend/backend-api-design.md +103 -0
- package/content/knowledge/backend/backend-architecture.md +100 -0
- package/content/knowledge/backend/backend-async-patterns.md +101 -0
- package/content/knowledge/backend/backend-auth-patterns.md +100 -0
- package/content/knowledge/backend/backend-conventions.md +105 -0
- package/content/knowledge/backend/backend-data-modeling.md +102 -0
- package/content/knowledge/backend/backend-deployment.md +100 -0
- package/content/knowledge/backend/backend-dev-environment.md +102 -0
- package/content/knowledge/backend/backend-observability.md +102 -0
- package/content/knowledge/backend/backend-project-structure.md +100 -0
- package/content/knowledge/backend/backend-requirements.md +103 -0
- package/content/knowledge/backend/backend-security.md +104 -0
- package/content/knowledge/backend/backend-testing.md +101 -0
- package/content/knowledge/backend/backend-worker-patterns.md +100 -0
- package/content/knowledge/cli/cli-architecture.md +101 -0
- package/content/knowledge/cli/cli-conventions.md +117 -0
- package/content/knowledge/cli/cli-dev-environment.md +121 -0
- package/content/knowledge/cli/cli-distribution-patterns.md +106 -0
- package/content/knowledge/cli/cli-interactivity-patterns.md +116 -0
- package/content/knowledge/cli/cli-output-patterns.md +107 -0
- package/content/knowledge/cli/cli-project-structure.md +124 -0
- package/content/knowledge/cli/cli-requirements.md +101 -0
- package/content/knowledge/cli/cli-shell-integration.md +130 -0
- package/content/knowledge/cli/cli-testing.md +134 -0
- package/content/knowledge/library/library-api-design.md +306 -0
- package/content/knowledge/library/library-architecture.md +247 -0
- package/content/knowledge/library/library-bundling.md +244 -0
- package/content/knowledge/library/library-conventions.md +229 -0
- package/content/knowledge/library/library-dev-environment.md +220 -0
- package/content/knowledge/library/library-documentation.md +300 -0
- package/content/knowledge/library/library-project-structure.md +237 -0
- package/content/knowledge/library/library-requirements.md +173 -0
- package/content/knowledge/library/library-security.md +257 -0
- package/content/knowledge/library/library-testing.md +319 -0
- package/content/knowledge/library/library-type-definitions.md +284 -0
- package/content/knowledge/library/library-versioning.md +300 -0
- package/content/knowledge/mobile-app/mobile-app-architecture.md +283 -0
- package/content/knowledge/mobile-app/mobile-app-conventions.md +180 -0
- package/content/knowledge/mobile-app/mobile-app-deployment.md +298 -0
- package/content/knowledge/mobile-app/mobile-app-dev-environment.md +257 -0
- package/content/knowledge/mobile-app/mobile-app-distribution.md +264 -0
- package/content/knowledge/mobile-app/mobile-app-observability.md +317 -0
- package/content/knowledge/mobile-app/mobile-app-offline-patterns.md +311 -0
- package/content/knowledge/mobile-app/mobile-app-project-structure.md +245 -0
- package/content/knowledge/mobile-app/mobile-app-push-notifications.md +321 -0
- package/content/knowledge/mobile-app/mobile-app-requirements.md +147 -0
- package/content/knowledge/mobile-app/mobile-app-security.md +338 -0
- package/content/knowledge/mobile-app/mobile-app-testing.md +400 -0
- package/content/knowledge/web-app/web-app-api-patterns.md +224 -0
- package/content/knowledge/web-app/web-app-architecture.md +116 -0
- package/content/knowledge/web-app/web-app-auth-patterns.md +256 -0
- package/content/knowledge/web-app/web-app-conventions.md +121 -0
- package/content/knowledge/web-app/web-app-data-patterns.md +218 -0
- package/content/knowledge/web-app/web-app-deployment-workflow.md +143 -0
- package/content/knowledge/web-app/web-app-deployment.md +134 -0
- package/content/knowledge/web-app/web-app-design-system.md +158 -0
- package/content/knowledge/web-app/web-app-dev-environment.md +173 -0
- package/content/knowledge/web-app/web-app-observability.md +221 -0
- package/content/knowledge/web-app/web-app-project-structure.md +160 -0
- package/content/knowledge/web-app/web-app-rendering-strategies.md +133 -0
- package/content/knowledge/web-app/web-app-requirements.md +112 -0
- package/content/knowledge/web-app/web-app-security.md +193 -0
- package/content/knowledge/web-app/web-app-session-patterns.md +214 -0
- package/content/knowledge/web-app/web-app-testing.md +249 -0
- package/content/knowledge/web-app/web-app-ux-patterns.md +162 -0
- package/content/methodology/backend-overlay.yml +73 -0
- package/content/methodology/cli-overlay.yml +69 -0
- package/content/methodology/library-overlay.yml +67 -0
- package/content/methodology/mobile-app-overlay.yml +71 -0
- package/content/methodology/web-app-overlay.yml +79 -0
- package/dist/cli/commands/init.d.ts +21 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +261 -13
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/init.test.js +206 -0
- package/dist/cli/commands/init.test.js.map +1 -1
- package/dist/config/schema.d.ts +1392 -64
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +82 -5
- package/dist/config/schema.js.map +1 -1
- package/dist/config/schema.test.js +302 -1
- package/dist/config/schema.test.js.map +1 -1
- package/dist/core/assembly/overlay-loader.d.ts.map +1 -1
- package/dist/core/assembly/overlay-loader.js +2 -1
- package/dist/core/assembly/overlay-loader.js.map +1 -1
- package/dist/core/assembly/overlay-loader.test.js +56 -0
- package/dist/core/assembly/overlay-loader.test.js.map +1 -1
- package/dist/e2e/game-pipeline.test.js +1 -0
- package/dist/e2e/game-pipeline.test.js.map +1 -1
- package/dist/e2e/project-type-overlays.test.d.ts +16 -0
- package/dist/e2e/project-type-overlays.test.d.ts.map +1 -0
- package/dist/e2e/project-type-overlays.test.js +834 -0
- package/dist/e2e/project-type-overlays.test.js.map +1 -0
- package/dist/types/config.d.ts +19 -2
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +0 -1
- package/dist/types/index.js.map +1 -1
- package/dist/wizard/questions.d.ts +27 -1
- package/dist/wizard/questions.d.ts.map +1 -1
- package/dist/wizard/questions.js +142 -3
- package/dist/wizard/questions.js.map +1 -1
- package/dist/wizard/questions.test.js +206 -8
- package/dist/wizard/questions.test.js.map +1 -1
- package/dist/wizard/wizard.d.ts +21 -0
- package/dist/wizard/wizard.d.ts.map +1 -1
- package/dist/wizard/wizard.js +27 -1
- package/dist/wizard/wizard.js.map +1 -1
- package/package.json +1 -1
- package/dist/types/wizard.d.ts +0 -14
- package/dist/types/wizard.d.ts.map +0 -1
- package/dist/types/wizard.js +0 -2
- package/dist/types/wizard.js.map +0 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: library-conventions
|
|
3
|
+
description: Public API naming, deprecation patterns, changelog conventions, and export patterns for published libraries
|
|
4
|
+
topics: [library, conventions, naming, deprecation, changelog, exports, api-design]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Library conventions are the agreements that make a library predictable, navigable, and trustworthy across versions. They cover how public APIs are named, how deprecated APIs are marked and eventually removed, how changes are communicated through changelogs, and how exports are structured. Inconsistent conventions are a tax on every consumer — they create confusion about what is stable, what is safe to use, and what changed between versions.
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
Establish and document conventions before publishing v1. Key areas: consistent naming patterns (verbs for functions, nouns for types/classes, `is`/`has` for predicates), deprecation lifecycle with JSDoc markers and migration guidance, changelog format (Keep a Changelog or Conventional Commits), and export structure that makes tree-shaking possible. Internal exports must be clearly separated from public exports to avoid accidental API surface expansion.
|
|
12
|
+
|
|
13
|
+
Core conventions:
|
|
14
|
+
- Functions: verb-noun (`parseConfig`, `validateSchema`, `createClient`)
|
|
15
|
+
- Types/interfaces: PascalCase nouns (`ParseOptions`, `ClientConfig`, `ValidationError`)
|
|
16
|
+
- Predicates: `is` prefix (`isError`, `isValidConfig`)
|
|
17
|
+
- Constants: SCREAMING_SNAKE for module-level, camelCase for config object keys
|
|
18
|
+
- Deprecation: JSDoc `@deprecated` + replacement reference + removal version
|
|
19
|
+
- Changelog: per-version sections with Added / Changed / Deprecated / Removed / Fixed / Security
|
|
20
|
+
|
|
21
|
+
## Deep Guidance
|
|
22
|
+
|
|
23
|
+
### Public API Naming
|
|
24
|
+
|
|
25
|
+
Naming is the most visible part of the API contract. Inconsistency in naming signals immaturity and creates cognitive load for consumers.
|
|
26
|
+
|
|
27
|
+
**Functions — verb-noun pattern:**
|
|
28
|
+
```typescript
|
|
29
|
+
// Good: verb-noun, action is clear
|
|
30
|
+
parseConfig(input: string): Config
|
|
31
|
+
validateSchema(schema: Schema): ValidationResult
|
|
32
|
+
createClient(options: ClientOptions): Client
|
|
33
|
+
formatError(error: unknown): string
|
|
34
|
+
resolveModulePath(specifier: string): string
|
|
35
|
+
|
|
36
|
+
// Bad: ambiguous, no verb, or inverted
|
|
37
|
+
config(input: string): Config // what does it do?
|
|
38
|
+
schemaValidator(schema: Schema): ... // -or suffix is not a function verb
|
|
39
|
+
client(options: ClientOptions): ... // noun-only looks like a constructor
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Types and interfaces — PascalCase nouns:**
|
|
43
|
+
```typescript
|
|
44
|
+
// Good
|
|
45
|
+
interface ParseOptions { ... }
|
|
46
|
+
type ValidationResult = { valid: boolean; errors: ValidationError[] }
|
|
47
|
+
class ConfigClient { ... }
|
|
48
|
+
type ErrorCode = 'NOT_FOUND' | 'INVALID' | 'TIMEOUT'
|
|
49
|
+
|
|
50
|
+
// Bad
|
|
51
|
+
interface parseOptions { ... } // lowercase
|
|
52
|
+
type validation_result = ... // snake_case
|
|
53
|
+
type ErrCode = ... // abbreviation
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Predicates — `is` prefix:**
|
|
57
|
+
```typescript
|
|
58
|
+
function isError(value: unknown): value is Error
|
|
59
|
+
function isValidConfig(config: unknown): config is Config
|
|
60
|
+
function hasRequiredFields(obj: unknown): boolean // 'has' for possession checks
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Boolean options — avoid double negatives:**
|
|
64
|
+
```typescript
|
|
65
|
+
// Good
|
|
66
|
+
interface Options {
|
|
67
|
+
strict: boolean // enable strict mode
|
|
68
|
+
cache: boolean // enable caching
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Bad
|
|
72
|
+
interface Options {
|
|
73
|
+
noStrict: boolean // double negative when true disables
|
|
74
|
+
disableCache: boolean // confusing when combined: disableCache: false
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Error types — descriptive, namespace-prefixed:**
|
|
79
|
+
```typescript
|
|
80
|
+
// Good: namespaced, descriptive
|
|
81
|
+
class ParseError extends Error {
|
|
82
|
+
constructor(message: string, public readonly line: number, public readonly col: number) {
|
|
83
|
+
super(message)
|
|
84
|
+
this.name = 'ParseError'
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Available as named export:
|
|
89
|
+
export { ParseError, ValidationError, NetworkError, TimeoutError }
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Deprecation Lifecycle
|
|
93
|
+
|
|
94
|
+
Deprecation is a promise to consumers: "this still works today, but plan to migrate." It must be communicated at multiple levels.
|
|
95
|
+
|
|
96
|
+
**Step 1: Add `@deprecated` JSDoc in a MINOR release:**
|
|
97
|
+
```typescript
|
|
98
|
+
/**
|
|
99
|
+
* Parse a configuration string.
|
|
100
|
+
* @deprecated Use `parseConfig()` instead. Will be removed in v3.0.
|
|
101
|
+
* @see parseConfig
|
|
102
|
+
*/
|
|
103
|
+
export function parse(input: string): Config {
|
|
104
|
+
return parseConfig(input)
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The `@deprecated` tag causes TypeScript to show strikethrough in IDEs and emit warnings. Always include:
|
|
109
|
+
- What to use instead
|
|
110
|
+
- When it will be removed (target major version)
|
|
111
|
+
|
|
112
|
+
**Step 2: Log a runtime warning (optional, for JS users without TypeScript):**
|
|
113
|
+
```typescript
|
|
114
|
+
export function parse(input: string): Config {
|
|
115
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
116
|
+
console.warn(
|
|
117
|
+
'[my-library] parse() is deprecated. Use parseConfig() instead. ' +
|
|
118
|
+
'Will be removed in v3.0. See migration guide: https://example.com/v3-migration'
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
return parseConfig(input)
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Only add runtime warnings if the library has significant JS (non-TypeScript) consumers. Don't pollute production logs.
|
|
126
|
+
|
|
127
|
+
**Step 3: Remove in the next major version:**
|
|
128
|
+
- Remove the export entirely
|
|
129
|
+
- Add a clear CHANGELOG entry with migration instructions
|
|
130
|
+
- Include migration guide link in the changelog entry
|
|
131
|
+
|
|
132
|
+
**Deprecation period policy:**
|
|
133
|
+
The minimum deprecation period before removal should be one full major version. If you deprecate in v2.3, the earliest removal is v3.0. Communicate the removal version at deprecation time.
|
|
134
|
+
|
|
135
|
+
### Changelog Conventions
|
|
136
|
+
|
|
137
|
+
Follow the [Keep a Changelog](https://keepachangelog.com) format. Every release must have a changelog entry before publishing.
|
|
138
|
+
|
|
139
|
+
**Format:**
|
|
140
|
+
```markdown
|
|
141
|
+
# Changelog
|
|
142
|
+
|
|
143
|
+
## [Unreleased]
|
|
144
|
+
|
|
145
|
+
## [2.1.0] - 2024-03-15
|
|
146
|
+
|
|
147
|
+
### Added
|
|
148
|
+
- `parseConfig()` function as the new primary parsing API
|
|
149
|
+
- `ParseOptions.strict` flag for strict mode validation
|
|
150
|
+
|
|
151
|
+
### Changed
|
|
152
|
+
- `createClient()` now accepts `ClientOptions.timeout` in milliseconds (previously seconds)
|
|
153
|
+
|
|
154
|
+
### Deprecated
|
|
155
|
+
- `parse()` — use `parseConfig()` instead. Will be removed in v3.0.
|
|
156
|
+
|
|
157
|
+
### Fixed
|
|
158
|
+
- `validateSchema()` no longer throws on empty input; returns `{ valid: false, errors: [] }`
|
|
159
|
+
|
|
160
|
+
## [2.0.0] - 2024-01-10
|
|
161
|
+
|
|
162
|
+
### Breaking Changes
|
|
163
|
+
- Removed `connect()` (deprecated since v1.5.0). Use `createClient()`.
|
|
164
|
+
- `Config.timeout` is now in milliseconds (was seconds in v1.x). Multiply existing values by 1000.
|
|
165
|
+
|
|
166
|
+
### Migration from v1.x
|
|
167
|
+
See: https://example.com/v2-migration
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Rules:
|
|
171
|
+
- Every entry in "Breaking Changes" must have a migration instruction or link
|
|
172
|
+
- "Added" entries must reference the new API by name
|
|
173
|
+
- "Fixed" entries must describe the incorrect behavior and the correct behavior
|
|
174
|
+
- Never put vague entries like "Various bug fixes" — enumerate them
|
|
175
|
+
|
|
176
|
+
### Export Patterns
|
|
177
|
+
|
|
178
|
+
How you structure exports determines your tree-shaking story and your public API surface.
|
|
179
|
+
|
|
180
|
+
**Root index.ts — explicit, intentional exports only:**
|
|
181
|
+
```typescript
|
|
182
|
+
// src/index.ts
|
|
183
|
+
// Public API — these are the semver-protected exports
|
|
184
|
+
|
|
185
|
+
// Core functions
|
|
186
|
+
export { parseConfig } from './parser'
|
|
187
|
+
export { validateSchema } from './validator'
|
|
188
|
+
export { createClient } from './client'
|
|
189
|
+
|
|
190
|
+
// Types
|
|
191
|
+
export type { ParseOptions, ParseResult } from './parser'
|
|
192
|
+
export type { ValidationResult, ValidationError } from './validator'
|
|
193
|
+
export type { ClientOptions, Client } from './client'
|
|
194
|
+
|
|
195
|
+
// Error types
|
|
196
|
+
export { ParseError, ValidationError as LibValidationError } from './errors'
|
|
197
|
+
|
|
198
|
+
// DO NOT export internal utilities
|
|
199
|
+
// DO NOT re-export everything with `export * from './...'`
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Avoid `export *` at the root:** It makes the API surface opaque and causes accidental exports of internal symbols.
|
|
203
|
+
|
|
204
|
+
**Subpath exports for optional features:**
|
|
205
|
+
```typescript
|
|
206
|
+
// package.json exports map (see library-bundling.md for full config)
|
|
207
|
+
{
|
|
208
|
+
"exports": {
|
|
209
|
+
".": "./dist/index.js",
|
|
210
|
+
"./plugins": "./dist/plugins/index.js",
|
|
211
|
+
"./testing": "./dist/testing/index.js"
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Consumers who don't use plugins pay zero bundle cost. Testing utilities stay separate from production code.
|
|
217
|
+
|
|
218
|
+
**Barrel files — use sparingly:**
|
|
219
|
+
Barrel files (files that re-export from many modules) can defeat tree-shaking in some bundlers. Prefer deep imports in internal code; use the root barrel only for the public API.
|
|
220
|
+
|
|
221
|
+
### Convention Documentation
|
|
222
|
+
|
|
223
|
+
Every library must have a `CONTRIBUTING.md` or `docs/conventions.md` documenting:
|
|
224
|
+
1. Naming conventions for new API additions
|
|
225
|
+
2. Deprecation lifecycle steps (checklist format)
|
|
226
|
+
3. Changelog update requirement (must update before PR merges)
|
|
227
|
+
4. Export checklist for new public APIs
|
|
228
|
+
|
|
229
|
+
Without documented conventions, contributors add APIs inconsistently, and the library accumulates naming debt that is expensive to fix without breaking changes.
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: library-dev-environment
|
|
3
|
+
description: Monorepo setup, npm link workflow, build watch mode, and local consumer testing for library development
|
|
4
|
+
topics: [library, dev-environment, monorepo, npm-link, build-watch, local-testing]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Library development environment setup is distinct from application development: you are building code that will be consumed by other projects, which means your dev workflow must include a way to test the library as a consumer would — before publishing to npm. The feedback loop between changing library source and seeing the effect in a consumer application is the central challenge. Get this wrong, and you spend hours debugging issues that only surface after publish.
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
Use build watch mode (TypeScript `--watch` or a bundler watcher) for fast feedback during development. For testing in a real consumer project, use `npm link` or workspace-relative `file:` references. In monorepos, use npm/pnpm/yarn workspaces to co-locate the library and consumer apps. Never develop library code exclusively through unit tests — always validate through a real consumer context. Set up scripts for the full dev loop: `build:watch` in one terminal, consumer app in another.
|
|
12
|
+
|
|
13
|
+
Core workflow tools:
|
|
14
|
+
- `tsc --watch` for TypeScript compilation feedback
|
|
15
|
+
- `npm link` / `pnpm link` for local cross-project testing
|
|
16
|
+
- Workspace `file:` references for monorepo consumers
|
|
17
|
+
- `npm pack` + install for pre-publish verification
|
|
18
|
+
|
|
19
|
+
## Deep Guidance
|
|
20
|
+
|
|
21
|
+
### Build Watch Mode
|
|
22
|
+
|
|
23
|
+
The development feedback loop starts with build watch mode. TypeScript's `--watch` mode recompiles on every save:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Terminal 1: watch the library build
|
|
27
|
+
npm run build:watch
|
|
28
|
+
|
|
29
|
+
# package.json script:
|
|
30
|
+
"build:watch": "tsc -p tsconfig.json --watch --preserveWatchOutput"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
For more complex builds (bundling, multiple outputs), use a bundler watcher:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# With tsup (recommended for dual ESM/CJS builds)
|
|
37
|
+
"build:watch": "tsup --watch"
|
|
38
|
+
|
|
39
|
+
# tsup.config.ts
|
|
40
|
+
import { defineConfig } from 'tsup'
|
|
41
|
+
|
|
42
|
+
export default defineConfig({
|
|
43
|
+
entry: ['src/index.ts'],
|
|
44
|
+
format: ['esm', 'cjs'],
|
|
45
|
+
dts: true,
|
|
46
|
+
sourcemap: true,
|
|
47
|
+
clean: true,
|
|
48
|
+
watch: process.env.WATCH === 'true'
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
TypeScript `--watch` alone is sufficient for type-only changes. If you're bundling (minifying, inlining), use the bundler's watch mode.
|
|
53
|
+
|
|
54
|
+
### npm link Workflow
|
|
55
|
+
|
|
56
|
+
`npm link` creates a symlink from your global npm prefix to the library, then links that into the consuming project:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# In the library directory:
|
|
60
|
+
cd my-library
|
|
61
|
+
npm link
|
|
62
|
+
# Creates: ~/.nvm/versions/node/vX/lib/node_modules/my-library -> /path/to/my-library
|
|
63
|
+
|
|
64
|
+
# In the consuming project:
|
|
65
|
+
cd my-app
|
|
66
|
+
npm link my-library
|
|
67
|
+
# Creates: my-app/node_modules/my-library -> ~/.nvm/.../my-library
|
|
68
|
+
|
|
69
|
+
# The consumer now uses the live dist/ from the library
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Caveats with npm link:**
|
|
73
|
+
- The consumer uses the `dist/` directory, so the library must be built first and kept rebuilt via watch mode
|
|
74
|
+
- React and other singleton libraries can cause issues because the library and consumer may each resolve their own copy: use `npm link my-app/node_modules/react` inside the library to force shared resolution
|
|
75
|
+
- `npm install` in the consumer will break the link — you must re-run `npm link my-library`
|
|
76
|
+
|
|
77
|
+
**Preferred alternative: `file:` reference in consumer:**
|
|
78
|
+
```json
|
|
79
|
+
// my-app/package.json
|
|
80
|
+
{
|
|
81
|
+
"dependencies": {
|
|
82
|
+
"my-library": "file:../my-library"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Run `npm install` in `my-app`. This creates a symlink into `my-library/` respecting the `exports` map. Survives `npm install` (unlike `npm link`). Requires the library to have its `dist/` built.
|
|
88
|
+
|
|
89
|
+
### pnpm Workspace Setup (Recommended for Monorepos)
|
|
90
|
+
|
|
91
|
+
pnpm workspaces handle library + consumer in the same repository without symlink complexity:
|
|
92
|
+
|
|
93
|
+
```yaml
|
|
94
|
+
# pnpm-workspace.yaml (at monorepo root)
|
|
95
|
+
packages:
|
|
96
|
+
- 'packages/*'
|
|
97
|
+
- 'apps/*'
|
|
98
|
+
- 'examples/*'
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
monorepo/
|
|
103
|
+
├── packages/
|
|
104
|
+
│ └── my-library/
|
|
105
|
+
│ ├── src/
|
|
106
|
+
│ ├── dist/
|
|
107
|
+
│ └── package.json # name: "my-library"
|
|
108
|
+
├── apps/
|
|
109
|
+
│ └── my-app/
|
|
110
|
+
│ └── package.json # depends on "my-library": "workspace:*"
|
|
111
|
+
└── pnpm-workspace.yaml
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
// apps/my-app/package.json
|
|
116
|
+
{
|
|
117
|
+
"dependencies": {
|
|
118
|
+
"my-library": "workspace:*"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
With `workspace:*`, pnpm links to the local package automatically. The `dist/` directory is used (respecting `exports` map), so the library still needs to be built.
|
|
124
|
+
|
|
125
|
+
**Monorepo dev script:**
|
|
126
|
+
```bash
|
|
127
|
+
# Run both library watch and app dev server in parallel
|
|
128
|
+
"dev": "concurrently \"npm run build:watch -w packages/my-library\" \"npm run dev -w apps/my-app\""
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Pre-publish Verification with npm pack
|
|
132
|
+
|
|
133
|
+
Before publishing, verify the actual package contents:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# Pack the library without publishing
|
|
137
|
+
npm pack --dry-run
|
|
138
|
+
|
|
139
|
+
# This shows exactly what files will be included in the published package
|
|
140
|
+
# Look for:
|
|
141
|
+
# - dist/ files present (ESM, CJS, .d.ts)
|
|
142
|
+
# - No src/ files (source not published)
|
|
143
|
+
# - No test files
|
|
144
|
+
# - README.md and CHANGELOG.md present
|
|
145
|
+
# - No .env or secrets
|
|
146
|
+
|
|
147
|
+
# Pack to a tarball and install it in a test project
|
|
148
|
+
npm pack
|
|
149
|
+
# Creates: my-library-1.0.0.tgz
|
|
150
|
+
|
|
151
|
+
# In a fresh test project:
|
|
152
|
+
npm install ../my-library/my-library-1.0.0.tgz
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Installing the tarball is the most faithful pre-publish test. It reproduces exactly what consumers get from `npm install my-library`.
|
|
156
|
+
|
|
157
|
+
### Dev Dependencies vs. Build Dependencies
|
|
158
|
+
|
|
159
|
+
Keep the dev environment fast by understanding what belongs where:
|
|
160
|
+
|
|
161
|
+
**devDependencies** (not published):
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"devDependencies": {
|
|
165
|
+
"typescript": "^5.4.0", // Build tool
|
|
166
|
+
"tsup": "^8.0.0", // Bundler
|
|
167
|
+
"vitest": "^1.4.0", // Test runner
|
|
168
|
+
"tsd": "^0.31.0", // Type testing
|
|
169
|
+
"typedoc": "^0.25.0", // Doc generation
|
|
170
|
+
"eslint": "^8.57.0", // Linter
|
|
171
|
+
"prettier": "^3.2.0", // Formatter
|
|
172
|
+
"concurrently": "^8.2.0", // Parallel scripts
|
|
173
|
+
"rimraf": "^5.0.0" // Cross-platform rm -rf
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**dependencies** (installed by consumers):
|
|
179
|
+
Only runtime dependencies that the library code imports at runtime. Keep this list minimal. Every dependency you add becomes a consumer's dependency. Prefer zero runtime dependencies for utility libraries.
|
|
180
|
+
|
|
181
|
+
**peerDependencies**:
|
|
182
|
+
Framework dependencies the consumer is expected to provide (React, Vue, etc.).
|
|
183
|
+
|
|
184
|
+
### Environment Variables for Dev
|
|
185
|
+
|
|
186
|
+
Libraries should not read environment variables at runtime (that's the consumer's responsibility). But the build process may need them:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# .env.local (gitignored) — only for build/test scripts
|
|
190
|
+
NPM_REGISTRY=https://registry.npmjs.org
|
|
191
|
+
TYPEDOC_TOKEN=... # for doc deployment
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Document any required environment variables in `docs/dev-setup.md`. Never hardcode registry URLs or tokens.
|
|
195
|
+
|
|
196
|
+
### Recommended package.json Dev Scripts
|
|
197
|
+
|
|
198
|
+
```json
|
|
199
|
+
{
|
|
200
|
+
"scripts": {
|
|
201
|
+
"build": "rimraf dist && tsup",
|
|
202
|
+
"build:watch": "tsup --watch",
|
|
203
|
+
"dev": "npm run build:watch",
|
|
204
|
+
"test": "vitest run",
|
|
205
|
+
"test:watch": "vitest",
|
|
206
|
+
"test:types": "tsd",
|
|
207
|
+
"test:coverage": "vitest run --coverage",
|
|
208
|
+
"test:examples": "node examples/basic-usage/index.js",
|
|
209
|
+
"lint": "eslint src/ tests/",
|
|
210
|
+
"format": "prettier --write src/ tests/",
|
|
211
|
+
"typecheck": "tsc --noEmit -p tsconfig.dev.json",
|
|
212
|
+
"docs": "typedoc",
|
|
213
|
+
"pack:dry": "npm pack --dry-run",
|
|
214
|
+
"prepublishOnly": "npm run build && npm run test && npm run test:types",
|
|
215
|
+
"clean": "rimraf dist"
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
The `prepublishOnly` script is a safety net — it runs automatically before `npm publish` and blocks publishing if tests fail.
|