Skip to content

Commit

Permalink
Chore: Fixes laurent22#6663: Fix watchInjectedJs and support multiple…
Browse files Browse the repository at this point in the history
… output bundles (laurent22#6664)
  • Loading branch information
personalizedrefrigerator authored Jul 22, 2022
1 parent 0e532fb commit f0831f1
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 64 deletions.
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,9 @@ packages/app-mobile/services/e2ee/RSA.react-native.js.map
packages/app-mobile/setupQuickActions.d.ts
packages/app-mobile/setupQuickActions.js
packages/app-mobile/setupQuickActions.js.map
packages/app-mobile/tools/buildInjectedJs.d.ts
packages/app-mobile/tools/buildInjectedJs.js
packages/app-mobile/tools/buildInjectedJs.js.map
packages/app-mobile/utils/ShareExtension.d.ts
packages/app-mobile/utils/ShareExtension.js
packages/app-mobile/utils/ShareExtension.js.map
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,9 @@ packages/app-mobile/services/e2ee/RSA.react-native.js.map
packages/app-mobile/setupQuickActions.d.ts
packages/app-mobile/setupQuickActions.js
packages/app-mobile/setupQuickActions.js.map
packages/app-mobile/tools/buildInjectedJs.d.ts
packages/app-mobile/tools/buildInjectedJs.js
packages/app-mobile/tools/buildInjectedJs.js.map
packages/app-mobile/utils/ShareExtension.d.ts
packages/app-mobile/utils/ShareExtension.js
packages/app-mobile/utils/ShareExtension.js.map
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
const gulp = require('gulp');
const utils = require('@joplin/tools/gulp/utils');
import { buildInjectedJS, watchInjectedJS } from './tools/buildInjectedJs';

const tasks = {
encodeAssets: {
fn: require('./tools/encodeAssets'),
},
buildInjectedJs: {
fn: require('./tools/buildInjectedJs'),
fn: buildInjectedJS,
},
watchInjectedJs: {
fn: watchInjectedJS,
},
podInstall: {
fn: require('./tools/podInstall'),
Expand Down
4 changes: 1 addition & 3 deletions packages/app-mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"watch": "tsc --watch --preserveWatchOutput --project tsconfig.json",
"clean": "node tools/clean.js",
"buildInjectedJs": "gulp buildInjectedJs",
"watchInjectedJs": "nodemon --verbose --watch components/NoteEditor/CodeMirror.ts --exec \"yarn run buildInjectedJs\"",
"watchInjectedJs": "gulp watchInjectedJs",
"postinstall": "jetify && yarn run build"
},
"dependencies": {
Expand Down Expand Up @@ -86,8 +86,6 @@
"@rollup/plugin-node-resolve": "^13.0.0",
"@rollup/plugin-typescript": "^8.2.1",
"@types/jest": "^28.1.3",
"@types/node": "^14.14.6",
"@types/react": "^16.9.55",
"@types/react-native": "^0.64.4",
"babel-plugin-module-resolver": "^4.1.0",
"execa": "^4.0.0",
Expand Down
55 changes: 0 additions & 55 deletions packages/app-mobile/tools/buildInjectedJs.js

This file was deleted.

172 changes: 172 additions & 0 deletions packages/app-mobile/tools/buildInjectedJs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// React Native WebView cannot load external JS files, however it can load
// arbitrary JS via the injectedJavaScript property. So we use this to load external
// files: First here we convert the JS file to a plain string, and that string
// is then loaded by eg. the Mermaid plugin, and finally injected in the WebView.

import { mkdirp, readFile, writeFile } from 'fs-extra';
import { dirname, extname, basename } from 'path';
const execa = require('execa');

import { OutputOptions, rollup, RollupOptions, watch as rollupWatch } from 'rollup';
import typescript from '@rollup/plugin-typescript';
import { nodeResolve } from '@rollup/plugin-node-resolve';

const rootDir = dirname(dirname(dirname(__dirname)));
const mobileDir = `${rootDir}/packages/app-mobile`;
const outputDir = `${mobileDir}/lib/rnInjectedJs`;

/**
* Stores the contents of the file at [filePath] as an importable string.
*
* @param name the name (excluding the .js extension) of the output file that will contain
* the JSON-ified file content
* @param filePath Path to the file to JSON-ify.
*/
async function copyJs(name: string, filePath: string) {
const outputPath = `${outputDir}/${name}.js`;
console.info(`Creating: ${outputPath}`);
const js = await readFile(filePath, 'utf-8');
const json = `module.exports = ${JSON.stringify(js)};`;
await writeFile(outputPath, json);
}


class BundledFile {
private readonly bundleOutputPath: string;
private readonly bundleMinifiedPath: string;
private readonly bundleBaseName: string;
private readonly rootFileDirectory: string;

public constructor(
public readonly bundleName: string,
private readonly sourceFilePath: string
) {
this.rootFileDirectory = dirname(sourceFilePath);
this.bundleBaseName = basename(sourceFilePath, extname(sourceFilePath));
this.bundleOutputPath = `${this.rootFileDirectory}/${this.bundleBaseName}.bundle.js`;
this.bundleMinifiedPath = `${this.rootFileDirectory}/${this.bundleBaseName}.bundle.min.js`;
}

private getRollupOptions(): [RollupOptions, OutputOptions] {
const rollupInputOptions: RollupOptions = {
input: this.sourceFilePath,
plugins: [
typescript({
// Exclude all .js files. Rollup will attempt to import a .js
// file if both a .ts and .js file are present, conflicting
// with our build setup. See
// https://discourse.joplinapp.org/t/importing-a-ts-file-from-a-rollup-bundled-ts-file/
exclude: `${this.rootFileDirectory}/**/*.js`,
}),
nodeResolve(),
],
};

const rollupOutputOptions: OutputOptions = {
format: 'iife',
name: this.bundleName,
file: this.bundleOutputPath,
};

return [rollupInputOptions, rollupOutputOptions];
}

private async uglify() {
console.info(`Minifying bundle: ${this.bundleName}...`);
await execa('yarn', [
'run', 'uglifyjs',
'--compress',
'-o', this.bundleMinifiedPath,
this.bundleOutputPath,
]);
}

/**
* Create a minified JS file in the same directory as `this.sourceFilePath` with
* the same name.
*/
public async build() {
const [rollupInputOptions, rollupOutputOptions] = this.getRollupOptions();

console.info(`Building bundle: ${this.bundleName}...`);
const bundle = await rollup(rollupInputOptions);
await bundle.write(rollupOutputOptions);

await this.uglify();
}

public async startWatching() {
const [rollupInputOptions, rollupOutputOptions] = this.getRollupOptions();
const watcher = rollupWatch({
...rollupInputOptions,
output: [rollupOutputOptions],
watch: {
exclude: [
`${mobileDir}/node_modules/`,
],
},
});

watcher.on('event', async event => {
if (event.code === 'BUNDLE_END') {
await this.uglify();
await this.copyToImportableFile();
console.info(`☑ Bundled ${this.bundleName}!`);

// Let plugins clean up
await event.result.close();
} else if (event.code === 'ERROR') {
console.error(event.error);

// Clean up any bundle-related resources
if (event.result) {
await event.result?.close();
}
} else if (event.code === 'END') {
console.info('Done bundling.');
} else if (event.code === 'START') {
console.info('Starting bundler...');
}
});

// We're done configuring the watcher
watcher.close();
}

/**
* Creates a file that can be imported by React native. This file contains the
* bundled JS as a string.
*/
public async copyToImportableFile() {
await copyJs(`${this.bundleBaseName}.bundle`, this.bundleMinifiedPath);
}
}


const bundledFiles: BundledFile[] = [
new BundledFile(
'codeMirrorBundle',
`${mobileDir}/components/NoteEditor/CodeMirror/CodeMirror.ts`
),
];

export async function buildInjectedJS() {
await mkdirp(outputDir);


// Build all in parallel
await Promise.all(bundledFiles.map(async file => {
await file.build();
await file.copyToImportableFile();
}));

await copyJs('webviewLib', `${mobileDir}/../lib/renderers/webviewLib.js`);
}

export async function watchInjectedJS() {
// Watch for changes
for (const file of bundledFiles) {
void(file.startWatching());
}
}

4 changes: 4 additions & 0 deletions packages/app-mobile/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
],
"exclude": [
"**/node_modules",

// Files that don't need transpilation
"gulpfile.ts",
"tools/*.ts",
"**/*.test.ts",
"**/*.test.tsx",
],
Expand Down
8 changes: 3 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3775,8 +3775,6 @@ __metadata:
"@rollup/plugin-node-resolve": ^13.0.0
"@rollup/plugin-typescript": ^8.2.1
"@types/jest": ^28.1.3
"@types/node": ^14.14.6
"@types/react": ^16.9.55
"@types/react-native": ^0.64.4
assert-browserify: ^2.0.0
babel-plugin-module-resolver: ^4.1.0
Expand Down Expand Up @@ -6240,12 +6238,12 @@ __metadata:
linkType: hard

"@types/jest@npm:^28.1.3":
version: 28.1.4
resolution: "@types/jest@npm:28.1.4"
version: 28.1.5
resolution: "@types/jest@npm:28.1.5"
dependencies:
jest-matcher-utils: ^28.0.0
pretty-format: ^28.0.0
checksum: 97e22c600397bb4f30e39b595f8285ae92e4eb29a1ef6d1689749e4a4da683d88ecfe717b64492f6adc4c17c1c989520c3546f938c84a7d435c6ac3acf1a2bdc
checksum: 994bfc25a5e767ec1506a2a7d94e60a7a5645b2e4e8444c56ae902f3a3e27ae54e821e41c1b4e7c8d7f5022bf5abfdd0460ead223ba6f2d0a194e5b2bed1ad76
languageName: node
linkType: hard

Expand Down

0 comments on commit f0831f1

Please sign in to comment.