@mrpelz/boilerplate-node 12.5.1 → 13.0.1

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.
Files changed (2) hide show
  1. package/README.md +381 -0
  2. package/package.json +1 -1
package/README.md ADDED
@@ -0,0 +1,381 @@
1
+ # `@mrpelz/boilerplate-node`
2
+
3
+ Easily start new TypeScript-based projects using a modular and extensible toolset.
4
+ This boilerplate tries to provide opinionated defaults for everyday-use while handling common pitfalls for edge-cases. If your edge-case is too special, it won’t prescribe a fixed configuration, always allowing a route to customization without all-or-nothing breakout.
5
+
6
+ ## Philosophy
7
+
8
+ ### Updatability vs. Customization
9
+
10
+ Boilerplates that want to offer developers a good experience in the long-term have to balance two interests: Updatability and customization.
11
+
12
+ Customization is necessary so that the boilerplate can cover as little edge cases as possible while concentrating its defaults on the essentials. Instead of offering a solution for every possible peculiarity of a given project, developers should always have the option to add their own configuration parameters or redefine entire sections.
13
+
14
+ Updatability ensures that the boilerplate can reflect changing best practices over time, even after the initial installation.
15
+
16
+ ### The Problem with Configuration Templates
17
+
18
+ Boilerplates that define configuration files via a template system can offer a streamlined initial installation thanks to the standardized production of all project files.
19
+ However, if a developer modifies one of the produced files after the installation (e.g. to handle a very special project setup), the boilerplate’s next update will either overwrite this per-project customization or not update the affected file at all, possibly creating breaking changes in conjunction with other updated configuration files.
20
+
21
+ ### How to Facilitate Customization/Abandoning Updates After Initial Install
22
+
23
+ Keeping production of configuration files confined to a template system, this “customization and update problem” can only be solved by either abstracting the tooling to such an extent that customizations also need to happen within the abstraction (thus creating user lock-in and mental overhead translating and maintaining the customizations), or at the other extreme, by only setting up a new project environment at the time of initial install, leaving developers to their own devices for subsequent updates and requiring them to replicate changes to the boilerplate on their own.
24
+
25
+ ### No Configuration Templates
26
+
27
+ Instead of using a template system for all config files, this boilerplate uses the extension mechanism provided by the given tool, provides its default configurations as artifacts within the NPM package and generates skeleton configs importing (or otherwise referencing) these artifacts. For non-extensible files it creates symlinks with proper relative path-handling.
28
+
29
+ For configurations handled through skeleton files, customization is easily done by recomposing configuration options with the always updated defaults referenced from the package.
30
+
31
+ For the very few symlinked configs, the user can choose to stick with the updated default or move to a fully-custom file maintained at the project’s discretion. (Re)running a bootstrap script allows for easy restore of previously customized files, if a project withes to return to a tool’s provided default config.
32
+
33
+ ## NPM-Package
34
+
35
+ Provides the configuration basis for NodeJS-based projects, i.e. for libraries or applications that run exclusively server-side.
36
+
37
+ ### Features
38
+
39
+ * TypeScript-config to output native ESM-modules
40
+ * produce sourcemaps
41
+ * lint and typecheck sourcecode with amendable defaults using ESLint
42
+ * lint and typecheck configurations defined as code (e.g. `eslint.config.js`)
43
+ * run unit tests using a TypeScript- and ESM-compatible basic Jest setup
44
+ * enforce commit message formatting using Commitlint
45
+ * enforce package.json matching repository attributes, e.g. name, version, repository fields, key sorting
46
+ * .editorconfig to match other tools’ settings
47
+ * VSCode project-settings and -extension suggestions to match tooling
48
+ * lint Bash-scripts using Shellcheck
49
+ * derive package versions from git tags and automatically handle prerelease-versioning in a feature-branch workflow
50
+ * Tmux niceties to help keep watch on all lint/check tasks during development
51
+ * use NodeJS’s native watch-feature to restart execution on code change (without leaving zombie-processes behind)
52
+ * GitLab-CI pipelines
53
+ * to run relevant checks on every change pushed to a merge request
54
+ * manually trigger (pre-)release tagging after checks complete
55
+ (no guessing breaking-changes from commit messages, press the appropriate play-button for pre-, patch-, minor- or major-release tagging after check-pipeline completes)
56
+ * produce NPM-packages on release and publish to GitLab package-registry
57
+ * comment prerelease-info to merge requests
58
+ * produce Docker-images on release and publish to GitLab image-registry
59
+
60
+ ## Usage
61
+
62
+ > **ℹ️ Opinion**
63
+ > This Readme provides examples for `npm`.
64
+ >
65
+ > The supporting scripts all use `npm` internally.
66
+ Feel free to change them in your project to use `yarn`, `pnpm` or something else, but as long as you want to use this boilerplate as-is, stick to `npm`.
67
+
68
+ ### Prerequisites
69
+
70
+ * `node` and `npm` installed
71
+ * (optionally) `git` installed and set up
72
+ * (GNU!) `make`, `sed`, `tmux` and `xargs` installed
73
+ > This boilerplate uses `make` for task orchestration. In order to compose Makefiles from NPM-dependency artifacts, **GNU**-Make is a strict necessity.
74
+ >
75
+ > In order to compose Makefiles from NPM-dependency artifacts, *GNU*-Make is a strict necessity. If you’re using macOS, install using `brew install make` and amend your `$PATH` to use GNU-Make by default (e.g. by putting
76
+ > ```bash
77
+ > PATH="$HOMEBREW_PREFIX/opt/make/libexec/gnubin:$PATH"
78
+ > ```
79
+ > to your `.zshrc`).
80
+ * (GNU!) `ln` installed
81
+ > Some config files cannot be natively extended and need to be symlinked to the boilerplate’s default. This ensures new defaults apply when the boilerplate is updated. In order to keep the project root portable across different developers’ environments, symlinks need to use relative paths, which unfortunately is only a feature in the `ln` utility from GNU-Coreutils. If you’re using macOS, install using `brew install coreutils` and amend your `$PATH` to use GNU-Coreutils by default (e.g. by putting
82
+ > ```bash
83
+ > PATH="$HOMEBREW_PREFIX/opt/coreutils/libexec/gnubin:$PATH"
84
+ > ```
85
+ > to your `.zshrc`).
86
+
87
+ ### 1. Optionally Create Environment First
88
+
89
+ ```bash
90
+ # create project directory
91
+ mkdir new-project
92
+
93
+ # change into the just created directory
94
+ cd !:1
95
+ # ⬆️ recall the first argument (`new-project`) from last command
96
+
97
+ # (optionally) initialize git repository
98
+ git init
99
+
100
+ # initialize npm module
101
+ npm init # you can just rush through this, most of the `package.json` will be fitted with proper values later
102
+ ```
103
+
104
+ ### 2. Add `boilerplate-node` to your Project
105
+
106
+ ```bash
107
+ # add module as dev-dependency
108
+ npm install --save-dev @mrpelz/boilerplate-node
109
+ ```
110
+
111
+ ### 3. Run Bootstrap Script
112
+
113
+ ```bash
114
+ # use `npm exec` to call CLIs exposed in `node_modules/.bin`
115
+ npm exec boilerplate-node-bootstrap
116
+ ```
117
+
118
+ Running the script without any arguments will walk you through the process of creating config file symlinks or skeletons step by step, allowing you to review what will be done for each file and confirming it separately:
119
+
120
+ ```bash
121
+ ℹ running with "@mrpelz/boilerplate-node" as dependency
122
+ ❓ 🖇 install symbolic links referencing files in "@mrpelz/boilerplate-node"?
123
+ ❔ [Y/n]
124
+ ```
125
+
126
+ Whenever you are prompted, you can just hit enter to select the capitalized default option or choose `y`/`n`.
127
+
128
+ Prompts for creating a symlink look like this:
129
+
130
+ ```bash
131
+ [SYMBOLIC LINK] "<file name>"
132
+ ❓ 🔗 add symbolic link "<file name>" (pointing to target "<target>") to "<directory>" in "<project root>"?
133
+ ❔ [Y/n]
134
+ ```
135
+
136
+ Prompts for creating config files look like this:
137
+
138
+ ```bash
139
+ [CONFIG FILE] "<file name>"
140
+ 🆕 new file contents:
141
+ <file contents>
142
+ ❓ 📄 add config file "<file name>" to "<directory>" in "<project root>"?
143
+ ❔ [Y/n]
144
+ ```
145
+
146
+ #### Automatically Selecting Responses
147
+
148
+ `boilerplate-node-bootstrap` can be called with an argument of `y`, `n` or `d`, always selecting yes, no or the default (capitalized) response for each prompt:
149
+
150
+ ```bash
151
+ npm exec boilerplate-node-bootstrap y
152
+ ```
153
+
154
+ ## Scripts
155
+
156
+ > **ℹ️ Opinion**
157
+ >
158
+ > This boilerplate uses `make` for task orchestration instead of stringing together multiple NPM scripts.
159
+ > Make is exactly designed for this purpose while NPM scripts are hard to compose, reuse and are just a byproduct of custom package-lifecycle hook scripts.
160
+
161
+ ### Calling a make target:
162
+
163
+ ```bash
164
+ make <target>
165
+ ```
166
+
167
+ > **ℹ️ Good to know**
168
+ >
169
+ > In order to get autocompletion working in ZSH, add
170
+ > ```bash
171
+ > zstyle ':completion:*:make:*:targets' call-command true
172
+ > zstyle ':completion:*:*:make:*' tag-order 'targets'
173
+ > ```
174
+ > to your `.zshrc`.
175
+
176
+ > **ℹ️ Good to know III**
177
+ >
178
+ > The boilerplate tries to handle “monorepos”.
179
+ > For the purpose of this ReadMe, “root package” is the package that contains NPM workspace definitions and the packages within those workspaces are called “sub packages”.
180
+ >
181
+ > When running a target from the root package, the target automatically runs for all sub packages/workspaces (`packages`) if that makes sense for the given target.
182
+ > You can change the sub package location by overwriting `SUB_PACKAGE_DIR` in your skeleton Makefile.
183
+ >
184
+ > If you want to run a target only for the root package, call make with `include_sub_packages=false`, e.g.:
185
+ > ```bash
186
+ > make check_lint include_sub_packages=false
187
+ > ```
188
+
189
+ ## Check
190
+
191
+ ### `make check`
192
+
193
+ Run all of:
194
+
195
+ * `check_commit`
196
+ * `check_package_json`
197
+ * `check_lint`
198
+ * `check_config`
199
+ * `check_typescript`
200
+ * `check_test`
201
+
202
+ ### `make check_commit`
203
+
204
+ Run `commitlint` for the latest commit.
205
+
206
+ ### `make check_config`
207
+
208
+ Run `tsc` to typecheck meta-files.
209
+
210
+ > **ℹ️ Good to know II**
211
+ >
212
+ > For the purpose of this ReadMe, “meta-file” means a file that is related to the tooling itself (e.g. configuring ESLint) and is not part of the application’s source code.
213
+
214
+ ### `make check_lint`
215
+
216
+ Run `eslint` to lint both sourcecode and meta-files.
217
+
218
+ ### `make check_package_json`
219
+
220
+ Run all of:
221
+
222
+ * `util_get_package_json`
223
+ * `check_package_json_sort`
224
+ * `check_package_json_repository`
225
+ * `check_package_json_name`
226
+ * `check_package_json_version`
227
+
228
+ ### `make check_package_json_name`
229
+
230
+ If package is linked to a Git repository and isn’t a sub-package, check if the `package.json` name matches the repository name.
231
+
232
+ ### `make check_package_json_repository`
233
+
234
+ If package is linked to a Git repository, check if the `package.json` repository fields contain the correct type, point to the correct repository and, if the package is a sub-package, point towards the correct sub-directory within the repository.
235
+
236
+ ### `make check_package_json_sort`
237
+
238
+ Run `sort-package-json` to check for proper key sorting in `package.json`.
239
+
240
+ ### `make check_package_json_version`
241
+
242
+ If package is linked to a Git repository, check if the `package.json` version matches the latest release version derived from Git tags.
243
+
244
+ ### `make check_test`
245
+
246
+ Run unit-tests using `jest`.
247
+
248
+ ### `make check_typescript`
249
+
250
+ Run `tsc` to typecheck sourcecode.
251
+
252
+ ## Transform
253
+
254
+ ### `make transform`
255
+
256
+ Run all of:
257
+
258
+ * `transform_package_json`
259
+ * `transform_lint`
260
+ * `transform_build`
261
+
262
+ ### `make transform_build`
263
+
264
+ Run `tsc` to build sourcecode (excluding test-files).
265
+
266
+ ### `make transform_lint`
267
+
268
+ Run `eslint` to fix lint-errors in both sourcecode and meta-files.
269
+
270
+ ### `make transform_package_json`
271
+
272
+ Run all of:
273
+
274
+ * `transform_package_json_sort`
275
+ * `transform_package_json_name`
276
+ * `transform_package_json_version`
277
+ * `transform_package_json_fix`
278
+
279
+ ### `make transform_package_json_fix`
280
+
281
+ Run `npm pkg fix` to fix common misconfigurations in `package.json`.
282
+
283
+ ### `make transform_package_json_name`
284
+
285
+ If not a sub-package, set Git repository name as `package.json` name.
286
+
287
+ ### `make transform_package_json_sort`
288
+
289
+ Run `sort-package-json` to apply proper key sorting in `package.json`.
290
+
291
+ ### `make transform_package_json_version`
292
+
293
+ Set Git repository version (from tags) as `package.json` version.
294
+
295
+ ### `make transform_prod`
296
+
297
+ Run `util_clear` and `transform_build`.
298
+
299
+ ## Util
300
+
301
+ ### `make util_clear`
302
+
303
+ Clear out `dist` directory.
304
+
305
+ ### `make util_edit`
306
+
307
+ Open VSCode for root- and sub-packages.
308
+
309
+ ### `make util_get_package_json`
310
+
311
+ Output `package.json` to stdout.
312
+
313
+ ### `make util_get_package_spec`
314
+
315
+ Output root- or sub-package spec (i.e. namespace + package name + version) to stdout.
316
+
317
+ ### `make util_get_package_spec_inner`
318
+
319
+ Output package spec (i.e. namespace + package name + version) to stdout.
320
+
321
+ ### `make util_get_next_prerelease_version <prerelease-tag>`
322
+
323
+ Check Git tags for `<prerelease-tag>` and output appropriate sequential semver-prerelease version to stdout.
324
+
325
+ ### `make util_get_version`
326
+
327
+ Output `package.json` version to stdout.
328
+
329
+ ### `make util_install_git_hooks`
330
+
331
+ Run `husky` to (re)install Git-hooks.
332
+
333
+ ## Run
334
+
335
+ ### `make run`
336
+
337
+ Run NodeJS application.
338
+
339
+ ## Watch
340
+
341
+ ### `make watch_run`
342
+
343
+ Run NodeJS application with `--watch`-option.
344
+
345
+ ### `make watch`
346
+
347
+ Use Tmux to show multi-panel view for:
348
+
349
+ * `watch_lint`
350
+ * `watch_test`
351
+ * `watch_build`
352
+ * `watch_config`
353
+ * `watch_run`
354
+
355
+ ### `make watch_build`
356
+
357
+ Run `tsc` to build sourcecode (excluding test-files) with `--watch`-option.
358
+
359
+ ### `make watch_config`
360
+
361
+ Run `tsc` to typecheck meta-files with `--watch`-option.
362
+
363
+ ### `make watch_dev`
364
+
365
+ Use Tmux to show multi-panel view for:
366
+
367
+ * `watch_lint`
368
+ * `watch_test`
369
+ * `watch_build`
370
+ * `watch_config`
371
+ * `watch_run`
372
+
373
+ …and provide “work-area” shell at the bottom.
374
+
375
+ ### `make watch_lint`
376
+
377
+ Run `eslint` with `nodemon` to (re)lint both sourcecode and meta-files on file change.
378
+
379
+ ### `make watch_test`
380
+
381
+ Run unit-tests using `jest` with `--watch`-option.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrpelz/boilerplate-node",
3
- "version": "12.5.1",
3
+ "version": "13.0.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/mrpelz/boilerplate.git",