Skip to content

Commit

Permalink
✨ add ability to generate proxy script.
Browse files Browse the repository at this point in the history
  • Loading branch information
momocow committed Feb 8, 2023
1 parent ced22ec commit 09d313c
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 16 deletions.
79 changes: 72 additions & 7 deletions lib/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,23 @@ import {
resolveUpdateBaseUrl,
setDefaultMatch,
} from './reducers';
import { processProxyScript } from './reducers/proxy-script';
import {
FileInfo,
HeadersWaterfall,
SSRILock,
UserscriptOptions,
} from './types';
import { interpolate } from './util';

const { ConcatSource, RawSource } = sources;

export class UserscriptPlugin {
public readonly hooks = {
processHeaders: new AsyncSeriesWaterfallHook<HeadersWaterfall>(['headers']),
processProxyHeaders: new AsyncSeriesWaterfallHook<HeadersWaterfall>([
'headers',
]),
};

public constructor(
Expand Down Expand Up @@ -73,7 +78,8 @@ export class UserscriptPlugin {
}

protected applyHooks(): void {
const { downloadBaseUrl, updateBaseUrl, ssri, headers } = this.options;
const { downloadBaseUrl, updateBaseUrl, ssri, headers, proxyScript } =
this.options;

if (typeof headers === 'function') {
this.hooks.processHeaders.tapPromise(
Expand Down Expand Up @@ -114,6 +120,13 @@ export class UserscriptPlugin {
interpolateValues.name,
wrapHook(interpolateValues),
);

if (proxyScript) {
this.hooks.processProxyHeaders.tap(
processProxyScript.name,
wrapHook(processProxyScript),
);
}
}

protected headersFactory(props: HeadersProps): Readonly<Headers> {
Expand Down Expand Up @@ -288,7 +301,8 @@ export class UserscriptPlugin {
data: CompilerData,
fileInfo: FileInfo,
): Promise<void> {
const { prefix, pretty, suffix, whitelist, strict } = this.options;
const { prefix, pretty, suffix, whitelist, strict, proxyScript, metajs } =
this.options;

const { headers: headersProps, ssriLock } =
await this.hooks.processHeaders.promise({
Expand All @@ -306,12 +320,52 @@ export class UserscriptPlugin {
headers.validate({ whitelist: whitelist ?? true });
}

let proxyScriptFile: string | undefined;
let proxyHeaders: Readonly<Headers> | undefined;

if (proxyScript) {
const { headers: proxyHeadersProps } =
await this.hooks.processProxyHeaders.promise({
headers: headersProps,
ssriLock,
fileInfo,
compilation,
buildNo: data.buildNo,
options: this.options,
});

proxyHeaders = this.headersFactory(proxyHeadersProps);

if (strict) {
proxyHeaders.validate({ whitelist: whitelist ?? true });
}

if (proxyScript === true || proxyScript.filename === undefined) {
proxyScriptFile = '[basename].proxy.user.js';
} else {
proxyScriptFile = interpolate(proxyScript.filename, {
chunkName: fileInfo.chunk.name,
file: fileInfo.originalFile,
filename: fileInfo.filename,
basename: fileInfo.basename,
query: fileInfo.query,
buildNo: data.buildNo.toString(),
buildTime: Date.now().toString(),
});
}
}

const { originalFile, chunk, metajsFile, userjsFile } = fileInfo;
const headersStr = headers.render({
prefix,
pretty,
suffix,
});
const proxyHeadersStr = proxyHeaders?.render({
prefix,
pretty,
suffix,
});
const sourceAsset = compilation.getAsset(originalFile);
if (!sourceAsset) {
return;
Expand All @@ -321,14 +375,25 @@ export class UserscriptPlugin {
userjsFile,
new ConcatSource(headersStr, '\n', sourceAsset.source),
{
related: { metajs: metajsFile },
minimized: true,
},
);
compilation.emitAsset(metajsFile, new RawSource(headersStr), {
related: { userjs: userjsFile },
minimized: true,
});

if (metajs !== false) {
compilation.emitAsset(
metajsFile,
new RawSource(proxyHeadersStr ?? headersStr),
{
minimized: true,
},
);
}

if (proxyHeadersStr !== undefined && proxyScriptFile !== undefined) {
compilation.emitAsset(proxyScriptFile, new RawSource(proxyHeadersStr), {
minimized: true,
});
}

chunk.files.add(userjsFile);
chunk.auxiliaryFiles.add(metajsFile);
Expand Down
7 changes: 4 additions & 3 deletions lib/reducers/base-urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ export const resolveUpdateBaseUrl: HeadersReducer = ({
if (headers.updateURL === undefined) {
return {
...headers,
updateURL: !options.metajs
? headers.downloadURL
: new URL(fileInfo.metajsFile, options.updateBaseUrl).toString(),
updateURL:
options.metajs === false
? headers.downloadURL
: new URL(fileInfo.metajsFile, options.updateBaseUrl).toString(),
};
}
return headers;
Expand Down
7 changes: 1 addition & 6 deletions lib/reducers/interpolate.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { HeadersReducer } from '../types';
import { interpolate } from '../util';

export const interpolateValues: HeadersReducer = ({
fileInfo: { chunk, originalFile, filename, basename, query },
Expand Down Expand Up @@ -51,9 +52,3 @@ export const interpolateValues: HeadersReducer = ({

return headers;
};

export function interpolate(str: string, data: Record<string, string>): string {
return Object.entries(data).reduce((value, [dataKey, dataVal]) => {
return value.replace(new RegExp(`\\[${dataKey}\\]`, 'g'), `${dataVal}`);
}, str);
}
42 changes: 42 additions & 0 deletions lib/reducers/proxy-script.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { URL } from 'url';

import { HeadersReducer } from '../types';
import { interpolate } from '../util';

export const processProxyScript: HeadersReducer = ({
headers,
fileInfo: { chunk, originalFile, filename, basename, query, userjsFile },
buildNo,
options: { proxyScript },
}) => {
if (proxyScript) {
const devBaseUrl =
proxyScript === true || proxyScript.baseUrl === undefined
? 'http://localhost:8080/'
: interpolate(proxyScript.baseUrl, {
chunkName: chunk.name,
file: originalFile,
filename,
basename,
query,
buildNo: buildNo.toString(),
buildTime: Date.now().toString(),
});

const requireTags = Array.isArray(headers.require)
? headers.require
: typeof headers.require === 'string'
? [headers.require]
: [];

headers = {
...headers,
require: [...requireTags, new URL(userjsFile, devBaseUrl).toString()],
downloadURL: undefined,
updateURL: undefined,
installURL: undefined,
};
}

return headers;
};
6 changes: 6 additions & 0 deletions lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface UserscriptOptions {
downloadBaseUrl?: string;
updateBaseUrl?: string;
ssri?: true | SSRIOptions;
proxyScript?: true | ProxyScriptOptions;
}

export type HeadersProvider = HeadersReducer | AsyncHeadersReducer;
Expand All @@ -41,6 +42,11 @@ export interface SSRIOptions {
lock?: boolean | string;
}

export interface ProxyScriptOptions {
filename?: string;
baseUrl?: string;
}

export interface FileInfo {
chunk: Chunk;
originalFile: string;
Expand Down
5 changes: 5 additions & 0 deletions lib/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function interpolate(str: string, data: Record<string, string>): string {
return Object.entries(data).reduce((value, [dataKey, dataVal]) => {
return value.replace(new RegExp(`\\[${dataKey}\\]`, 'g'), `${dataVal}`);
}, str);
}

0 comments on commit 09d313c

Please sign in to comment.