@adobe/aem-cli 16.16.33 → 16.17.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 +7 -0
- package/README.md +9 -4
- package/package.json +1 -1
- package/src/server/HelixProject.js +10 -6
- package/src/server/HelixServer.js +15 -18
- package/src/up.cmd.js +7 -2
- package/src/up.js +7 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [16.17.0](https://github.com/adobe/helix-cli/compare/v16.16.33...v16.17.0) (2026-04-07)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **html-folder:** Add --html-mount flag to control URL path for html-folder serving ([#2697](https://github.com/adobe/helix-cli/issues/2697)) ([4ed1f4b](https://github.com/adobe/helix-cli/commit/4ed1f4bea996e2afcf79dd1fc94f2809689ed772))
|
|
7
|
+
|
|
1
8
|
## [16.16.33](https://github.com/adobe/helix-cli/compare/v16.16.32...v16.16.33) (2026-04-06)
|
|
2
9
|
|
|
3
10
|
|
package/README.md
CHANGED
|
@@ -79,13 +79,17 @@ This feature is especially helpful when:
|
|
|
79
79
|
The `--html-folder` option enables serving HTML files without extensions, useful for previewing content changes when you don't have access to the authoring system.
|
|
80
80
|
|
|
81
81
|
```
|
|
82
|
-
$ aem up --html-folder
|
|
82
|
+
$ aem up --html-folder drafts # serves at /drafts/*
|
|
83
|
+
$ aem up --html-folder content --html-mount / # serves at /* (root)
|
|
84
|
+
$ aem up --html-folder drafts --html-mount /preview # serves at /preview/*
|
|
83
85
|
```
|
|
84
86
|
|
|
87
|
+
Use `--html-mount` to control the URL path where files are served. Without it, files are served at `/FOLDER/*`.
|
|
88
|
+
|
|
85
89
|
This enables two features:
|
|
86
90
|
|
|
87
|
-
1. **Extension-less URLs**: Access `/
|
|
88
|
-
2. **Plain HTML with metadata**: Create
|
|
91
|
+
1. **Extension-less URLs**: Access `/drafts/page` (or `/page` with root mount) to serve the corresponding `.html` file
|
|
92
|
+
2. **Plain HTML with metadata**: Create `.plain.html` files that are automatically wrapped with proper HTML structure and metadata processing
|
|
89
93
|
|
|
90
94
|
#### Plain HTML files (.plain.html)
|
|
91
95
|
|
|
@@ -181,7 +185,8 @@ If present, `ALL_PROXY` is used as fallback if there is no other match.
|
|
|
181
185
|
| `--livereload` | `AEM_LIVERELOAD` | `true` | Enable automatic reloading of modified sources in browser. |
|
|
182
186
|
| `--no-livereload` | `AEM_NO_LIVERELOAD` | `false` | Disable live-reload. |
|
|
183
187
|
| `--forward-browser-logs` | `AEM_FORWARD_BROWSER_LOGS` | `false` | Forward browser console logs to terminal. |
|
|
184
|
-
| `--html-folder` | `AEM_HTML_FOLDER` | undefined | Serve HTML files from folder without extensions.
|
|
188
|
+
| `--html-folder` | `AEM_HTML_FOLDER` | undefined | Serve HTML files from folder without extensions. |
|
|
189
|
+
| `--html-mount` | `AEM_HTML_MOUNT` | `/FOLDER` | URL path where html-folder files are served. |
|
|
185
190
|
| `--open` | `AEM_OPEN` | `/` | Open a browser window at specified path after server start. |
|
|
186
191
|
| `--no-open` | `AEM_NO_OPEN` | `false` | Disable automatic opening of browser window. |
|
|
187
192
|
| `--tls-key` | `AEM_TLS_KEY` | undefined | Path to .key file (for enabling TLS) |
|
package/package.json
CHANGED
|
@@ -86,16 +86,16 @@ export class HelixProject extends BaseProject {
|
|
|
86
86
|
if (path.isAbsolute(value) || value.includes('..') || value.startsWith('/')) {
|
|
87
87
|
throw new Error(`Invalid HTML folder name: ${value} only folders within the current workspace are allowed`);
|
|
88
88
|
}
|
|
89
|
-
|
|
90
|
-
this._htmlFolder = value;
|
|
91
|
-
this._server.withHtmlFolder(value);
|
|
92
|
-
} else {
|
|
93
89
|
this._htmlFolder = value;
|
|
94
|
-
this._server.withHtmlFolder(value);
|
|
95
90
|
}
|
|
96
91
|
return this;
|
|
97
92
|
}
|
|
98
93
|
|
|
94
|
+
withHtmlMount(value) {
|
|
95
|
+
this._htmlMount = value;
|
|
96
|
+
return this;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
99
|
get proxyUrl() {
|
|
100
100
|
return this._proxyUrl;
|
|
101
101
|
}
|
|
@@ -142,6 +142,10 @@ export class HelixProject extends BaseProject {
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
async init() {
|
|
145
|
+
if (this._htmlFolder) {
|
|
146
|
+
const mount = this._htmlMount || `/${this._htmlFolder}`;
|
|
147
|
+
this._server.withHtmlFolder(this._htmlFolder, mount);
|
|
148
|
+
}
|
|
145
149
|
await super.init();
|
|
146
150
|
this._indexer = new Indexer()
|
|
147
151
|
.withLogger(this._logger)
|
|
@@ -206,7 +210,7 @@ export class HelixProject extends BaseProject {
|
|
|
206
210
|
await lstat(htmlFolderPath);
|
|
207
211
|
this.log.debug(`Registered HTML folder for live-reload: ${this._htmlFolder}`);
|
|
208
212
|
// Watch all HTML files in the folder - only .html extension
|
|
209
|
-
this.liveReload.registerFiles([`${htmlFolderPath}/**/*.html`],
|
|
213
|
+
this.liveReload.registerFiles([`${htmlFolderPath}/**/*.html`], this._server.mountPrefix);
|
|
210
214
|
} catch (e) {
|
|
211
215
|
this.log.error(`HTML folder '${this._htmlFolder}' does not exist`);
|
|
212
216
|
throw new Error(`HTML folder '${this._htmlFolder}' does not exist`);
|
|
@@ -63,12 +63,17 @@ export class HelixServer extends BaseServer {
|
|
|
63
63
|
return this;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
withHtmlFolder(
|
|
67
|
-
|
|
68
|
-
this.
|
|
66
|
+
withHtmlFolder(folder, mount) {
|
|
67
|
+
this._htmlFolder = folder;
|
|
68
|
+
this._htmlMount = mount;
|
|
69
|
+
this._mountPrefix = mount.endsWith('/') ? mount : `${mount}/`;
|
|
69
70
|
return this;
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
get mountPrefix() {
|
|
74
|
+
return this._mountPrefix;
|
|
75
|
+
}
|
|
76
|
+
|
|
72
77
|
async handleLogin(req, res) {
|
|
73
78
|
const userAgent = req.headers['user-agent']?.toLowerCase();
|
|
74
79
|
if (userAgent?.includes('safari') && !userAgent?.includes('chrome')) {
|
|
@@ -262,22 +267,15 @@ export class HelixServer extends BaseServer {
|
|
|
262
267
|
* @param {Function} next next middleware
|
|
263
268
|
*/
|
|
264
269
|
async handleHtmlFolderRequest(req, res, next) {
|
|
265
|
-
if (!this._htmlFolder) {
|
|
266
|
-
return next();
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Use Express's req.path for pathname extraction
|
|
270
270
|
const pathname = req.path;
|
|
271
|
-
const folderPrefix = `/${this._htmlFolder}/`;
|
|
272
271
|
|
|
273
|
-
|
|
274
|
-
if (
|
|
272
|
+
let relativePath;
|
|
273
|
+
if (pathname.startsWith(this._mountPrefix)) {
|
|
274
|
+
relativePath = pathname.slice(this._mountPrefix.length);
|
|
275
|
+
} else {
|
|
275
276
|
return next();
|
|
276
277
|
}
|
|
277
278
|
|
|
278
|
-
// Extract the path within the HTML folder
|
|
279
|
-
let relativePath = pathname.slice(folderPrefix.length);
|
|
280
|
-
|
|
281
279
|
// Handle directory requests (trailing slash) by appending 'index'
|
|
282
280
|
if (relativePath === '' || relativePath.endsWith('/')) {
|
|
283
281
|
relativePath = `${relativePath}index`.replace(/\/+/g, '/');
|
|
@@ -452,10 +450,9 @@ export class HelixServer extends BaseServer {
|
|
|
452
450
|
|
|
453
451
|
// Add HTML folder handler before the general proxy handler
|
|
454
452
|
if (this._htmlFolder) {
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
this.
|
|
458
|
-
this.log.info(`Serving HTML files from folder: ${this._htmlFolder}`);
|
|
453
|
+
const mountPattern = new RegExp(`^${this._mountPrefix}.*`);
|
|
454
|
+
this.app.get(mountPattern, asyncHandler(this.handleHtmlFolderRequest.bind(this)));
|
|
455
|
+
this.log.info(`Serving HTML files from folder: ${this._htmlFolder} at ${this._htmlMount}`);
|
|
459
456
|
}
|
|
460
457
|
|
|
461
458
|
const handler = asyncHandler(this.handleProxyModeRequest.bind(this));
|
package/src/up.cmd.js
CHANGED
|
@@ -56,11 +56,15 @@ export default class UpCommand extends AbstractServerCommand {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
withHtmlFolder(value) {
|
|
59
|
-
// Basic validation - detailed validation done in HelixProject
|
|
60
59
|
this._htmlFolder = value;
|
|
61
60
|
return this;
|
|
62
61
|
}
|
|
63
62
|
|
|
63
|
+
withHtmlMount(value) {
|
|
64
|
+
this._htmlMount = value;
|
|
65
|
+
return this;
|
|
66
|
+
}
|
|
67
|
+
|
|
64
68
|
async doStop() {
|
|
65
69
|
await super.doStop();
|
|
66
70
|
if (this._watcher) {
|
|
@@ -113,7 +117,8 @@ export default class UpCommand extends AbstractServerCommand {
|
|
|
113
117
|
.withAllowInsecure(this._allowInsecure)
|
|
114
118
|
.withSiteToken(this._siteToken)
|
|
115
119
|
.withCookies(this._cookies)
|
|
116
|
-
.withHtmlFolder(this._htmlFolder)
|
|
120
|
+
.withHtmlFolder(this._htmlFolder)
|
|
121
|
+
.withHtmlMount(this._htmlMount);
|
|
117
122
|
|
|
118
123
|
this.log.info(chalk`{yellow ___ ________ ___ __ __ v${pkgJson.version}}`);
|
|
119
124
|
this.log.info(chalk`{yellow / | / ____/ |/ / _____(_)___ ___ __ __/ /___ _/ /_____ _____}`);
|
package/src/up.js
CHANGED
|
@@ -117,7 +117,12 @@ export default function up() {
|
|
|
117
117
|
})
|
|
118
118
|
.option('html-folder', {
|
|
119
119
|
alias: 'htmlFolder',
|
|
120
|
-
describe: 'Serve HTML files from this folder without extensions
|
|
120
|
+
describe: 'Serve HTML files from this folder without extensions. Defaults to serving at /FOLDER.',
|
|
121
|
+
type: 'string',
|
|
122
|
+
})
|
|
123
|
+
.option('html-mount', {
|
|
124
|
+
alias: 'htmlMount',
|
|
125
|
+
describe: 'URL path where html-folder files are served (e.g., / for root). Defaults to /FOLDER.',
|
|
121
126
|
type: 'string',
|
|
122
127
|
})
|
|
123
128
|
|
|
@@ -147,6 +152,7 @@ export default function up() {
|
|
|
147
152
|
.withCache(argv.alphaCache)
|
|
148
153
|
.withCookies(argv.cookies)
|
|
149
154
|
.withHtmlFolder(argv.htmlFolder)
|
|
155
|
+
.withHtmlMount(argv.htmlMount)
|
|
150
156
|
.run();
|
|
151
157
|
},
|
|
152
158
|
};
|