mirror of
				https://github.com/home-assistant/frontend.git
				synced 2025-10-30 22:19:55 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			234 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			234 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // Tasks to generate entry HTML
 | |
| 
 | |
| import fs from "fs-extra";
 | |
| import gulp from "gulp";
 | |
| import { minify } from "html-minifier-terser";
 | |
| import template from "lodash.template";
 | |
| import path from "path";
 | |
| import { htmlMinifierOptions, terserOptions } from "../bundle.cjs";
 | |
| import env from "../env.cjs";
 | |
| import paths from "../paths.cjs";
 | |
| 
 | |
| const renderTemplate = (templateFile, data = {}) => {
 | |
|   const compiled = template(
 | |
|     fs.readFileSync(templateFile, { encoding: "utf-8" })
 | |
|   );
 | |
|   return compiled({
 | |
|     ...data,
 | |
|     useRollup: env.useRollup(),
 | |
|     useWDS: env.useWDS(),
 | |
|     // Resolve any child/nested templates relative to the parent and pass the same data
 | |
|     renderTemplate: (childTemplate) =>
 | |
|       renderTemplate(
 | |
|         path.resolve(path.dirname(templateFile), childTemplate),
 | |
|         data
 | |
|       ),
 | |
|   });
 | |
| };
 | |
| 
 | |
| const WRAP_TAGS = { ".js": "script", ".css": "style" };
 | |
| 
 | |
| const minifyHtml = (content, ext) => {
 | |
|   const wrapTag = WRAP_TAGS[ext] || "";
 | |
|   const begTag = wrapTag && `<${wrapTag}>`;
 | |
|   const endTag = wrapTag && `</${wrapTag}>`;
 | |
|   return minify(begTag + content + endTag, {
 | |
|     ...htmlMinifierOptions,
 | |
|     conservativeCollapse: false,
 | |
|     minifyJS: terserOptions({
 | |
|       latestBuild: false, // Shared scripts should be ES5
 | |
|       isTestBuild: true, // Don't need source maps
 | |
|     }),
 | |
|   }).then((wrapped) =>
 | |
|     wrapTag ? wrapped.slice(begTag.length, -endTag.length) : wrapped
 | |
|   );
 | |
| };
 | |
| 
 | |
| // Function to generate a dev task for each project's configuration
 | |
| // Note Currently WDS paths are hard-coded to only work for app
 | |
| const genPagesDevTask =
 | |
|   (
 | |
|     pageEntries,
 | |
|     inputRoot,
 | |
|     outputRoot,
 | |
|     useWDS = false,
 | |
|     inputSub = "src/html",
 | |
|     publicRoot = ""
 | |
|   ) =>
 | |
|   async () => {
 | |
|     for (const [page, entries] of Object.entries(pageEntries)) {
 | |
|       const content = renderTemplate(
 | |
|         path.resolve(inputRoot, inputSub, `${page}.template`),
 | |
|         {
 | |
|           latestEntryJS: entries.map((entry) =>
 | |
|             useWDS
 | |
|               ? `http://localhost:8000/src/entrypoints/${entry}.ts`
 | |
|               : `${publicRoot}/frontend_latest/${entry}.js`
 | |
|           ),
 | |
|           es5EntryJS: entries.map(
 | |
|             (entry) => `${publicRoot}/frontend_es5/${entry}.js`
 | |
|           ),
 | |
|           latestCustomPanelJS: useWDS
 | |
|             ? "http://localhost:8000/src/entrypoints/custom-panel.ts"
 | |
|             : `${publicRoot}/frontend_latest/custom-panel.js`,
 | |
|           es5CustomPanelJS: `${publicRoot}/frontend_es5/custom-panel.js`,
 | |
|         }
 | |
|       );
 | |
|       fs.outputFileSync(path.resolve(outputRoot, page), content);
 | |
|     }
 | |
|   };
 | |
| 
 | |
| // Same as previous but for production builds
 | |
| // (includes minification and hashed file names from manifest)
 | |
| const genPagesProdTask =
 | |
|   (
 | |
|     pageEntries,
 | |
|     inputRoot,
 | |
|     outputRoot,
 | |
|     outputLatest,
 | |
|     outputES5,
 | |
|     inputSub = "src/html"
 | |
|   ) =>
 | |
|   async () => {
 | |
|     const latestManifest = fs.readJsonSync(
 | |
|       path.resolve(outputLatest, "manifest.json")
 | |
|     );
 | |
|     const es5Manifest = outputES5
 | |
|       ? fs.readJsonSync(path.resolve(outputES5, "manifest.json"))
 | |
|       : {};
 | |
|     const minifiedHTML = [];
 | |
|     for (const [page, entries] of Object.entries(pageEntries)) {
 | |
|       const content = renderTemplate(
 | |
|         path.resolve(inputRoot, inputSub, `${page}.template`),
 | |
|         {
 | |
|           latestEntryJS: entries.map((entry) => latestManifest[`${entry}.js`]),
 | |
|           es5EntryJS: entries.map((entry) => es5Manifest[`${entry}.js`]),
 | |
|           latestCustomPanelJS: latestManifest["custom-panel.js"],
 | |
|           es5CustomPanelJS: es5Manifest["custom-panel.js"],
 | |
|         }
 | |
|       );
 | |
|       minifiedHTML.push(
 | |
|         minifyHtml(content, path.extname(page)).then((minified) =>
 | |
|           fs.outputFileSync(path.resolve(outputRoot, page), minified)
 | |
|         )
 | |
|       );
 | |
|     }
 | |
|     await Promise.all(minifiedHTML);
 | |
|   };
 | |
| 
 | |
| // Map HTML pages to their required entrypoints
 | |
| const APP_PAGE_ENTRIES = {
 | |
|   "authorize.html": ["authorize"],
 | |
|   "onboarding.html": ["onboarding"],
 | |
|   "index.html": ["core", "app"],
 | |
| };
 | |
| 
 | |
| gulp.task(
 | |
|   "gen-pages-app-dev",
 | |
|   genPagesDevTask(
 | |
|     APP_PAGE_ENTRIES,
 | |
|     paths.polymer_dir,
 | |
|     paths.app_output_root,
 | |
|     env.useWDS()
 | |
|   )
 | |
| );
 | |
| 
 | |
| gulp.task(
 | |
|   "gen-pages-app-prod",
 | |
|   genPagesProdTask(
 | |
|     APP_PAGE_ENTRIES,
 | |
|     paths.polymer_dir,
 | |
|     paths.app_output_root,
 | |
|     paths.app_output_latest,
 | |
|     paths.app_output_es5
 | |
|   )
 | |
| );
 | |
| 
 | |
| const CAST_PAGE_ENTRIES = {
 | |
|   "faq.html": ["launcher"],
 | |
|   "index.html": ["launcher"],
 | |
|   "media.html": ["media"],
 | |
|   "receiver.html": ["receiver"],
 | |
| };
 | |
| 
 | |
| gulp.task(
 | |
|   "gen-pages-cast-dev",
 | |
|   genPagesDevTask(CAST_PAGE_ENTRIES, paths.cast_dir, paths.cast_output_root)
 | |
| );
 | |
| 
 | |
| gulp.task(
 | |
|   "gen-pages-cast-prod",
 | |
|   genPagesProdTask(
 | |
|     CAST_PAGE_ENTRIES,
 | |
|     paths.cast_dir,
 | |
|     paths.cast_output_root,
 | |
|     paths.cast_output_latest,
 | |
|     paths.cast_output_es5
 | |
|   )
 | |
| );
 | |
| 
 | |
| const DEMO_PAGE_ENTRIES = { "index.html": ["main"] };
 | |
| 
 | |
| gulp.task(
 | |
|   "gen-pages-demo-dev",
 | |
|   genPagesDevTask(DEMO_PAGE_ENTRIES, paths.demo_dir, paths.demo_output_root)
 | |
| );
 | |
| 
 | |
| gulp.task(
 | |
|   "gen-pages-demo-prod",
 | |
|   genPagesProdTask(
 | |
|     DEMO_PAGE_ENTRIES,
 | |
|     paths.demo_dir,
 | |
|     paths.demo_output_root,
 | |
|     paths.demo_output_latest,
 | |
|     paths.demo_output_es5
 | |
|   )
 | |
| );
 | |
| 
 | |
| const GALLERY_PAGE_ENTRIES = { "index.html": ["entrypoint"] };
 | |
| 
 | |
| gulp.task(
 | |
|   "gen-pages-gallery-dev",
 | |
|   genPagesDevTask(
 | |
|     GALLERY_PAGE_ENTRIES,
 | |
|     paths.gallery_dir,
 | |
|     paths.gallery_output_root
 | |
|   )
 | |
| );
 | |
| 
 | |
| gulp.task(
 | |
|   "gen-pages-gallery-prod",
 | |
|   genPagesProdTask(
 | |
|     GALLERY_PAGE_ENTRIES,
 | |
|     paths.gallery_dir,
 | |
|     paths.gallery_output_root,
 | |
|     paths.gallery_output_latest
 | |
|   )
 | |
| );
 | |
| 
 | |
| const HASSIO_PAGE_ENTRIES = { "entrypoint.js": ["entrypoint"] };
 | |
| 
 | |
| gulp.task(
 | |
|   "gen-pages-hassio-dev",
 | |
|   genPagesDevTask(
 | |
|     HASSIO_PAGE_ENTRIES,
 | |
|     paths.hassio_dir,
 | |
|     paths.hassio_output_root,
 | |
|     undefined,
 | |
|     "src",
 | |
|     paths.hassio_publicPath
 | |
|   )
 | |
| );
 | |
| 
 | |
| gulp.task(
 | |
|   "gen-pages-hassio-prod",
 | |
|   genPagesProdTask(
 | |
|     HASSIO_PAGE_ENTRIES,
 | |
|     paths.hassio_dir,
 | |
|     paths.hassio_output_root,
 | |
|     paths.hassio_output_latest,
 | |
|     paths.hassio_output_es5,
 | |
|     "src"
 | |
|   )
 | |
| );
 | 
