Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion dev/browser/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@ import { exec } from 'node:child_process';
import os from 'node:os';

export default async function start(server) {
const url = server ? `https://${server.host}:${server.port}` : 'https://localhost:3000';
const protocol = server?.protocol || 'https';
const url = server ? `${protocol}://${server.host}:${server.port}` : 'https://localhost:3000';

console.log(`-> Dev server: ${url}`);

// A remote or headless workstation has no browser to open; printing the URL
// is all that is useful there.
if (server && server.headless) {
return;
}

if (os.platform() === 'darwin') {
exec(`open ${url}`);
Expand Down
32 changes: 28 additions & 4 deletions dev/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ const args = process.argv.slice(2);
const platform = args.find((arg) => /(android|ios|browser)/i.test(arg)) || "android";
const isRelease = args.includes("--release") || args.includes("-r") || false;
const noServer = args.includes("--no-server");
// Bind and serve overrides, needed whenever the dev server is not reached over
// the LAN: a remote workstation (VS Code Remote port forwarding) wants
// `--host localhost --http`, and `--headless` keeps a headless box from trying
// to launch a browser.
const hostOverride = getArgValue("--host") || process.env.SHELLULAR_DEV_HOST;
const portOverride = getArgValue("--port") || process.env.SHELLULAR_DEV_PORT;
const noHttps = args.includes("--http");
const headless = args.includes("--headless");

const { default: start } = await import(`./${platform}/start.js`);

Expand Down Expand Up @@ -37,10 +45,11 @@ async function main() {
} else if (noServer) {
command = `webpack --mode development --env platform=${platform}`;
} else {
const host = getIp();
const port = getPort();
devServer = { host, port };
command = `webpack serve --mode development --env platform=${platform} host=${host} port=${port}`;
const host = hostOverride || getIp();
const port = portOverride || getPort();
const protocol = platform === "browser" && !noHttps ? "https" : "http";
devServer = { host, port, protocol, headless };
command = `webpack serve --mode development --env platform=${platform} host=${host} port=${port}${noHttps ? " https=false" : ""}`;
}

console.log(command);
Expand Down Expand Up @@ -131,6 +140,21 @@ function printToStdOut(error, stdout, stderr) {
}
}

/**
* Reads the value of a `--flag value` or `--flag=value` argument.
* @param {string} flag - The flag to look for.
* @returns {string|undefined} The value, or undefined when the flag is absent.
*/
function getArgValue(flag) {
const inline = args.find((arg) => arg.startsWith(`${flag}=`));
if (inline) {
return inline.slice(flag.length + 1);
}

const index = args.indexOf(flag);
return index !== -1 ? args[index + 1] : undefined;
}

function getPort() {
if (platform === "browser") {
return 7977;
Expand Down
30 changes: 22 additions & 8 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,14 @@ export default (_, { env = {}, mode = "development" }) => {
platform = "android",
host,
port,
https = "true",
console: compileConsole = false,
} = env;
// The browser target is served over https so the phone gets a secure
// context on the LAN. Behind a localhost tunnel (VS Code Remote port
// forwarding) http is both a secure context and one less certificate
// warning, so `https=false` turns TLS off.
const useHttps = platform === "browser" && https !== "false";
const outputPath =
platform === "browser"
? BROWSER_BUNDLE
Expand All @@ -45,11 +51,16 @@ export default (_, { env = {}, mode = "development" }) => {

let alias;
if (isDev) {
console.log(`dev server: ${host}:${port}`);
alias = {
// assuming app & packages are in the same monorepo, adjust as needed
"@shellular/protocol": resolve("../packages/protocol/dist/index.js"),
};
// Only alias the protocol package when this checkout really sits next to
// it in the monorepo. A standalone checkout has no ../packages, and an
// alias pointing at a missing file breaks every dev build.
const localProtocol = resolve("../packages/protocol/dist/index.js");
if (existsSync(localProtocol)) {
console.log(`using local protocol: ${localProtocol}`);
alias = { "@shellular/protocol": localProtocol };
} else {
console.log(`no local protocol found. using the one from node_modules`);
}
} else if (!compileConsole) {
clearOutputDir(outputPath);
}
Expand Down Expand Up @@ -125,7 +136,7 @@ export default (_, { env = {}, mode = "development" }) => {
webSocketURL: {
hostname: host,
port: Number(port),
protocol: platform === "browser" ? "wss" : "ws",
protocol: useHttps ? "wss" : "ws",
pathname: "/ws",
},
},
Expand All @@ -138,7 +149,7 @@ export default (_, { env = {}, mode = "development" }) => {
: {}),
...(platform === "browser"
? {
server: "https",
server: useHttps ? "https" : "http",
headers: (request) => {
const isAuthCallback =
new URL(
Expand Down Expand Up @@ -255,7 +266,10 @@ export default (_, { env = {}, mode = "development" }) => {
DISPLAY_NAME: packageJson.displayName,
HOST: isDev && host ? host : null,
PORT: isDev && port ? port : null,
ORIGIN: isDev && host && port ? `http://${host}:${port}` : null,
ORIGIN:
isDev && host && port
? `${useHttps ? "https" : "http"}://${host}:${port}`
: null,
}),
],
optimization: {
Expand Down