Skip to content

Commit

Permalink
Merge pull request #30 from yakisova41/add-userscriptinject-mode
Browse files Browse the repository at this point in the history
⚡️feat: add userscript dom import
  • Loading branch information
yakisova41 authored Apr 2, 2024
2 parents 6c22891 + 975be6a commit 8aa1ec6
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 26 deletions.
5 changes: 5 additions & 0 deletions README-ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ const config = {
['@author', 'me'],
['@grant', 'unsageWindow'],
],
userscriptInjectPage: ['src/contentScript/contentScript.ts'],
};

export default config;
Expand Down Expand Up @@ -121,3 +122,7 @@ publicフォルダーのディレクトリパスを指定できます。
### importIconToUsercript

`manifest.json`に指定された48ピクセルのiconをbase64に変換してuserscriptのiconに設定します

### userscriptInjectPage

userscriptとして読み込む際にunsafeWindowからアクセスしたbodyへ直接scriptタグを使用して挿入するcontentscriptを指定できます。
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const config = {
['@author', 'me'],
['@grant', 'unsageWindow'],
],
userscriptInjectPage: ['src/contentScript/contentScript.ts'],
};

export default config;
Expand Down Expand Up @@ -121,3 +122,7 @@ For detailed header format, please check [Documentation | Tampermonkey](https://
### importIconToUsercript

Convert the 48-pixel icon specified in the `manifest.json` to base64 and set it to the userscript icon.

### userscriptInjectPage

You can specify the contentscript to be inserted using a script tag directly into the body accessed from the unsafeWindow when loading as a userscript.
5 changes: 4 additions & 1 deletion dev/crx-monkey.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// @ts-check

/** @type {import('../packages/crx-monkey/dist/node/main').NonLoadedCrxMonkeyConfig} */
const config = { importIconToUsercript: true };
const config = {
importIconToUsercript: true,
userscriptInjectPage: ['src/contentScript/contentScript.ts'],
};

export default config;
1 change: 1 addition & 0 deletions packages/crx-monkey/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const defaultConfig: CrxMonkeyConfig = {
publicDir: path.join(process.cwd(), './public'),
userScriptHeader: [],
importIconToUsercript: false,
userscriptInjectPage: [],
};

async function getConfigPath(): Promise<string | null> {
Expand Down
39 changes: 27 additions & 12 deletions packages/crx-monkey/src/node/handlers/build/BuildUserScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { BuildResult } from 'esbuild';
import fse from 'fs-extra';
import path from 'path';
import { Build, BuildImplements } from './Build';
import { generateInjectScriptCode } from '../dev/utils';

export class BuildUserScript extends Build implements BuildImplements {
private readonly headerFactory: UserscriptHeaderFactory;
Expand All @@ -38,14 +39,11 @@ export class BuildUserScript extends Build implements BuildImplements {
if (contentScripts !== undefined) {
const { jsFiles, cssFiles } = getAllJsAndCSSByContentScripts(contentScripts);

/**
* If even one css is loaded, a GM_addStyle grant is added to the header
*/
const isLoadedCss = cssFiles.length !== 0;

const { matchMap, allMatches } = createMatchMap(contentScripts, jsFiles, cssFiles);

this.headerRegister(allMatches, isLoadedCss);
const isExistInjectScripts = this.isIncludedInjectScripts(jsFiles);

this.headerRegister(allMatches, isExistInjectScripts);

this.loadContentCssFiles(cssFiles);

Expand All @@ -62,7 +60,7 @@ export class BuildUserScript extends Build implements BuildImplements {
}
}

private async headerRegister(allMatches: string[], isLoadedCss: boolean) {
private async headerRegister(allMatches: string[], unsafeWindow: boolean) {
allMatches.forEach((match) => {
this.headerFactory.push('@match', match);
});
Expand Down Expand Up @@ -93,10 +91,6 @@ export class BuildUserScript extends Build implements BuildImplements {
});
}

if (isLoadedCss) {
this.headerFactory.push('@grant', 'GM_addStyle');
}

const configHeader = this.config.userScriptHeader;
if (configHeader !== undefined) {
configHeader.forEach((configHeaderItem) => {
Expand All @@ -108,6 +102,10 @@ export class BuildUserScript extends Build implements BuildImplements {
});
}

if (unsafeWindow) {
this.headerFactory.push('@grant', 'unsafeWindow');
}

if (this.config.importIconToUsercript) {
const icons = this.manifest.icons;

Expand Down Expand Up @@ -169,7 +167,12 @@ export class BuildUserScript extends Build implements BuildImplements {

if (jsBuildResultStore[filePath] !== undefined) {
const buildResultText = new TextDecoder().decode(jsBuildResultStore[filePath]);
scriptContent = scriptContent + buildResultText;

if (this.config.userscriptInjectPage.includes(filePath)) {
scriptContent = scriptContent + generateInjectScriptCode(buildResultText);
} else {
scriptContent = scriptContent + buildResultText;
}
}

if (cssResultStore[filePath] !== undefined) {
Expand Down Expand Up @@ -215,4 +218,16 @@ export class BuildUserScript extends Build implements BuildImplements {
this.cssResultStore[cssFilePath] = result;
});
}

private isIncludedInjectScripts(jsFiles: string[]) {
let result = false;

jsFiles.forEach((jsFile) => {
if (this.config.userscriptInjectPage.includes(jsFile)) {
result = true;
}
});

return result;
}
}
39 changes: 27 additions & 12 deletions packages/crx-monkey/src/node/handlers/dev/WatchUserScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { BuildResult } from 'esbuild';
import fse from 'fs-extra';
import path from 'path';
import { ReloadServer } from './server/reloadServer';
import { generateInjectScriptCode } from './utils';

export class WatchUserScript extends Watch implements WatchImplements {
private readonly headerFactory: UserscriptHeaderFactory;
Expand Down Expand Up @@ -41,14 +42,11 @@ export class WatchUserScript extends Watch implements WatchImplements {
if (contentScripts !== undefined) {
const { jsFiles, cssFiles } = getAllJsAndCSSByContentScripts(contentScripts);

/**
* If even one css is loaded, a GM_addStyle grant is added to the header
*/
const isLoadedCss = cssFiles.length !== 0;

const { matchMap, allMatches } = createMatchMap(contentScripts, jsFiles, cssFiles);

this.headerRegister(allMatches, isLoadedCss);
const isExistInjectScripts = this.isIncludedInjectScripts(jsFiles);

this.headerRegister(allMatches, isExistInjectScripts);

this.loadContentCssFiles(cssFiles);

Expand All @@ -69,7 +67,7 @@ export class WatchUserScript extends Watch implements WatchImplements {
}
}

private async headerRegister(allMatches: string[], isLoadedCss: boolean) {
private async headerRegister(allMatches: string[], unsafeWindow: boolean) {
allMatches.forEach((match) => {
this.headerFactory.push('@match', match);
});
Expand Down Expand Up @@ -100,10 +98,6 @@ export class WatchUserScript extends Watch implements WatchImplements {
});
}

if (isLoadedCss) {
this.headerFactory.push('@grant', 'GM_addStyle');
}

const configHeader = this.config.userScriptHeader;
if (configHeader !== undefined) {
configHeader.forEach((configHeaderItem) => {
Expand All @@ -115,6 +109,10 @@ export class WatchUserScript extends Watch implements WatchImplements {
});
}

if (unsafeWindow) {
this.headerFactory.push('@grant', 'unsafeWindow');
}

if (this.config.importIconToUsercript) {
const icons = this.manifest.icons;

Expand Down Expand Up @@ -176,7 +174,12 @@ export class WatchUserScript extends Watch implements WatchImplements {

if (jsBuildResultStore[filePath] !== undefined) {
const buildResultText = new TextDecoder().decode(jsBuildResultStore[filePath]);
scriptContent = scriptContent + buildResultText;

if (this.config.userscriptInjectPage.includes(filePath)) {
scriptContent = scriptContent + generateInjectScriptCode(buildResultText);
} else {
scriptContent = scriptContent + buildResultText;
}
}

if (cssResultStore[filePath] !== undefined) {
Expand Down Expand Up @@ -222,4 +225,16 @@ export class WatchUserScript extends Watch implements WatchImplements {
this.cssResultStore[cssFilePath] = result;
});
}

private isIncludedInjectScripts(jsFiles: string[]) {
let result = false;

jsFiles.forEach((jsFile) => {
if (this.config.userscriptInjectPage.includes(jsFile)) {
result = true;
}
});

return result;
}
}
2 changes: 1 addition & 1 deletion packages/crx-monkey/src/node/handlers/dev/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export default async function handleDev() {

await hostingServer.start();

console.clear();
// console.clear();
consola.box(
[
`${chalk.cyan.bold('CRX-MONKEY')} ${chalk.green(`v${pkg.version}`)}`,
Expand Down
10 changes: 10 additions & 0 deletions packages/crx-monkey/src/node/handlers/dev/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,13 @@ export function getDevelopDir() {
throw new Error('');
}
}

export function generateInjectScriptCode(scriptContent: string) {
return [
`const inject = ()=>{${scriptContent}}`,
'const script = document.createElement("script");',
'script.innerHTML = `(${inject.toString()})()`',
'unsafeWindow.document.body.appendChild(script)',
'',
].join('\n');
}
1 change: 1 addition & 0 deletions packages/crx-monkey/src/node/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface CrxMonkeyConfig {
publicDir: string;
userScriptHeader: UserScriptHeader;
importIconToUsercript: boolean;
userscriptInjectPage: string[];
}

export type NonLoadedCrxMonkeyConfig = {
Expand Down

0 comments on commit 8aa1ec6

Please sign in to comment.