Skip to content

Commit d1dba44

Browse files
authored
feat: serve frontend from a folder (#37)
* feat: serve frontend from a folder Closes #36 * ci: fix failing tests * ci: fix tests on Windows
1 parent 1df0dd2 commit d1dba44

File tree

7 files changed

+49
-20
lines changed

7 files changed

+49
-20
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"description": "Azure Static Web Apps Emulator for Auth, API and static content",
55
"scripts": {
66
"release": "release-it --preRelease=alpha",
7+
"pretest": "npm run build",
78
"test": "jest --detectOpenHandles --silent --verbose",
89
"build": "tsc",
910
"prebuild": "rm -fr dist",

readme.md

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,24 @@ Using `npx`:
5353
- Start the emulator: `npx @manekinekko/swa-emu@latest`
5454
- Access your SWA app from `http://localhost`
5555

56+
### Start the emulator from a specific folder
57+
58+
By default, SWA EMU will start from the current directory `./`. But if you have multiple SWA projects, you can start SWA EMU with a specific folder, and the emulator will use that folder as the `app_location`.
59+
60+
If your SWA project is under `./my-app`, then run the SWA EMU and provide that folder:
61+
62+
```bash
63+
swa ./my-app
64+
```
65+
66+
> Please also note, that running `swa ./my-app` is equivalent to `swa --app-location=./my-app`.
67+
68+
In case the SWA EMU cannot determine the right frontend application artifact (dist) folder to serve, you can override this configuration by providing the `--app-artifact-location` flag:
69+
70+
```bash
71+
swa ./my-app --app-artifact-location ./my-app/dist/
72+
```
73+
5674
### Use with a local API dev server
5775

5876
When developing locally on your back-end application, it might be useful to use your local API dev server, to serve your API content and benefit from the built-in features like debugging. In order to use SWA EMU with your local API dev server, follow these two steps:
@@ -79,8 +97,8 @@ swa --use-app=http://<app-dev-server-host>:<app-dev-server-port>
7997

8098
Here is a list of the default ports used by popular dev servers:
8199

82-
| Tool | Port | Command |
83-
| ---------------------------------------------------------------------------------- | ---- | -------------------------------------------- |
100+
| Tool | Port | Command |
101+
| ---------------------------------------------------------------------------------- | ---- | ------------------------------------- |
84102
| [Angular](https://angular.io/cli) | 4200 | `swa --use-app=http://localhost:4200` |
85103
| [Vue](https://cli.vuejs.org/) | 8080 | `swa --use-app=http://localhost:8080` |
86104
| [Vite](https://github.com/vitejs/vite/) | 3000 | `swa --use-app=http://localhost:3000` |
@@ -127,12 +145,12 @@ If you need to override the default values, provide the following options:
127145
The emulator supports local authentication flow and mocks the following providers:
128146

129147
| Provider | [Endpoint](https://docs.microsoft.com/azure/static-web-apps/authentication-authorization?WT.mc_id=javascript-0000-wachegha#login) | Local Emulation |
130-
| -------- | -------------------------------------------------------------------------------------------------------------------------------- | --------------- |
131-
| GitHub | `.auth/login/github` ||
132-
| Twitter | `.auth/login/twitter` ||
133-
| Google | `.auth/login/google` ||
134-
| Facebook | `.auth/login/facbook` ||
135-
| AAD | `.auth/login/aad` ||
148+
| -------- | --------------------------------------------------------------------------------------------------------------------------------- | --------------- |
149+
| GitHub | `.auth/login/github` ||
150+
| Twitter | `.auth/login/twitter` ||
151+
| Google | `.auth/login/google` ||
152+
| Facebook | `.auth/login/facbook` ||
153+
| AAD | `.auth/login/aad` ||
136154

137155
When requesting the `.auth/me` endpoint, a mocked user `clientPrincipal` will be returned by the emulator. Here is an example:
138156

src/auth/routes/identity_auth_login_provider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const httpTrigger = async function (context: Context, req: ServerRequest) {
1313

1414
switch (provider) {
1515
case "github":
16-
client_id = process.env.GITHUB_CLIENT_ID || client_id;
16+
client_id = process.env.GITHUB_CLIENT_ID || "";
1717

1818
//**** GITHUB NOTICE: start */
1919
if (!client_id) {

src/cli.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const APP_PORT = 4200;
1616

1717
program
1818
.name("swa")
19-
.usage("<command>")
19+
.usage("[options] <command>")
2020
.version(require("../package.json").version)
2121

2222
// SWA config
@@ -59,8 +59,13 @@ let [appLocation, appArtifactLocation, apiLocation] = [
5959
program.apiLocation as string,
6060
];
6161

62+
// if the user provides an app folder, use it as an app artifact location
63+
if (program.args.length) {
64+
appLocation = program.args[0];
65+
}
66+
6267
// retrieve the project's build configuration
63-
// provide any specific config that the user might provide
68+
// use any specific config that the user might provide
6469
const configFile = readConfigFile({
6570
overrideConfig: {
6671
appLocation,
@@ -117,7 +122,7 @@ const { command: hostCommand, args: hostArgs } = createRuntimeHost({
117122
appArtifactLocation: configFile?.appArtifactLocation,
118123
});
119124

120-
let serveApiContent = `[ -d '${apiLocation}' ] && (cd ${apiLocation}; func start --cors *) || echo 'No API found. Skipping.'`;
125+
let serveApiContent = `([ -d '${configFile?.apiLocation}' ] && (cd ${configFile?.apiLocation}; func start --cors *)) || echo 'No API found. Skipping.'`;
121126
if (program.useApi) {
122127
serveApiContent = `echo 'using API dev server at ${program.useApi}'`;
123128
}
@@ -150,7 +155,7 @@ const startCommand = [
150155
];
151156

152157
if (process.env.DEBUG) {
153-
shell.echo(startCommand.join("\n"));
158+
console.log({startCommand})
154159
}
155160

156161
if (program.build) {

src/runtimeHost.spec.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import path from "path";
12
import { createRuntimeHost } from "./runtimeHost";
23
import * as detectRuntime from "./runtimes";
34

@@ -25,7 +26,7 @@ describe("runtimeHost", () => {
2526
});
2627

2728
expect(spyDetectRuntime).toHaveBeenCalledWith("./");
28-
expect(rh.command).toContain("@manekinekko/swa-emulator/node_modules/.bin/http-server");
29+
expect(rh.command).toContain(path.join("swa-emulator", "node_modules", ".bin", "http-server"));
2930
expect(rh.args).toEqual(["./foobar", "--port", "8080", "--cache", "-1", "--proxy", "http://0.0.0.0:4242/?"]);
3031
});
3132

@@ -36,7 +37,7 @@ describe("runtimeHost", () => {
3637
});
3738

3839
expect(spyDetectRuntime).toHaveBeenCalledWith("./");
39-
expect(rh.command).toContain("@manekinekko/swa-emulator/node_modules/.bin/http-server");
40+
expect(rh.command).toContain(path.join("swa-emulator", "node_modules", ".bin", "http-server"));
4041
expect(rh.args).toEqual(["./", "--port", "8080", "--cache", "-1", "--proxy", "http://0.0.0.0:4242/?"]);
4142
});
4243

@@ -47,7 +48,7 @@ describe("runtimeHost", () => {
4748
});
4849

4950
expect(spyDetectRuntime).toHaveBeenCalledWith("./");
50-
expect(rh.command).toContain("@manekinekko/swa-emulator/node_modules/.bin/http-server");
51+
expect(rh.command).toContain(path.join("swa-emulator", "node_modules", ".bin", "http-server"));
5152
expect(rh.args).toEqual(["./", "--port", "8080", "--cache", "-1", "--proxy", "http://127.0.0.1:4242/?"]);
5253
});
5354

@@ -58,7 +59,7 @@ describe("runtimeHost", () => {
5859
});
5960

6061
expect(spyDetectRuntime).toHaveBeenCalledWith("./");
61-
expect(rh.command).toContain("@manekinekko/swa-emulator/node_modules/.bin/http-server");
62+
expect(rh.command).toContain(path.join("swa-emulator", "node_modules", ".bin", "http-server"));
6263
expect(rh.args).toEqual(["./", "--port", "8080", "--cache", "-1", "--proxy", "http://0.0.0.0:3000/?"]);
6364
});
6465

@@ -69,7 +70,7 @@ describe("runtimeHost", () => {
6970
});
7071

7172
expect(spyDetectRuntime).toHaveBeenCalledWith("./foobar");
72-
expect(rh.command).toContain("@manekinekko/swa-emulator/node_modules/.bin/http-server");
73+
expect(rh.command).toContain(path.join("swa-emulator", "node_modules", ".bin", "http-server"));
7374
expect(rh.args).toEqual(["./", "--port", "8080", "--cache", "-1", "--proxy", "http://0.0.0.0:4242/?"]);
7475
});
7576
});

src/runtimes.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import mockFs from "mock-fs";
22
import { detectRuntime, RuntimeType } from "./runtimes";
33

4-
const appLocation = "/tmp";
4+
const appLocation = "./tmp-swa-emulator";
55
describe("runtime", () => {
66
afterEach(() => {
77
mockFs.restore();

src/utils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,11 @@ export const readConfigFile = ({ overrideConfig }: { overrideConfig?: Partial<Gi
114114

115115
if (fs.existsSync(githubActionFolder) === false) {
116116
console.warn(warningMessage);
117-
return overrideConfig;
117+
return {
118+
appLocation: path.normalize(path.join(process.cwd(), overrideConfig?.appLocation || `.${path.sep}`)),
119+
apiLocation: path.normalize(path.join(process.cwd(), overrideConfig?.apiLocation || `${path.sep}api`)),
120+
appArtifactLocation: path.normalize(path.join(process.cwd(), overrideConfig?.appArtifactLocation || `.${path.sep}`)),
121+
};
118122
}
119123

120124
// find the SWA GitHub action file

0 commit comments

Comments
 (0)