11/* eslint-disable @typescript-eslint/ban-ts-comment */
2- // @ts -nocheck
3-
4- import { Engine } from '@rocket/engine/server' ;
5- import { gatherFiles } from '@rocket/engine' ;
6-
7- import { fromRollup } from '@web/dev-server-rollup' ;
8-
9- import { rollup } from 'rollup' ;
102import path from 'path' ;
11- import { rollupPluginHTML } from '@web/rollup-plugin-html' ;
123
13- import { createMpaConfig , createServiceWorkerConfig } from '@rocket/building-rollup' ;
14- import { adjustPluginOptions } from 'plugins-manager' ;
154import { existsSync } from 'fs' ;
16- import { readFile , unlink , writeFile } from 'fs/promises' ;
17-
18- import puppeteer from 'puppeteer' ;
19-
20- /**
21- * @param {object } config
22- */
23- async function buildAndWrite ( config ) {
24- const bundle = await rollup ( config ) ;
25-
26- if ( Array . isArray ( config . output ) ) {
27- await bundle . write ( config . output [ 0 ] ) ;
28- await bundle . write ( config . output [ 1 ] ) ;
29- } else {
30- await bundle . write ( config . output ) ;
31- }
32- }
33-
34- async function productionBuild ( config ) {
35- const defaultSetupPlugins = [ ] ;
36- if ( config . pathPrefix ) {
37- defaultSetupPlugins . push (
38- adjustPluginOptions ( rollupPluginHTML , { absolutePathPrefix : config . pathPrefix } ) ,
39- ) ;
40- }
41-
42- const mpaConfig = createMpaConfig ( {
43- input : '**/*.html' ,
44- output : {
45- dir : config . outputDir ,
46- } ,
47- // custom
48- rootDir : path . resolve ( config . outputDevDir ) ,
49- absoluteBaseUrl : config . absoluteBaseUrl ,
50- setupPlugins : [
51- ...defaultSetupPlugins ,
52- ...config . setupDevServerAndBuildPlugins ,
53- ...config . setupBuildPlugins ,
54- ] ,
55- } ) ;
56- const finalConfig =
57- typeof config . adjustBuildOptions === 'function'
58- ? config . adjustBuildOptions ( mpaConfig )
59- : mpaConfig ;
60- await buildAndWrite ( finalConfig ) ;
61-
62- const { serviceWorkerSourcePath } = config ;
63- if ( existsSync ( serviceWorkerSourcePath ) ) {
64- const serviceWorkerConfig = createServiceWorkerConfig ( {
65- input : serviceWorkerSourcePath ,
66- output : {
67- file : path . join ( path . resolve ( config . outputDir ) , config . serviceWorkerName ) ,
68- } ,
69- } ) ;
5+ import { readFile , writeFile } from 'fs/promises' ;
706
71- await buildAndWrite ( serviceWorkerConfig ) ;
72- }
73- }
7+ import { buildHtml } from './build/buildHtml.js' ;
8+ import { buildOpenGraphImages } from './build/buildOpenGraphImages.js' ;
9+ import { buildJavaScriptOptimizedOutput } from './build/buildJavaScriptOptimizedOutput.js' ;
7410
7511export class RocketBuild {
12+ /**
13+ * @param {import('commander').Command } program
14+ * @param {import('./RocketCli.js').RocketCli } cli
15+ */
7616 async setupCommand ( program , cli ) {
7717 this . cli = cli ;
7818
@@ -87,32 +27,30 @@ export class RocketBuild {
8727 }
8828
8929 async build ( ) {
30+ if ( ! this . cli ) {
31+ return ;
32+ }
33+ // for typescript as `this.cli.options.outputDir` supports other inputs as well
34+ // but the cli will normalize it to a string before calling plugins
35+ if ( typeof this . cli . options . outputDir !== 'string' ) {
36+ return ;
37+ }
38+
9039 await this . cli . events . dispatchEventDone ( 'build-start' ) ;
91- await this . cli . clearOutputDir ( ) ;
92- await this . cli . clearOutputDevDir ( ) ;
9340
94- this . engine = new Engine ( ) ;
95- this . engine . setOptions ( {
96- docsDir : this . cli . options . inputDir ,
97- outputDir : this . cli . options . outputDevDir ,
98- setupPlugins : this . cli . options . setupEnginePlugins ,
99- longFileHeaderWidth : this . cli . options . longFileHeaderWidth ,
100- longFileHeaderComment : this . cli . options . longFileHeaderComment ,
101- renderMode : 'production' ,
102- clearOutputDir : this . cli . options . clearOutputDir ,
103- } ) ;
104- console . log ( 'Engine building...' ) ;
105- await this . engine . build ( { autoStop : this . cli . options . buildAutoStop } ) ;
41+ // 1. build html
42+ this . engine = await buildHtml ( this . cli ) ;
10643
44+ // 2. build open graph images
10745 if ( this . cli . options . buildOpenGraphImages ) {
10846 console . log ( 'Generating Open Graph Images...' ) ;
109- await this . buildOpenGraphImages ( ) ;
47+ await buildOpenGraphImages ( this . cli ) ;
11048 }
11149
112- if ( this . cli . options . buildOptimize ) {
50+ // 3. build optimized output
51+ if ( this . cli . options . buildOptimize && this . engine ) {
11352 console . log ( 'Optimize Production Build...' ) ;
114- await productionBuild ( this . cli . options ) ;
115- await this . engine . copyPublicFilesTo ( this . cli . options . outputDir ) ;
53+ await buildJavaScriptOptimizedOutput ( this . cli , this . engine ) ;
11654 }
11755
11856 // hackfix 404.html by making all asset urls absolute (rollup always makes them relative) which will break if netlify serves the content form a different url
@@ -130,87 +68,4 @@ export class RocketBuild {
13068
13169 await this . cli . events . dispatchEventDone ( 'build-end' ) ;
13270 }
133-
134- async buildOpenGraphImages ( ) {
135- const openGraphFiles = await gatherFiles ( this . cli . options . outputDevDir , {
136- fileEndings : [ '.opengraph.html' ] ,
137- } ) ;
138- if ( openGraphFiles . length === 0 ) {
139- return ;
140- }
141-
142- // TODO: enable URL support in the Engine and remove this "workaround"
143- if (
144- typeof this . cli . options . inputDir !== 'string' ||
145- typeof this . cli . options . outputDevDir !== 'string'
146- ) {
147- return ;
148- }
149-
150- const withWrap = this . cli . options . setupDevServerAndBuildPlugins
151- ? this . cli . options . setupDevServerAndBuildPlugins . map ( modFunction => {
152- modFunction . wrapPlugin = fromRollup ;
153- return modFunction ;
154- } )
155- : [ ] ;
156-
157- this . engine = new Engine ( ) ;
158- this . engine . setOptions ( {
159- docsDir : this . cli . options . inputDir ,
160- outputDir : this . cli . options . outputDevDir ,
161- setupPlugins : this . cli . options . setupEnginePlugins ,
162- open : false ,
163- clearOutputDir : false ,
164- adjustDevServerOptions : this . cli . options . adjustDevServerOptions ,
165- setupDevServerMiddleware : this . cli . options . setupDevServerMiddleware ,
166- setupDevServerPlugins : [ ...this . cli . options . setupDevServerPlugins , ...withWrap ] ,
167- } ) ;
168- try {
169- await this . engine . start ( ) ;
170-
171- const browser = await puppeteer . launch ( ) ;
172- const page = await browser . newPage ( ) ;
173-
174- // In 2022 Twitter & Facebook recommend a size of 1200x628 - we capture with 2 dpr for retina displays
175- await page . setViewport ( {
176- width : 1200 ,
177- height : 628 ,
178- deviceScaleFactor : 2 ,
179- } ) ;
180-
181- for ( const openGraphFile of openGraphFiles ) {
182- const relUrl = path . relative ( this . cli . options . outputDevDir , openGraphFile ) ;
183- const imagePath = openGraphFile . replace ( '.opengraph.html' , '.opengraph.png' ) ;
184- const htmlPath = openGraphFile . replace ( '.opengraph.html' , '.html' ) ;
185- const relImageUrl = path . basename ( imagePath ) ;
186-
187- let htmlString = await readFile ( htmlPath , 'utf8' ) ;
188- if ( ! htmlString . includes ( '<meta property="og:image"' ) ) {
189- if ( htmlString . includes ( '</head>' ) ) {
190- htmlString = htmlString . replace (
191- '</head>' ,
192- [
193- ' <meta property="og:image:width" content="2400">' ,
194- ' <meta property="og:image:height" content="1256">' ,
195- ` <meta property="og:image" content="./${ relImageUrl } ">` ,
196- ' </head>' ,
197- ] . join ( '\n' ) ,
198- ) ;
199- }
200- }
201- const url = `http://localhost:${ this . engine . devServer . config . port } /${ relUrl } ` ;
202- await page . goto ( url , { waitUntil : 'networkidle0' } ) ;
203- await page . screenshot ( { path : imagePath } ) ;
204-
205- await unlink ( openGraphFile ) ;
206- await writeFile ( htmlPath , htmlString ) ;
207- }
208- await browser . close ( ) ;
209-
210- await this . engine . stop ( ) ;
211- } catch ( e ) {
212- console . log ( 'Could not start dev server to generate open graph images' ) ;
213- console . error ( e ) ;
214- }
215- }
21671}
0 commit comments