Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(client): client/src/cordova/dev action #2111

Merged
merged 13 commits into from
Aug 12, 2024
1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
"eslint-plugin-import": "^2.26.0",
"esm": "^3.2.25",
"file-loader": "^6.2.0",
"folder-hash": "^4.0.4",
"html-webpack-plugin": "^5.1.0",
"husky": "^1.3.1",
"i18n-strings-files": "^2.0.0",
Expand Down
87 changes: 87 additions & 0 deletions client/src/cordova/start.action.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright 2022 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import path from 'path';
import url from 'url';

import {createReloadServer} from '@outline/infrastructure/build/create_reload_server.mjs';
import {getRootDir} from '@outline/infrastructure/build/get_root_dir.mjs';
import {runAction} from '@outline/infrastructure/build/run_action.mjs';
import cordovaLib from 'cordova-lib';
import {hashElement} from 'folder-hash';
import * as fs from 'fs-extra';
const {cordova} = cordovaLib;

import {getBuildParameters} from '../../build/get_build_parameters.mjs';

const getUIHash = async () => {
const hashResult = await hashElement(
path.join(getRootDir(), 'client/src/www'),
{
files: {include: ['**/*.ts', '**/*.html', '**/*.css', '**/*.js']},
}
);

return hashResult.hash;
};

/**
* @description Builds the parameterized cordova binary (ios, macos, maccatalyst, android).
*
* @param {string[]} parameters
*/
export async function main(...parameters) {
const {platform, verbose} = getBuildParameters(parameters);

if (platform !== 'macos') {
throw new Error('Only macos platform is currently supported');
}

await runAction('client/src/www/build', ...parameters);
await runAction('client/go/build', ...parameters);
await runAction('client/src/cordova/setup', ...parameters);

if (verbose) {
cordova.on('verbose', message =>
console.debug(`[cordova:verbose] ${message}`)
);
}

let previousUIHashResult = await getUIHash();

console.log('Starting reload server @ port 35729...');
createReloadServer(async () => {
const currentUIHashResult = await getUIHash();

if (previousUIHashResult === currentUIHashResult) {
return false;
}

previousUIHashResult = currentUIHashResult;

await runAction('client/src/www/build', ...parameters);

await fs.copy(
path.join(getRootDir(), 'client/www'),
// TODO: find way to programmatically get this path
'/Users/daniellacosse/Library/Developer/Xcode/DerivedData/macos-XXXXXXX/Build/Products/Debug/Outline.app/Contents/Resources/www'
);

return true;
}).listen(35729);
}

if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
await main(...process.argv.slice(2));
}
11 changes: 11 additions & 0 deletions client/src/www/index_cordova.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,16 @@
</head>
<body unresolved>
<app-root></app-root>

<script>
Copy link
Contributor Author

@daniellacosse daniellacosse Aug 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately I can't inject this in debug mode because that mode doesn't work on MacOS.

@fortuna are there security concerns with this?

Copy link
Contributor Author

@daniellacosse daniellacosse Aug 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's a problem, I can try injecting this script tag in the action after cordova/src/www/build is run! Maybe with jsdom?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use a separate index_cordova.dev.html file and use that in the cordova setup using makeReplacements()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So creating a separate file would mean i'd have to breakout a whole other webpack config/build workflow so instead i opted to just call makeReplacements() on the index_cordova.html output by the webpack process. PTAL.

try {
const reloadSocket = new WebSocket("ws://localhost:35729");

reloadSocket.onopen = () => console.log("LiveReload connected~");
reloadSocket.onmessage = ({ data }) => data === "reload" && location.reload();
} catch (e) {
// nevermind
}
</script>
</body>
</html>
36 changes: 36 additions & 0 deletions infrastructure/build/create_reload_server.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2024 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import {createServer} from 'node:http';

import {WebSocketServer} from 'ws';

export function createReloadServer(
shouldReload = () => true,
reloadCheckIntervalMs = 1000
) {
const server = createServer();
const websocket = new WebSocketServer({server});

websocket.on('connection', connection => {
setInterval(async () => {
if (!(await shouldReload())) return;

console.log('Reloading...');
connection.send('reload');
}, reloadCheckIntervalMs);
});

return server;
}
3 changes: 2 additions & 1 deletion infrastructure/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"dependencies": {
"chalk": "^5.3.0",
"node-fetch": "^3.3.2",
"node-forge": "^1.3.1"
"node-forge": "^1.3.1",
"ws": "^8.18.0"
}
}
Loading
Loading