create-express-new 1.2.0 → 1.3.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/CHANGELOG.md +11 -1
- package/README.md +21 -3
- package/bin/express-cli.js +9 -0
- package/lib/app.js +39 -5
- package/lib/wizard.js +5 -1
- package/package.json +1 -1
- package/templates/app/Dockerfile.ejs +19 -0
- package/templates/public/stylesheets/style.scss +10 -0
- package/templates/versions.json +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,15 @@ All notable changes to this project are documented here. The format is based on
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.3.0] - 2026-10-11
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `--sass` adds Sass to a web app: a `style.scss` compiled to the CSS the app serves by a `css`
|
|
14
|
+
script that runs before `start` and `dev`, a `css:watch` script, and a stage in the `--docker`
|
|
15
|
+
image that compiles the stylesheets. The wizard offers it under Extras
|
|
16
|
+
- Issue templates for bug reports and feature requests
|
|
17
|
+
|
|
9
18
|
## [1.2.0] - 2026-10-11
|
|
10
19
|
|
|
11
20
|
### Added
|
|
@@ -136,7 +145,8 @@ the full list and a table for migrating commands.
|
|
|
136
145
|
- The `-e/--ejs`, `--hbs`, `--pug` and `-H/--hogan` aliases; use `--view=<engine>`
|
|
137
146
|
- The `debug` package and `DEBUG=...` start instructions
|
|
138
147
|
|
|
139
|
-
[Unreleased]: https://github.com/w0244079/create-express-new/compare/v1.
|
|
148
|
+
[Unreleased]: https://github.com/w0244079/create-express-new/compare/v1.3.0...HEAD
|
|
149
|
+
[1.3.0]: https://github.com/w0244079/create-express-new/compare/v1.2.0...v1.3.0
|
|
140
150
|
[1.2.0]: https://github.com/w0244079/create-express-new/compare/v1.1.0...v1.2.0
|
|
141
151
|
[1.1.0]: https://github.com/w0244079/create-express-new/compare/v1.0.0...v1.1.0
|
|
142
152
|
[1.0.0]: https://github.com/w0244079/create-express-new/releases/tag/v1.0.0
|
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ $ pnpm create express-new@latest
|
|
|
30
30
|
- the language: JavaScript, TypeScript or CommonJS
|
|
31
31
|
- optional middleware, and CSRF protection with sessions
|
|
32
32
|
- the request logger
|
|
33
|
-
- extras: a Dockerfile and
|
|
33
|
+
- extras: a Dockerfile, ESLint and Sass
|
|
34
34
|
- a `.gitignore`
|
|
35
35
|
- the [package manager](#package-manager) the app requires: pnpm, or npm
|
|
36
36
|
|
|
@@ -237,6 +237,7 @@ The image:
|
|
|
237
237
|
- is based on `node:22-slim`, the latest release of the minimum supported Node.js version
|
|
238
238
|
- installs only production dependencies, in a build stage of their own, so the package manager is
|
|
239
239
|
not in the final image
|
|
240
|
+
- with `--sass`, compiles the stylesheets in another build stage, so Sass is not in the final image
|
|
240
241
|
- runs the app as the unprivileged `node` user with `NODE_ENV=production`
|
|
241
242
|
- checks `/health` with a `HEALTHCHECK`
|
|
242
243
|
- runs `node` directly, so it receives `SIGTERM` and shuts down gracefully
|
|
@@ -250,6 +251,21 @@ The image:
|
|
|
250
251
|
`--ts` it also adds [typescript-eslint](https://typescript-eslint.io/); as typescript-eslint does not
|
|
251
252
|
support TypeScript 7 yet, these apps use TypeScript 6.
|
|
252
253
|
|
|
254
|
+
### Sass
|
|
255
|
+
|
|
256
|
+
`--sass` adds [Sass](https://sass-lang.com/) to a web app: a `public/stylesheets/style.scss` in place
|
|
257
|
+
of `style.css`, compiled to the CSS the app serves.
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
$ pnpm start # compiles the stylesheets, then starts the app
|
|
261
|
+
$ pnpm dev # compiles them once, then restarts the app on change
|
|
262
|
+
$ pnpm css:watch # recompiles them on change, in a second terminal
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Sass is a development dependency, so `pnpm start` fails where only production dependencies are
|
|
266
|
+
installed: compile the stylesheets first with `pnpm css`, as the `--docker` image does.
|
|
267
|
+
[Using Sass](docs/sass.md) covers this, the files it ignores and adding Sass to an existing app.
|
|
268
|
+
|
|
253
269
|
## Command Line Options
|
|
254
270
|
|
|
255
271
|
-v, --view <engine> add view <engine> support (ejs|hbs|pug|twig) (defaults to pug)
|
|
@@ -273,6 +289,7 @@ support TypeScript 7 yet, these apps use TypeScript 6.
|
|
|
273
289
|
token (all|pages) (defaults to all)
|
|
274
290
|
--uploads add multer and an upload route at /uploads
|
|
275
291
|
--logger <name> request logger (morgan|pino) (defaults to morgan)
|
|
292
|
+
--sass add Sass, compiling .scss stylesheets (not with --api alone)
|
|
276
293
|
--docker add a Dockerfile for a production image
|
|
277
294
|
--lint add ESLint and a lint script
|
|
278
295
|
--pm <name> package manager the app requires (pnpm|npm) (defaults to pnpm)
|
|
@@ -289,11 +306,12 @@ support TypeScript 7 yet, these apps use TypeScript 6.
|
|
|
289
306
|
|
|
290
307
|
This fork started from `express-generator` 4.16.1. It generates Express 5 apps as ES modules, with
|
|
291
308
|
pug in place of jade, for Node.js 22.9 or newer. `--view=<engine>` replaces the `--ejs`, `--hbs` and
|
|
292
|
-
`--pug` aliases, and apps use plain CSS
|
|
309
|
+
`--pug` aliases, and apps use plain CSS unless you add Sass with `--sass`; the other CSS preprocessors
|
|
310
|
+
are gone.
|
|
293
311
|
|
|
294
312
|
- [Changes from express-generator](docs/changes-from-express-generator.md): everything added,
|
|
295
313
|
changed and removed, and a table for migrating commands
|
|
296
|
-
- [Using Sass](docs/sass.md): adding Sass to
|
|
314
|
+
- [Using Sass](docs/sass.md): what `--sass` adds, and adding Sass to an existing app
|
|
297
315
|
|
|
298
316
|
## Contributing
|
|
299
317
|
|
package/bin/express-cli.js
CHANGED
|
@@ -35,6 +35,7 @@ const OPTIONS = {
|
|
|
35
35
|
'no-view': { type: 'boolean' },
|
|
36
36
|
pm: { type: 'string' },
|
|
37
37
|
'rate-limit': { type: 'boolean' },
|
|
38
|
+
sass: { type: 'boolean' },
|
|
38
39
|
session: { type: 'boolean' },
|
|
39
40
|
ts: { type: 'boolean' },
|
|
40
41
|
uploads: { type: 'boolean' },
|
|
@@ -351,6 +352,13 @@ function main (options, done) {
|
|
|
351
352
|
return done(1)
|
|
352
353
|
}
|
|
353
354
|
|
|
355
|
+
// Sass is for the stylesheets of web apps
|
|
356
|
+
if (options.sass && options.api && !options.view) {
|
|
357
|
+
usage()
|
|
358
|
+
error('option `--sass\' cannot be used with `--api\', unless `--view\' is given too')
|
|
359
|
+
return done(1)
|
|
360
|
+
}
|
|
361
|
+
|
|
354
362
|
if (options.csrf && !options.session) {
|
|
355
363
|
usage()
|
|
356
364
|
error('option `--csrf\' requires `--session\'')
|
|
@@ -527,6 +535,7 @@ function usage () {
|
|
|
527
535
|
console.log(' token (all|pages) (defaults to all)')
|
|
528
536
|
console.log(' --uploads add multer and an upload route at /uploads')
|
|
529
537
|
console.log(' --logger <name> request logger (morgan|pino) (defaults to morgan)')
|
|
538
|
+
console.log(' --sass add Sass, compiling .scss stylesheets (not with --api alone)')
|
|
530
539
|
console.log(' --docker add a Dockerfile for a production image')
|
|
531
540
|
console.log(' --lint add ESLint and a lint script')
|
|
532
541
|
console.log(' --pm <name> package manager the app requires (pnpm|npm) (defaults to pnpm)')
|
package/lib/app.js
CHANGED
|
@@ -84,6 +84,7 @@ const ALTERNATIVES = [
|
|
|
84
84
|
'eslint.config.js',
|
|
85
85
|
'eslint.config.mjs',
|
|
86
86
|
'pnpm-workspace.yaml',
|
|
87
|
+
'public/stylesheets/style.scss',
|
|
87
88
|
...fs.readdirSync(path.join(TEMPLATE_DIR, 'views')).map((file) => 'views/' + file)
|
|
88
89
|
]
|
|
89
90
|
|
|
@@ -112,10 +113,12 @@ export function planApp (name, options) {
|
|
|
112
113
|
file(to, fs.readFileSync(path.join(TEMPLATE_DIR, from), 'utf-8'), extra)
|
|
113
114
|
}
|
|
114
115
|
|
|
115
|
-
// an ignore file, ignoring uploaded files too
|
|
116
|
+
// an ignore file, ignoring uploaded files and compiled stylesheets too
|
|
116
117
|
function ignore (from) {
|
|
117
|
-
|
|
118
|
-
|
|
118
|
+
let contents = fs.readFileSync(path.join(TEMPLATE_DIR, from), 'utf-8')
|
|
119
|
+
if (options.uploads) contents += '\n# Uploaded files\nuploads/\n'
|
|
120
|
+
if (sass) contents += '\n# Stylesheets compiled from Sass: write styles in .scss files\npublic/stylesheets/*.css\npublic/stylesheets/*.css.map\n'
|
|
121
|
+
return contents
|
|
119
122
|
}
|
|
120
123
|
|
|
121
124
|
// Module format
|
|
@@ -137,6 +140,9 @@ export function planApp (name, options) {
|
|
|
137
140
|
const corsApi = webApi && options.corsScope !== 'all'
|
|
138
141
|
const csrfSkipApi = webApi && csrf && options.csrfScope === 'pages'
|
|
139
142
|
|
|
143
|
+
// Sass, for the stylesheets of apps with static files
|
|
144
|
+
const sass = Boolean(options.sass) && !api
|
|
145
|
+
|
|
140
146
|
// File uploads, with an upload form in apps with views
|
|
141
147
|
const uploads = Boolean(options.uploads)
|
|
142
148
|
|
|
@@ -274,7 +280,25 @@ export function planApp (name, options) {
|
|
|
274
280
|
dir('public/stylesheets')
|
|
275
281
|
|
|
276
282
|
// Stylesheet
|
|
277
|
-
|
|
283
|
+
if (sass) {
|
|
284
|
+
copy('public/stylesheets/style.scss', 'public/stylesheets/style.scss')
|
|
285
|
+
} else {
|
|
286
|
+
copy('public/stylesheets/style.css', 'public/stylesheets/style.css')
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Sass compiles each .scss file to the .css file the app serves, before
|
|
291
|
+
// the app starts: a development dependency, so the stylesheets of an app
|
|
292
|
+
// installed without them are compiled first, as in the Dockerfile
|
|
293
|
+
if (sass) {
|
|
294
|
+
const styles = 'public/stylesheets:public/stylesheets'
|
|
295
|
+
|
|
296
|
+
pkg.scripts.css = 'sass ' + styles
|
|
297
|
+
// recompile on change, alongside the dev script
|
|
298
|
+
pkg.scripts['css:watch'] = 'sass --watch ' + styles
|
|
299
|
+
pkg.scripts.prestart = scriptCommand(pm, 'css')
|
|
300
|
+
pkg.scripts.predev = scriptCommand(pm, 'css')
|
|
301
|
+
pkg.devDependencies.sass = VERSIONS.sass
|
|
278
302
|
}
|
|
279
303
|
|
|
280
304
|
// copy route templates
|
|
@@ -421,7 +445,15 @@ export function planApp (name, options) {
|
|
|
421
445
|
|
|
422
446
|
// Package manager settings, protecting installs from compromised packages
|
|
423
447
|
if (pm === 'pnpm') {
|
|
424
|
-
|
|
448
|
+
let settings = fs.readFileSync(path.join(TEMPLATE_DIR, 'app/pnpm-workspace.yaml'), 'utf-8')
|
|
449
|
+
|
|
450
|
+
// Sass's optional file watcher has an install script, which would stop
|
|
451
|
+
// the install, and which it works without
|
|
452
|
+
if (sass) {
|
|
453
|
+
settings += '\n# Do not run the install script of the file watcher Sass uses, which works\n# without it.\nallowBuilds:\n \'@parcel/watcher\': false\n'
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
file('pnpm-workspace.yaml', settings, { config: true })
|
|
425
457
|
} else {
|
|
426
458
|
copy('app/npmrc', '.npmrc', { config: true })
|
|
427
459
|
}
|
|
@@ -432,6 +464,8 @@ export function planApp (name, options) {
|
|
|
432
464
|
dockerfile.locals.name = name
|
|
433
465
|
dockerfile.locals.www = www
|
|
434
466
|
dockerfile.locals.uploads = uploads
|
|
467
|
+
dockerfile.locals.sass = sass
|
|
468
|
+
dockerfile.locals.css = scriptCommand(pm, 'css')
|
|
435
469
|
dockerfile.locals.pm = pm
|
|
436
470
|
// the exact package manager version, for repeatable image builds
|
|
437
471
|
dockerfile.locals.pmVersion = VERSIONS[pm].replace(/^\^/, '')
|
package/lib/wizard.js
CHANGED
|
@@ -138,7 +138,9 @@ export async function wizard (io) {
|
|
|
138
138
|
initial: answers.extras,
|
|
139
139
|
choices: [
|
|
140
140
|
{ label: 'Dockerfile', value: 'docker', hint: 'production image with a /health check' },
|
|
141
|
-
{ label: 'ESLint', value: 'lint', hint: 'with a lint script' }
|
|
141
|
+
{ label: 'ESLint', value: 'lint', hint: 'with a lint script' },
|
|
142
|
+
// stylesheets are for web apps
|
|
143
|
+
...(answers.kind !== 'api' ? [{ label: 'Sass', value: 'sass', hint: 'stylesheets compiled from .scss files' }] : [])
|
|
142
144
|
]
|
|
143
145
|
})
|
|
144
146
|
},
|
|
@@ -361,6 +363,7 @@ function toOptions (answers) {
|
|
|
361
363
|
logger: answers.logger ?? 'morgan',
|
|
362
364
|
pm: answers.pm ?? DEFAULT_PACKAGE_MANAGER,
|
|
363
365
|
rateLimit: middleware.includes('rate-limit'),
|
|
366
|
+
sass: kind !== 'api' && extras.includes('sass'),
|
|
364
367
|
session,
|
|
365
368
|
ts: language === 'ts',
|
|
366
369
|
uploads: middleware.includes('uploads'),
|
|
@@ -397,6 +400,7 @@ export function toCommand (options) {
|
|
|
397
400
|
if (options.csrfScope === 'pages') flags.push('--csrf-scope=pages')
|
|
398
401
|
if (options.uploads) flags.push('--uploads')
|
|
399
402
|
if (options.logger && options.logger !== 'morgan') flags.push('--logger=' + options.logger)
|
|
403
|
+
if (options.sass) flags.push('--sass')
|
|
400
404
|
if (options.docker) flags.push('--docker')
|
|
401
405
|
if (options.lint) flags.push('--lint')
|
|
402
406
|
if (pm !== DEFAULT_PACKAGE_MANAGER) flags.push('--pm=' + pm)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-express-new",
|
|
3
3
|
"description": "Express 5 application generator: ESM, TypeScript and CommonJS app templates. A modern successor to express-generator.",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.3.0",
|
|
5
5
|
"author": "Michael Caines (https://github.com/w0244079)",
|
|
6
6
|
"contributors": [
|
|
7
7
|
"TJ Holowaychuk <tj@vision-media.ca>",
|
|
@@ -36,6 +36,20 @@ COPY package*.json .npmrc ./
|
|
|
36
36
|
RUN npm ci --omit=dev
|
|
37
37
|
<% } -%>
|
|
38
38
|
|
|
39
|
+
<% if (sass) { -%>
|
|
40
|
+
# Stylesheets are compiled in their own stage too, as Sass is a development
|
|
41
|
+
# dependency, which the final image does not have.
|
|
42
|
+
FROM dependencies AS stylesheets
|
|
43
|
+
|
|
44
|
+
<% if (pm === 'pnpm') { -%>
|
|
45
|
+
RUN pnpm install --frozen-lockfile
|
|
46
|
+
<% } else { -%>
|
|
47
|
+
RUN npm ci
|
|
48
|
+
<% } -%>
|
|
49
|
+
COPY public/stylesheets ./public/stylesheets
|
|
50
|
+
RUN <%- css %>
|
|
51
|
+
|
|
52
|
+
<% } -%>
|
|
39
53
|
FROM node:22-slim
|
|
40
54
|
|
|
41
55
|
ENV NODE_ENV=production
|
|
@@ -47,6 +61,11 @@ COPY --from=dependencies /app/node_modules ./node_modules
|
|
|
47
61
|
# copy the app owned by the unprivileged node user, which runs it, so it can
|
|
48
62
|
# read the files whatever their permissions on the build machine
|
|
49
63
|
COPY --chown=node:node . .
|
|
64
|
+
<% if (sass) { -%>
|
|
65
|
+
|
|
66
|
+
# the stylesheets compiled above
|
|
67
|
+
COPY --chown=node:node --from=stylesheets /app/public/stylesheets ./public/stylesheets
|
|
68
|
+
<% } -%>
|
|
50
69
|
<% if (uploads) { -%>
|
|
51
70
|
|
|
52
71
|
# a folder for uploaded files that the node user can write to; files saved
|