Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@surma/rollup-plugin-off-main-thread

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@surma/rollup-plugin-off-main-thread - npm Package Compare versions

Comparing version 2.0.0 to 2.1.0

192

index.js

@@ -19,2 +19,3 @@ /**

const tippex = require("tippex");
const json5 = require("json5");

@@ -41,2 +42,21 @@ const defaultOpts = {

// A regexp to find static `new Worker` invocations.
// Matches `new Worker(...file part...`
// File part matches one of:
// - '...'
// - "..."
// - `import.meta.url`
// - new URL('...', import.meta.url)
// - new URL("...", import.meta.url)
const workerRegexpForTransform = /(new\s+Worker\()\s*(('.*?'|".*?")|import\.meta\.url|new\s+URL\(('.*?'|".*?"),\s*import\.meta\.url\))/gs;
// A regexp to find static `new Worker` invocations we've rewritten during the transform phase.
// Matches `new Worker(...file part..., ...options...`.
// File part matches one of:
// - new URL('...', module.uri)
// - new URL("...", module.uri)
const workerRegexpForOutput = /new\s+Worker\(new\s+URL\((?:'.*?'|".*?"),\s*module\.uri\)\s*(,([^)]+))/gs;
let longWarningAlreadyShown = false;
module.exports = function(opts = {}) {

@@ -50,3 +70,3 @@ opts = Object.assign({}, defaultOpts, opts);

let workerFiles;
let isEsmOutput = false;
let isEsmOutput = () => { throw new Error("outputOptions hasn't been called yet") };
return {

@@ -59,18 +79,2 @@ name: "off-main-thread",

outputOptions({ format }) {
if (format === "esm" || format === "es") {
if (!opts.silenceESMWorkerWarning) {
this.warn(
'Very few browsers support ES modules in Workers. If you want to your code to run in all browsers, set `output.format = "amd";`'
);
}
// In ESM, we never prepend a loader.
isEsmOutput = true;
} else if (format !== "amd") {
this.error(
`\`output.format\` must either be "amd" or "esm", got "${format}"`
);
}
},
async resolveId(id, importer) {

@@ -97,12 +101,2 @@ if (!id.startsWith(urlLoaderPrefix)) return;

async transform(code, id) {
// A regexp to find static `new Worker` invocations.
// File part matches one of:
// - '...'
// - "..."
// - `import.meta.url`
// - `new URL('...', import.meta.url)
// - `new URL("...", import.meta.url)
// Also matches optional options param.
const workerRegexp = /new\s+Worker\(\s*('.*?'|".*?"|import\.meta\.url|new\s+URL\(('.*?'|".*?"),\s*import\.meta\.url\))\s*(?:,(.+?))?\)/gs;
const ms = new MagicString(code);

@@ -116,22 +110,54 @@

code,
workerRegexp,
workerRegexpForTransform,
(
fullMatch,
partBeforeArgs,
workerSource,
directWorkerFile,
workerFile = directWorkerFile,
optionsStr = ""
workerFile,
) => {
// We need to get this before the `await`, otherwise `lastIndex`
// will be already overridden.
const workerParametersEndIndex = workerRegexpForTransform.lastIndex;
const matchIndex = workerParametersEndIndex - fullMatch.length;
const workerParametersStartIndex = matchIndex + partBeforeArgs.length;
let workerIdPromise;
if (directWorkerFile === "import.meta.url") {
if (workerSource === "import.meta.url") {
// Turn the current file into a chunk
workerIdPromise = Promise.resolve(id);
} else {
// Otherwise it's a string literal either directly or in the URL
// constructor, which we treat as the same thing.
// Otherwise it's a string literal either directly or in the `new URL(...)`.
if (directWorkerFile) {
const fullMatchWithOpts = `${fullMatch}, …)`;
const fullReplacement = `new Worker(new URL(${directWorkerFile}, import.meta.url), …)`;
if (!longWarningAlreadyShown) {
this.warn(
`rollup-plugin-off-main-thread:
\`${fullMatchWithOpts}\` suggests that the Worker should be relative to the document, not the script.
In the bundler, we don't know what the final document's URL will be, and instead assume it's a URL relative to the current module.
This might lead to incorrect behaviour during runtime.
If you did mean to use a URL relative to the current module, please change your code to the following form:
\`${fullReplacement}\`
This will become a hard error in the future.`,
matchIndex
);
longWarningAlreadyShown = true;
} else {
this.warn(
`rollup-plugin-off-main-thread: Treating \`${fullMatchWithOpts}\` as \`${fullReplacement}\``,
matchIndex
);
}
workerFile = directWorkerFile;
}
// Cut off surrounding quotes.
workerFile = workerFile.slice(1, -1);
if (!/^\.{0,2}\//.test(workerFile)) {
if (!/^\.{1,2}\//.test(workerFile)) {
this.warn(
`Paths passed to the Worker constructor must be relative or absolute, i.e. start with /, ./ or ../ (just like dynamic import!). Ignoring "${workerFile}".`
`Paths passed to the Worker constructor must be relative to the current file, i.e. start with ./ or ../ (just like dynamic import!). Ignoring "${workerFile}".`,
matchIndex
);

@@ -144,20 +170,2 @@ return;

// We need to get this before the `await`, otherwise `lastIndex`
// will be already overridden.
const matchIndex = workerRegexp.lastIndex - fullMatch.length;
const workerParametersStartIndex = matchIndex + "new Worker(".length;
const workerParametersEndIndex =
matchIndex + fullMatch.length - ")".length;
// Parse the optional options object if provided.
optionsStr = optionsStr.trim();
if (optionsStr) {
let optionsObject = new Function(`return ${optionsStr};`)();
if (!isEsmOutput) {
delete optionsObject.type;
}
optionsStr = JSON.stringify(optionsObject);
optionsStr = optionsStr === "{}" ? "" : `, ${optionsStr}`;
}
// tippex.match accepts only sync callback, but we want to perform &

@@ -177,3 +185,3 @@ // wait for async job here, so we track those promises separately.

workerParametersEndIndex,
`import.meta.ROLLUP_FILE_URL_${chunkRefId}${optionsStr}`
`new URL(import.meta.ROLLUP_FILE_URL_${chunkRefId}, import.meta.url)`
);

@@ -200,10 +208,48 @@ })()

resolveFileUrl(chunk) {
return `"./${chunk.fileName}"`;
return JSON.stringify(chunk.relativePath);
},
outputOptions({ format }) {
if (format === "esm" || format === "es") {
if (!opts.silenceESMWorkerWarning) {
this.warn(
'Very few browsers support ES modules in Workers. If you want to your code to run in all browsers, set `output.format = "amd";`'
);
}
// In ESM, we never prepend a loader.
isEsmOutput = () => true;
} else if (format !== "amd") {
this.error(
`\`output.format\` must either be "amd" or "esm", got "${format}"`
);
} else {
isEsmOutput = () => false;
}
},
renderDynamicImport() {
if (isEsmOutput()) return;
// In our loader, `require` simply return a promise directly.
// This is tinier and simpler output than the Rollup's default.
return {
left: 'require(',
right: ')'
};
},
resolveImportMeta(property) {
if (isEsmOutput()) return;
if (property === 'url') {
// In our loader, `module.uri` is already fully resolved
// so we can emit something shorter than the Rollup's default.
return `module.uri`;
}
},
renderChunk(code, chunk, outputOptions) {
// We don’t need to do any loader processing when targeting ESM format.
if (isEsmOutput) {
return;
}
if (isEsmOutput()) return;
if (outputOptions.banner && outputOptions.banner.length > 0) {

@@ -217,4 +263,30 @@ this.error(

tippex.match(code, workerRegexpForOutput, (fullMatch, optionsWithCommaStr, optionsStr) => {
let options;
try {
options = json5.parse(optionsStr);
} catch (e) {
// If we couldn't parse the options object, maybe it's something dynamic or has nested
// parentheses or something like that. In that case, treat it as a warning
// and not a hard error, just like we wouldn't break on unmatched regex.
console.warn("Couldn't match options object", fullMatch, ": ", e);
return;
}
if (!("type" in options)) {
// Nothing to do.
return;
}
delete options.type;
const replacementEnd = workerRegexpForOutput.lastIndex;
const replacementStart = replacementEnd - optionsWithCommaStr.length;
optionsStr = json5.stringify(options);
optionsWithCommaStr = optionsStr === "{}" ? "" : `, ${optionsStr}`;
ms.overwrite(
replacementStart,
replacementEnd,
optionsWithCommaStr
);
});
// Mangle define() call
const id = `./${chunk.fileName}`;
ms.remove(0, "define(".length);

@@ -227,3 +299,3 @@ // If the module does not have any dependencies, it’s technically okay

}
ms.prepend(`${opts.amdFunctionName}("${id}",`);
ms.prepend(`${opts.amdFunctionName}(`);

@@ -230,0 +302,0 @@ // Prepend loader if it’s an entry point or a worker file

{
"name": "@surma/rollup-plugin-off-main-thread",
"version": "2.0.0",
"version": "2.1.0",
"description": "Use Rollup with workers and ES6 modules today.",

@@ -14,2 +14,3 @@ "main": "index.js",

"chai": "4.2.0",
"chalk": "^2.4.2",
"karma": "4.2.0",

@@ -24,3 +25,3 @@ "karma-chai": "0.1.0",

"prettier": "1.18.2",
"rollup": "2.0.0-0"
"rollup": "2.2.0"
},

@@ -33,2 +34,3 @@ "repository": {

"ejs": "^2.6.1",
"json5": "^2.2.0",
"magic-string": "^0.25.0",

@@ -35,0 +37,0 @@ "tippex": "^3.0.0"

@@ -18,2 +18,3 @@ /**

const fs = require("fs");
const chalk = require("chalk");

@@ -57,3 +58,23 @@ const karma = require("karma");

input,
strictDeprecations: true
strictDeprecations: true,
// Copied / adapted from default `onwarn` in Rollup CLI.
onwarn: warning => {
console.warn(`⚠️ ${chalk.bold(warning.message)}`);
if (warning.url) {
console.warn(chalk.cyan(warning.url));
}
if (warning.loc) {
console.warn(
`${warning.loc.file} (${warning.loc.line}:${warning.loc.column})`
);
}
if (warning.frame) {
console.warn(chalk.dim(warning.frame));
}
console.warn("");
}
};

@@ -60,0 +81,0 @@ const rollupConfigPath = "./" + path.join(pathName, "rollup.config.js");

@@ -14,5 +14,8 @@ /**

export default async function() {
const { default: f } = await import("./b.js");
export default async function(f) {
self.postMessage(f());
}
export function someValue() {
return self.String("a");
}

@@ -14,4 +14,8 @@ /**

// Import for side-effects (of which there are none)
// to make sure that a.js gets its own chunk.
import {someValue} from "./a.js";
export default function() {
return "a";
return someValue();
}

@@ -15,4 +15,4 @@ /**

import a from "./a.js";
a();
import("./b.js");
import("./b.js").then(({default: f}) => {
a(f);
})

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc