Skip to content

Commit

Permalink
Merge pull request #3669 from dmichon-msft/serve-file
Browse files Browse the repository at this point in the history
[rush-serve-plugin] Allow serving single files
  • Loading branch information
iclanton authored Oct 4, 2022
2 parents 9d4cb72 + 4c9cb80 commit 4f0ce88
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@rushstack/rush-serve-plugin",
"comment": "Allow serving of single files, e.g. to serve a specific file at \"/\" (the root).",
"type": "minor"
}
],
"packageName": "@rushstack/rush-serve-plugin"
}
21 changes: 18 additions & 3 deletions rush-plugins/rush-serve-plugin/src/RushProjectServeConfigFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,25 @@ export interface IRushProjectServeJson {
routing: IRoutingRuleJson[];
}

export interface IRoutingRuleJson {
projectRelativeFolder: string;
export interface IBaseRoutingRuleJson {
servePath: string;
immutable?: boolean;
}

export interface IRoutingFolderRuleJson extends IBaseRoutingRuleJson {
projectRelativeFile: undefined;
projectRelativeFolder: string;
}

export interface IRoutingFileRuleJson extends IBaseRoutingRuleJson {
projectRelativeFile: string;
projectRelativeFolder: undefined;
}

export type IRoutingRuleJson = IRoutingFileRuleJson | IRoutingFolderRuleJson;

export interface IRoutingRule {
type: 'file' | 'folder';
diskPath: string;
servePath: string;
immutable: boolean;
Expand Down Expand Up @@ -61,8 +73,11 @@ export class RushServeConfiguration {
);
if (serveJson) {
for (const rule of serveJson.routing) {
const { projectRelativeFile, projectRelativeFolder } = rule;
const diskPath: string = projectRelativeFolder ?? projectRelativeFile;
rules.push({
diskPath: path.resolve(project.projectFolder, rule.projectRelativeFolder),
type: projectRelativeFile ? 'file' : 'folder',
diskPath: path.resolve(project.projectFolder, diskPath),
servePath: rule.servePath,
immutable: !!rule.immutable
});
Expand Down
46 changes: 34 additions & 12 deletions rush-plugins/rush-serve-plugin/src/phasedCommandHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,22 +89,44 @@ export async function phasedCommandHandler(options: IPhasedCommandHandlerOptions
logger.terminal
);

function setHeaders(response: express.Response, path: string, stat: unknown): void {
const fileRoutingRules: Map<string, IRoutingRule> = new Map();

function setHeaders(response: express.Response, path?: string, stat?: unknown): void {
response.set('Access-Control-Allow-Origin', '*');
response.set('Access-Control-Allow-Methods', 'GET');
response.set('Access-Control-Allow-Methods', 'GET, OPTIONS');
}

for (const rule of routingRules) {
app.use(
rule.servePath,
express.static(rule.diskPath, {
dotfiles: 'ignore',
immutable: rule.immutable,
index: false,
redirect: false,
setHeaders
})
);
const { diskPath, servePath } = rule;
if (rule.type === 'file') {
const existingRule: IRoutingRule | undefined = fileRoutingRules.get(servePath);
if (existingRule) {
throw new Error(
`Request to serve "${diskPath}" at "${servePath}" conflicts with existing rule to serve "${existingRule.diskPath}" from this location.`
);
} else {
fileRoutingRules.set(diskPath, rule);
app.get(servePath, (request: express.Request, response: express.Response) => {
response.sendFile(diskPath, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, OPTIONS'
}
});
});
}
} else {
app.use(
servePath,
express.static(diskPath, {
dotfiles: 'ignore',
immutable: rule.immutable,
index: false,
redirect: false,
setHeaders
})
);
}
}

const server: https.Server = https.createServer(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,50 @@
"type": "array",
"description": "Routing rules",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["projectRelativeFolder", "servePath"],
"properties": {
"projectRelativeFolder": {
"type": "string",
"description": "The folder from which to read assets, relative to the root of the current project."
},
"oneOf": [
{
"type": "object",
"additionalProperties": false,
"required": ["projectRelativeFolder", "servePath"],
"properties": {
"projectRelativeFolder": {
"type": "string",
"description": "The folder from which to read assets, relative to the root of the current project."
},

"servePath": {
"type": "string",
"description": "The server path at which to serve the assets in \"projectRelativeFolder\"."
},

"servePath": {
"type": "string",
"description": "The server path at which to serve the assets in \"projectRelativeFolder\"."
"immutable": {
"type": "boolean",
"description": "Enables or disables the `immutable` directive in the `Cache-Control` resoponse header. See (https://expressjs.com/en/4x/api.html#express.static)."
}
}
},
{
"type": "object",
"additionalProperties": false,
"required": ["projectRelativeFile", "servePath"],
"properties": {
"projectRelativeFile": {
"type": "string",
"description": "The file to serve, relative to the root of the current project."
},

"servePath": {
"type": "string",
"description": "The server path at which to serve \"projectRelativeFile\"."
},

"immutable": {
"type": "boolean",
"description": "Enables or disables the `immutable` directive in the `Cache-Control` resoponse header. See (https://expressjs.com/en/4x/api.html#express.static)."
"immutable": {
"type": "boolean",
"description": "Enables or disables the `immutable` directive in the `Cache-Control` resoponse header. See (https://expressjs.com/en/4x/api.html#express.static)."
}
}
}
}
]
}
}
}
Expand Down

0 comments on commit 4f0ce88

Please sign in to comment.