1+ import * as esbuild from 'esbuild' ;
2+ import fs from 'fs' ;
3+ import crypto from 'crypto' ;
4+
5+ const isWatchMode = process . argv . includes ( '--watch' ) ;
6+
7+ // https://gist.github.com/adamziel/ab4bf95756d70c1aefd1dc56fbed2c62
8+ const wpDepsPlugin = {
9+ name : 'import-wordpress-deps' ,
10+ setup ( currentBuild ) {
11+ currentBuild . onResolve ( { filter : / ^ r e a c t | r e a c t - d o m $ / } , ( args ) => ( {
12+ path : args . path ,
13+ namespace : 'wp-element' ,
14+ } ) ) ;
15+ currentBuild . onLoad ( { filter : / ^ r e a c t \/ j s x - r u n t i m e $ / } , ( ) => ( {
16+ contents :
17+ 'module.exports = { default: window.ReactJSXRuntime, ...window.ReactJSXRuntime }' ,
18+ loader : 'js' ,
19+ } ) ) ;
20+ currentBuild . onLoad ( { filter : / .* / , namespace : 'wp-element' } , ( ) => ( {
21+ contents :
22+ 'module.exports = { default: window.wp.element, ...window.wp.element }' ,
23+ loader : 'js' ,
24+ } ) ) ;
25+
26+ const wpImportMap = {
27+ '@wordpress/a11y' : 'wp.a11y' ,
28+ '@wordpress/api-fetch' : 'wp.apiFetch' ,
29+ '@wordpress/autop' : 'wp.autop' ,
30+ '@wordpress/blob' : 'wp.blob' ,
31+ '@wordpress/block-directory' : 'wp.blockDirectory' ,
32+ '@wordpress/block-editor' : 'wp.blockEditor' ,
33+ '@wordpress/block-library' : 'wp.blockLibrary' ,
34+ '@wordpress/block-serialization-default-parser' :
35+ 'wp.blockSerializationDefaultParser' ,
36+ '@wordpress/blocks' : 'wp.blocks' ,
37+ '@wordpress/components' : 'wp.components' ,
38+ '@wordpress/compose' : 'wp.compose' ,
39+ '@wordpress/core-data' : 'wp.coreData' ,
40+ '@wordpress/data' : 'wp.data' ,
41+ '@wordpress/date' : 'wp.date' ,
42+ '@wordpress/deprecated' : 'wp.deprecated' ,
43+ '@wordpress/dom' : 'wp.dom' ,
44+ '@wordpress/dom-ready' : 'wp.domReady' ,
45+ '@wordpress/edit-navigation' : 'wp.editNavigation' ,
46+ '@wordpress/edit-post' : 'wp.editPost' ,
47+ '@wordpress/edit-site' : 'wp.editSite' ,
48+ '@wordpress/edit-widgets' : 'wp.editWidgets' ,
49+ '@wordpress/editor' : 'wp.editor' ,
50+ '@wordpress/element' : 'wp.element' ,
51+ '@wordpress/escape-html' : 'wp.escapeHtml' ,
52+ '@wordpress/format-library' : 'wp.formatLibrary' ,
53+ '@wordpress/hooks' : 'wp.hooks' ,
54+ '@wordpress/html-entities' : 'wp.htmlEntities' ,
55+ '@wordpress/i18n' : 'wp.i18n' ,
56+ '@wordpress/icons' : 'wp.icons' ,
57+ '@wordpress/is-shallow-equal' : 'wp.isShallowEqual' ,
58+ '@wordpress/keyboard-shortcuts' : 'wp.keyboardShortcuts' ,
59+ '@wordpress/keycodes' : 'wp.keycodes' ,
60+ '@wordpress/notices' : 'wp.notices' ,
61+ '@wordpress/nux' : 'wp.nux' ,
62+ '@wordpress/plugins' : 'wp.plugins' ,
63+ '@wordpress/preferences' : 'wp.preferences' ,
64+ '@wordpress/preferences-persistence' : 'wp.preferencesPersistence' ,
65+ '@wordpress/primitives' : 'wp.primitives' ,
66+ '@wordpress/reusable-blocks' : 'wp.reusableBlocks' ,
67+ '@wordpress/rich-text' : 'wp.richText' ,
68+ '@wordpress/shortcode' : 'wp.shortcode' ,
69+ '@wordpress/url' : 'wp.url' ,
70+ '@wordpress/viewport' : 'wp.viewport' ,
71+ '@wordpress/warning' : 'wp.warning' ,
72+ '@wordpress/widgets' : 'wp.widgets' ,
73+ '@wordpress/wordcount' : 'wp.wordcount' ,
74+ } ;
75+
76+ const resolvedWpDeps = new Set ( ) ;
77+ for ( const [ src , dest ] of Object . entries ( wpImportMap ) ) {
78+ currentBuild . onResolve ( { filter : new RegExp ( `^${ src } $` ) } , ( args ) => {
79+ resolvedWpDeps . add ( dest ) ;
80+ return {
81+ path : args . path ,
82+ namespace : src ,
83+ } ;
84+ } ) ;
85+ currentBuild . onLoad ( { filter : / .* / , namespace : src } , ( ) => {
86+ return {
87+ contents : 'module.exports = ' + dest ,
88+ loader : 'js' ,
89+ } ;
90+ } ) ;
91+ }
92+
93+ currentBuild . onEnd ( ( ) => {
94+ // Get all entrypoints
95+ const entrypoints = currentBuild . initialOptions . entryPoints ;
96+ const deps = JSON . stringify (
97+ [ ...resolvedWpDeps ]
98+ // wp.element to wp-element
99+ . map ( ( dep ) => dep . replace ( '.' , '-' ) )
100+ // wp-blockEditor to wp-block-editor
101+ . map ( ( dep ) =>
102+ dep . replace ( / [ A - Z ] / g, ( letter ) => `-${ letter . toLowerCase ( ) } ` )
103+ )
104+ ) ;
105+ // Get all built files paths
106+ for ( const outfile in entrypoints ) {
107+ const builtFile =
108+ currentBuild . initialOptions . outdir + '/' + outfile + '.js' ;
109+ const hash = hashFiles ( [ builtFile ] ) ;
110+ const hashesFile =
111+ currentBuild . initialOptions . outdir + `/${ outfile } .asset.php` ;
112+ // Write hash and deps to a PHP file
113+ fs . writeFileSync (
114+ hashesFile ,
115+ `<?php return array(
116+ 'version' => '${ hash } ',
117+ 'dependencies' => ${ deps }
118+ );
119+ `
120+ ) ;
121+ }
122+ } ) ;
123+ } ,
124+ } ;
125+
126+ const buildOptions = {
127+ entryPoints : {
128+ app : './src/entry.jsx'
129+ } ,
130+ outdir : 'dist' ,
131+ bundle : true ,
132+ minify : ! isWatchMode ,
133+ sourcemap : isWatchMode ,
134+ target : 'es6' ,
135+ logLevel : 'info' ,
136+ platform : 'browser' ,
137+ jsxFactory : 'wp.element.createElement' ,
138+ jsxImportSource : 'react' ,
139+ jsxFragment : 'wp.element.Fragment' ,
140+ plugins : [
141+ wpDepsPlugin ,
142+ cleanup ( )
143+ ]
144+ } ;
145+
146+ if ( isWatchMode ) {
147+ let ctx = await esbuild . context ( buildOptions ) ;
148+ await ctx . watch ( ) ;
149+ console . log ( 'Watching...' ) ;
150+ } else {
151+ console . log ( 'Building...' ) ;
152+ await esbuild . build ( buildOptions ) ;
153+ }
154+
155+ function hashFiles ( filePaths ) {
156+ // if all files exist
157+ if ( ! filePaths . every ( fs . existsSync ) ) {
158+ return '' ;
159+ }
160+ return sha256 (
161+ Buffer . concat ( filePaths . map ( ( filePath ) => fs . readFileSync ( filePath ) ) )
162+ ) ;
163+ }
164+
165+ function cleanup ( ) {
166+ return {
167+ name : 'cleanupFiles' ,
168+ setup ( build ) {
169+ const options = build . initialOptions ;
170+ build . onStart ( ( ) => {
171+ fs . readdirSync ( options . outdir ) . forEach ( ( path ) => {
172+ fs . unlinkSync ( options . outdir + '/' + path ) ;
173+ } ) ;
174+ } ) ;
175+ } ,
176+ } ;
177+ }
178+
179+ function sha256 ( buffer ) {
180+ const hash = crypto . createHash ( 'sha256' ) ;
181+ hash . update ( buffer ) ;
182+ return hash . digest ( 'hex' ) ;
183+ }
0 commit comments