mirror of
				https://github.com/home-assistant/frontend.git
				synced 2025-10-30 22:19:55 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			150 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // Worker plugin
 | |
| // Each worker will include all of its dependencies
 | |
| // instead of relying on an importer.
 | |
| 
 | |
| // Forked from v.1.4.1
 | |
| // https://github.com/surma/rollup-plugin-off-main-thread
 | |
| /**
 | |
|  * Copyright 2018 Google Inc. All Rights Reserved.
 | |
|  * 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.
 | |
|  */
 | |
| 
 | |
| const rollup = require("rollup");
 | |
| const path = require("path");
 | |
| const MagicString = require("magic-string");
 | |
| 
 | |
| const defaultOpts = {
 | |
|   // A RegExp to find `new Workers()` calls. The second capture group _must_
 | |
|   // capture the provided file name without the quotes.
 | |
|   workerRegexp: /new Worker\((["'])(.+?)\1(,[^)]+)?\)/g,
 | |
|   plugins: ["node-resolve", "commonjs", "babel", "terser", "ignore"],
 | |
| };
 | |
| 
 | |
| async function getBundledWorker(workerPath, rollupOptions) {
 | |
|   const bundle = await rollup.rollup({
 | |
|     ...rollupOptions,
 | |
|     input: {
 | |
|       worker: workerPath,
 | |
|     },
 | |
|   });
 | |
|   const { output } = await bundle.generate({
 | |
|     // Generates cleanest output, we shouldn't have any imports/exports
 | |
|     // that would be incompatible with ES5.
 | |
|     format: "es",
 | |
|     // We should not export anything. This will fail build if we are.
 | |
|     exports: "none",
 | |
|   });
 | |
| 
 | |
|   let code;
 | |
| 
 | |
|   for (const chunkOrAsset of output) {
 | |
|     if (chunkOrAsset.name === "worker") {
 | |
|       code = chunkOrAsset.code;
 | |
|     } else if (chunkOrAsset.type !== "asset") {
 | |
|       throw new Error("Unexpected extra output");
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return code;
 | |
| }
 | |
| 
 | |
| module.exports = function (opts = {}) {
 | |
|   opts = { ...defaultOpts, ...opts };
 | |
| 
 | |
|   let rollupOptions;
 | |
|   let refIds;
 | |
| 
 | |
|   return {
 | |
|     name: "hass-worker",
 | |
| 
 | |
|     async buildStart(options) {
 | |
|       refIds = {};
 | |
|       rollupOptions = {
 | |
|         plugins: options.plugins.filter((plugin) =>
 | |
|           opts.plugins.includes(plugin.name)
 | |
|         ),
 | |
|       };
 | |
|     },
 | |
| 
 | |
|     async transform(code, id) {
 | |
|       // Copy the regexp as they are stateful and this hook is async.
 | |
|       const workerRegexp = new RegExp(
 | |
|         opts.workerRegexp.source,
 | |
|         opts.workerRegexp.flags
 | |
|       );
 | |
|       if (!workerRegexp.test(code)) {
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       const ms = new MagicString(code);
 | |
|       // Reset the regexp
 | |
|       workerRegexp.lastIndex = 0;
 | |
|       while (true) {
 | |
|         const match = workerRegexp.exec(code);
 | |
|         if (!match) {
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|         const workerFile = match[2];
 | |
|         let optionsObject = {};
 | |
|         // Parse the optional options object
 | |
|         if (match[3] && match[3].length > 0) {
 | |
|           // FIXME: ooooof!
 | |
|           optionsObject = new Function(`return ${match[3].slice(1)};`)();
 | |
|         }
 | |
|         delete optionsObject.type;
 | |
| 
 | |
|         if (!new RegExp("^.*/").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}".`
 | |
|           );
 | |
|           continue;
 | |
|         }
 | |
| 
 | |
|         // Find worker file and store it as a chunk with ID prefixed for our loader
 | |
|         const resolvedWorkerFile = (await this.resolve(workerFile, id)).id;
 | |
|         let chunkRefId;
 | |
|         if (resolvedWorkerFile in refIds) {
 | |
|           chunkRefId = refIds[resolvedWorkerFile];
 | |
|         } else {
 | |
|           this.addWatchFile(resolvedWorkerFile);
 | |
|           const source = await getBundledWorker(
 | |
|             resolvedWorkerFile,
 | |
|             rollupOptions
 | |
|           );
 | |
|           chunkRefId = refIds[resolvedWorkerFile] = this.emitFile({
 | |
|             name: path.basename(resolvedWorkerFile),
 | |
|             source,
 | |
|             type: "asset",
 | |
|           });
 | |
|         }
 | |
| 
 | |
|         const workerParametersStartIndex = match.index + "new Worker(".length;
 | |
|         const workerParametersEndIndex =
 | |
|           match.index + match[0].length - ")".length;
 | |
| 
 | |
|         ms.overwrite(
 | |
|           workerParametersStartIndex,
 | |
|           workerParametersEndIndex,
 | |
|           `import.meta.ROLLUP_FILE_URL_${chunkRefId}, ${JSON.stringify(
 | |
|             optionsObject
 | |
|           )}`
 | |
|         );
 | |
|       }
 | |
| 
 | |
|       return {
 | |
|         code: ms.toString(),
 | |
|         map: ms.generateMap({ hires: true }),
 | |
|       };
 | |
|     },
 | |
|   };
 | |
| };
 | 
