Skip to content

Commit 1f28d44

Browse files
committed
use esbuild instead of webpack
1 parent c48beb7 commit 1f28d44

File tree

10 files changed

+2748
-14385
lines changed

10 files changed

+2748
-14385
lines changed

.babelrc

Lines changed: 0 additions & 3 deletions
This file was deleted.

bootstrap.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
exit;
2121
}
2222

23+
define(__NAMESPACE__ . '\\MAIN_FILE', __FILE__);
24+
define(__NAMESPACE__ . '\\BASENAME', plugin_basename(MAIN_FILE));
25+
define(__NAMESPACE__ . '\\DIR_PATH', plugin_dir_path(MAIN_FILE));
26+
define(__NAMESPACE__ . '\\DIR_URL', plugin_dir_url(MAIN_FILE));
27+
2328
const ADMIN_PAGE_SLUG = 'kwio-react-page';
2429

2530
add_action('admin_menu', function () {
@@ -43,7 +48,7 @@ function () {
4348
return;
4449
}
4550

46-
$assetManifestFile = plugin_dir_path(__FILE__) . 'dist/app.asset.php';
51+
$assetManifestFile = DIR_PATH . 'dist/app.asset.php';
4752
if (!file_exists($assetManifestFile)) {
4853
return;
4954
}
@@ -52,22 +57,22 @@ function () {
5257

5358
wp_enqueue_script(
5459
ADMIN_PAGE_SLUG,
55-
plugin_dir_url(__FILE__) . 'dist/app.js',
60+
DIR_URL . 'dist/app.js',
5661
$assetManifest['dependencies'],
5762
$assetManifest['version']
5863
);
5964

6065
wp_set_script_translations(
6166
ADMIN_PAGE_SLUG,
6267
'wp-react-page-admin-example',
63-
plugin_dir_path(__FILE__) . 'lang'
68+
DIR_PATH . 'lang'
6469
);
6570

6671
wp_enqueue_style(
6772
ADMIN_PAGE_SLUG,
68-
plugin_dir_url(__FILE__) . 'dist/app.css',
73+
DIR_URL . 'dist/app.css',
6974
['wp-components'],
70-
filemtime(plugin_dir_path(__FILE__) . 'dist/app.css')
75+
filemtime(DIR_PATH . 'dist/app.css')
7176
);
7277
});
7378

declaration.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
declare module '*.module.scss' {
1+
declare module '*.module.css' {
22
const content: Record<string, string>;
33
export default content;
44
}

esbuild.mjs

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
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: /^react|react-dom$/ }, (args) => ({
12+
path: args.path,
13+
namespace: 'wp-element',
14+
}));
15+
currentBuild.onLoad({ filter: /^react\/jsx-runtime$/ }, () => ({
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

Comments
 (0)