-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove unnecessary build steps from dev environments #25077
Comments
We could also use HTM instead of JSX, which would remove the need to transpile in dev environments. Coupled with modern browser support for ES6, There's some runtime overhead with that approach, but there's a Babel plugin that could be used to transpile for production builds. cc @gziolo, beyond just contributions to Gutenberg itself, I think that could remove a huge barrier for plugin devs wanting to use |
I built a small proof-of-concept, and it's working fairly well so far. It should also be possible to transpile JSX in the browser, instead of using HTM. That'd make it an easier transition, although it'd probably be slower than HTM. As long as it's fast enough for small/medium-sized projects, though, I think that could be a good starting point, and people could add complexity as they need it. |
Some related projects in the JS space: I don't think they remove the need for tooling but they try to resolve some of the issues that exist. HTM is a very interesting alternative for JSX but it depends on ESNext and template literals in particular. Gutenberg still supports IE11 so the step for transpiling code to ES5 is mandatory to use many of the features that you assume as standard these days. I think this is a great topic to raise in the weekly Core JS chats. Feel free to add it to the agenda at: |
Those look great! I ended up using Snowpack in the proof-of-concept, which itself uses esbuild under the hood. I think those have a lot of potential too.
Is it mandatory for the development workflow, or just for production output? All modern browsers support template literals, and IMO it's safe to assume that the vast majority of devs are using modern browsers. For the small fraction of devs using IE11, it'd still be easy to allow them to load the build files in their dev environments, while everyone else can use the source files directly. The proof of concept -- (which has evolved a lot in the past week) -- shows those use cases in action -- devs w/ old browsers would just run the |
Just a note regarding HTM and browser support: HTM itself actually supports IE11 and is published as ES5. Tagged Templates must be transpiled for that browser, but HTM manually implements callsite-based caching in order to circumvent Safari 10-12 issues, which ends up benefitting IE11. The typical solution is to compile HTM in production using babel-plugn-htm, which produces the same hyperscript-like function calls JSX compiles to: // input
html`<button onClick=${click} ...${props}>Hello ${world}</button>`;
// output
React.createElement("button", Object.assign({ onClick: click }, props), "Hello ", world); |
One thing that might be worth considering: from what I gather, these files are served by PHP and could be processed minimally as part of that. It's not perfect, but a simple tokenizer-based JSX transformation like this gross regex could be easily ported to PHP, which would allow authoring in JSX but then sending HTM over the wire. // file: foo.js
const Foo = props => (
<div className="foo">
<h1>Hello {props.name}</h1>
<ul>{props.items.map(item => (
<li>{item}</li>
))}</ul>
</div>
);
// would be served as:
const Foo = props => html`
<div className="foo">
<h1>Hello ${props.name}</h1>
<ul>${props.items.map(item => html`
<li>${item}</li>
`)}</ul>
</div>
); This has the rather pleasant benefit of being easy to debug without SourceMaps. Nesting, variables and loops are exactly as they appear, rather than sourcemapped from different positions or across files. Wherever you're introducing the UMD bundles for React etc would then also include HTM: <script src="https://unpkg.com/react"></script>
<script src="https://unpkg.com/react-dom"></script>
<script src="https://unpkg.com/htm"></script>
<script>window.html = htm.bind(React.createElement);</script> |
@developit, thank you for sharing more details about ways to better integrate HTM 👍🏻
Right, my point was that you need to transpile source code to support IE11 which this proposal tries to avoid. Well, at least in development. |
Cross-linking the thread from the WordPress Slack (the link requires registration at https://make.wordpress.org/chat/: https://wordpress.slack.com/archives/C5UNMSU4R/p1615573177193800 The highlight would be the article from @aduth where he explains how to use Snowpack (previously Pik) to set everything up: |
Some more links:
|
Another link to share, a comparison of a new generation of build tools: https://css-tricks.com/comparing-the-new-generation-of-build-tools/ |
I just noticed that there's an official codemod to convert JSX to HTM, which could come in handy if we ever want to migrate. The build task could still convert to HTML for production, though, of course. We could keep JSX if desired, though, and still get 80% of the benefit by removing all the other tooling from the dev workflow. Some of the earlier concerns may no longer be barriers since we're dropping IE11 support. |
I've done some experiments with this lately, and the results are pretty promising! I don't think ditching JSX would help much though. Instead, I think we can start by targeting modern browsers and using ES modules in dev environment. In my (naive) testing, this alone improves the performance of the build time from 28s down to 7s, that's 4 times faster (for initial build only). However, we need some tooling updates first as the foundation though. #31792 could potentially be a good first step to improve the resolution logic in ESLint. Here's roughly my plan for what's next:
IMHO, this should be a more stable migration path and is mostly backward-compatible with minimal changes in current build tooling. |
Hi Kevin,
i have done a very small example project transforming js/scss into js/css code distributable in wordpress : https://github.com/lgersman/ix-article-esbuild-2021 The bundling transforms the sourcecode (including scss imports and I utilized esbuild to do the transform. no need external plugins/deps required - just esbuild (and sass for scss). I did this experiment when i realized that both vitejs and snowpack are based on esbuild (=> so it can't be a bad idea :-)) The js transformations from Same for handling scss Maybe this code can be used as inspiration to swap out Babel with pure esbuild/sass dependencies. |
Just sharing here in case adopting esbuild is being considered: |
Next.js added an experimental SWC support recently: https://nextjs.org/blog/next-11-1. They are still working on reimplementing their custom Babel plugins to Rust so they continue to work with SWC. I think we would have to revisit what gets shipped with Babel either way because both esbuild and SWC don't play along nicely with custom transforms. In the context of Gutenberg knowing how the build process is shaped, it should be simpler to try to replace Babel with SWC. It's mostly because we use two steps:
By the way, @youknowriad started exploring how we could use ESM in WordPress in a backward-compatible fashion. In #34140 he used esbuild to move forward with the prototype 😄 |
Good morning guys, i just stumbled across https://github.com/adambrgmn/wp-bundler a js/css Bundler tailored to fit Wordpress / Gutenberg developer needs. Looks pretty well ! It's based on SWC, a JS Transpiler written in Rust and used by Parcel 2. Bonus : wp-bundler has built-in support for generating the Wordpress gettext ressources (without depending on wp-env/wp-cli i18n). Looks promisiing ! PS: I am not related to this project. |
I am working on the project that bundles wordpress blocks with vite that in turn uses esbuild to transpile everything but strugling to figure out why all assets after compile, load in the browser without errors, they are absent in the list of gutenberg blocks... |
@asolopovas Maybe a bit off-topic here… But did you make sure that the call to |
@simono I have managed to make build process to work properly. But whenever I try to do dev mode, everything loads, all block assets, but no block appear in the list of blocks. |
Hello @asolopovas, (1) Not sure if someone can/would/may help you until you provide a full/working example. => Your project references in (2) It's always a good idea to provide a as-small-as-possible sample project containing an error/bug/problem. Otherwise the friendly guys (potentially) helping you don't see the wood for the trees. (3) In your case I would start like that:
(4) also important before starting to spend time into coding software : Investigate some minutes into prior art to ensure you dont't reinvent the wheel. And in case you find a project doing what you want to do - participate ! Have a look at https://github.com/kucrut/vite-for-wp (using vitejs) or even https://github.com/adambrgmn/wp-bundler (using just plain If your software solves a problem uniquely (i.e. it is not yet-another-xxx-project) it will not so hard to find participants. My comment does not solve your issue but probably (many) of your forthcoming issues. |
@lgersman thanks for spending so much time precious responding to my questions I really mean it and appreciate it. Unfortunately even though that vite js utilizes a different approach to compiling assets then I tried to create as simple as possible representation of my issue and if you go to import {registerBlockType} from '@wordpress/blocks'
registerBlockType( 'test/test', {
edit: function () {
return <p> Hello world (from the editor)</p>;
},
save: function () {
return <p> Hola mundo (from the frontend) </p>;
},
} ); I have also spent a lot of time on https://developer.wordpress.org/block-editor/ trying to find what have I missed, but nothing helps. I have enough knowledge of the webpack to compile various projects and probably read webpack docs multiple times as well have managed to adapt all sort internal JavaScript code to be built with ViteJs. But Gutenberg blocks compile in somewhat unique way that I can’t yet grasp. During last few days I have managed to figure out the build stage of my project and successfully managed to compile the block, but it sort of does the hack during the build process by replacing But whenever I am in dev mode where it compiles each individual module with esbuild and actually imports functions the code is not recognized by the editor nor does it throw any errors that would give me a hint into my problem, and this is the part that is the most difficult. The project is a bit large I admit but because I had to account for bundling the all module, as welll as I had to include a bunch of code that would load the compiled compiled assets into wordpress, and all the development environment from wordpress to be able to run the code and see what the issue is.So even if I wanted to create a simple representation of my issue that would not be such an easy task nor the task I aware how I could do differently. If you download both repos in same folder do compose and I was also planing to implement the following https://humanmade.com/2018/11/26/hot-module-replacement-for-gutenberg-blocks/ to see If I will be able to hot swap gutenberg blocks during development rather than reloading the page on each insubstantial block change. I initially though to use webpack hmr as I saw in the article but due to long compiling time I planned to adapt it in my package and share it with everyone for a bit more comforatble development expirience. |
Hi @asolopovas,
It's actually not a hack :-) Any bundler does it this way if you transpile JavaScript for Gutenberg. An example : If you use Have a look at the browser console and evaluate
(1) Are you sure that your code is really loaded in the browser in dev mode ? (2) I remember a similar problem some time ago but are not sure if it matches your concrete problem : When the browser loads a Javascript resource and the response do not contain the correct mimetype (=> it needs to be the Module JavaScript mimetype, since ViteJS generates JavaScript modules for HMR instead of regular IIFE wrapped Javascript !) the Javascript resource gets silently not executed. Check if the mimetype of your js script in dev mode has the right mimetype
I do a lot of Gutenberg development / have the same usecase (=> HMR). If you just want to develop your Gutenberg block utlizing HMR ... there is a much simpler way without any extra tool coding : (The Gutenberg folks use it almost anyware for their code too.) In the Gutenberg repo (just clone the repo, call the build storybook npm script and open it in the browser) is a story called "Gutenberg playground" emdedding Gutenberg in a Storybook story (yes, it's really fantastic and works since 2019 :-) see https://wptavern.com/new-gutenberg-playground-offers-a-standalone-version-of-the-editor-for-testing-outside-the-wordpress-admin). I derived my own Storybook story (=> for each of my Gutenberg blocks) from there Gutenberg playground story registering/loading/referencing my blocks. The rest (HMR & stuff) is done by Storybook out of the box. You just press save in your editor and the code change immediately shows up in your currently opened Gutenberg block story. It is much easier & faster to do Gutenberg block development with a custom Gutenberg Storybook story for your block than with a manual managed wordpress/gutenberg/wp-env/vitejs environment. Plus: You can write separate Storybook stories showing/testing every aspect of your Gutenberg block. Trust me, works like a charm at no cost :-) |
Great, I am already look up Storybook... (1) I am 101% sure that everything is loaded in the browser as I can console log from the script right before registerBlock function. (2) Everything is fine with mimetypes as everything inside the script works but the registerBlock type, it also demands to add title to the component in the console, which it doesn't do when you build it for production. I wanted to modify columns and column block of wordpress and add tailwind styling features to it, thats why I decided to setup environment I kind of succeded to do it with default wordpress dev tools, but wanted to create something that works better and faster and alows me to do same work on new environment. But thats how headaches usually begin unfortunately... Hate this rule "ain't broken don't fix it" always costs me time, but the pleasure you get when you succeed is definitely worth it. |
One last guess ... you told me your code runs fine in production mode (=> where I am not sure if I would not bet that And HMR does'nt work limitless too - that's why I often reject HMR in favor of a script executed in my watch/transpile loop reloading the current browser tab (https://github.com/IONOS-WordPress/cm4all-wp-impex/blob/develop/bin/dev-refresh-browser.sh) - not as elegant as HMR but works ALWAYS and independant of tools/language/framework/... :-) |
Ok to simplify things, vite js just uses rollup js under the bonet, but does few different things than rollup. Consider block like this: import {registerBlockType} from '@wordpress/blocks'
registerBlockType( 'test/test', {
edit: function () {
return <p> Hello world (from the editor)</p>;
},
save: function () {
return <p> Hola mundo (from the frontend) </p>;
},
} ); In production because of vite-gutenberg-plugin, particularly of this file, this code turns to something like this: (function(c, a, t, o) {
'use strict';
const s = (e => e && typeof e == 'object' && 'default' in e ? e : {default: e})(a),
l = {
$schema: 'https://json.schemastore.org/block.json',
apiVersion: 2,
name: 'test/test',
title: 'Test Block',
textdomain: 'gutenberg-test',
icon: 'universal-access-alt',
category: 'layout',
example: {},
},
r = () => {
const e = o.useBlockProps({style: n});
return s.default.createElement('div', {...e}, t.__('Hello World, step 1 (from the editor).', 'gutenberg-examples'))
},
i = () => {
const e = o.useBlockProps.save({style: n});
return s.default.createElement('div', {...e}, t.__('Hello World, step 1 (from the frontend).', 'gutenberg-examples'))
},
n = {backgroundColor: '#900', color: '#fff', padding: '20px'}, {name: p, title: m} = l;
c.registerBlockType(p, {title: m, edit: r, save: i})
})(wp.blocks, window.React, wp.i18n, wp.blockEditor); and works perfectly fine. But in dev mode it has a dev server which serves all the assets that are transpiled on fly using esbuild individually from the node package themselves, so the code when loaded in the browser on request looks like compiled version of Here are couple screenshots to better understand what I mean One more cool feature about vite js is that if I add my dev workspace to chrome all error in the scripts automatically map to source files like so.
|
Have you seen that in dev mode your vite-gutenberg-plugin
<https://github.com/asolopovas/vite-gutenberg-plugin> plugin doesnt
translate the ***@***.***/blocks' import to window.wp.blocks ?
That's what I talked about in my last comment... and thats the problem.
Your mappings are just applied in build mode.
Am Mo., 12. Sept. 2022 um 14:10 Uhr schrieb Andrius Solopovas <
***@***.***>:
… Ok to simplify thinks, vite js just uses rollup js under the bonet, but
does few different things than rollup.
Consider block like this:
import {registerBlockType} from ***@***.***/blocks'
registerBlockType( 'test/test', {
edit: function () {
return <p> Hello world (from the editor)</p>;
},
save: function () {
return <p> Hola mundo (from the frontend) </p>;
},} );
In production because of vite-gutenberg-plugin
<https://github.com/asolopovas/vite-gutenberg-plugin> this code turns to
something like this:
(function(c, a, t, o) {
'use strict';
const s = (e => e && typeof e == 'object' && 'default' in e ? e : {default: e})(a),
l = {
$schema: 'https://json.schemastore.org/block.json',
apiVersion: 2,
name: 'test/test',
title: 'Test Block',
textdomain: 'gutenberg-test',
icon: 'universal-access-alt',
category: 'layout',
example: {},
},
r = () => {
const e = o.useBlockProps({style: n});
return s.default.createElement('div', {...e}, t.__('Hello World, step 1 (from the editor).', 'gutenberg-examples'))
},
i = () => {
const e = o.useBlockProps.save({style: n});
return s.default.createElement('div', {...e}, t.__('Hello World, step 1 (from the frontend).', 'gutenberg-examples'))
},
n = {backgroundColor: '#900', color: '#fff', padding: '20px'}, {name: p, title: m} = l;
c.registerBlockType(p, {title: m, edit: r, save: i})})(wp.blocks, window.React, wp.i18n, wp.blockEditor);
and works perfectly fine.
But in dev mode it has a dev server which serves all the assets that are
transpiled on fly using esbuild individually from the node package
themselves, so the code when loaded in the browser on request looks like
compiled version of @wordpress/blocks
Here are couple screenshots to better understand what I mean
[image: image]
<https://user-images.githubusercontent.com/6893216/189649358-3cdf2d29-2a80-4e07-8460-31a0fae09e90.png>
[image: image]
<https://user-images.githubusercontent.com/6893216/189649495-3979d3a5-3e47-444a-8453-163697b5ebbd.png>
[image: image]
<https://user-images.githubusercontent.com/6893216/189649617-486c7cb5-b0d5-418d-9cca-fa58678893e6.png>
—
Reply to this email directly, view it on GitHub
<#25077 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAT5N75VJMRB5KLFFP3EXLV54MSZANCNFSM4QYPREKA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
In dev mode this plugin does not do anything it only works in production. In dev model it takes the original node package and transpiles it, As I mentioned earlier this plugin was hack borrowed from someone's code to fix the production stage, I can't figure out the dev stage. If @wordpress/blocks is loaded and transpiled from original package, it should work the same as I was able to achieve it with laravel mix. |
Exactly thats the problem Andrius - in dev mode the plugin MUST ALSO
transpile ***@***.***/blocks' import to `window.wp.blocks` (and all other
imported wordpress packages too)
Am Mo., 12. Sept. 2022 um 20:54 Uhr schrieb Andrius Solopovas <
***@***.***>:
… In dev mode this plugin does not do anything it only works in production.
In dev model it takes the original node package and transpiles it
—
Reply to this email directly, view it on GitHub
<#25077 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAT5N6OESKLVKAGTMYQER3V5535BANCNFSM4QYPREKA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
It cannot do that, thats not what vite does... I was able to do globals replace for @wordpress/blocks in production because it builds assets with rollup |
I am pretty sure that you can do that using
https://vitejs.dev/config/shared-options.html#esbuild
since you can configure esbuild in vitejs to do anything you want.
and using esbuild you can for sure replace imports with globals (google for
it, multiple plugins available for this option)
Am Mo., 12. Sept. 2022 um 21:00 Uhr schrieb Andrius Solopovas <
***@***.***>:
… It cannot do that that not what vite does... I was able to do globals
replace for @wordpress/blocks in production because it builds assets with
rollup
—
Reply to this email directly, view it on GitHub
<#25077 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAT5N4FCP5NCVHXHWXTOPDV554VDANCNFSM4QYPREKA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
I understand what your saying, and it woiuld definitely solve the problem, same way as it did for production stage. Unfortunately there is not info on how to do that. |
I should be able to come out with something like this,
But that would mean that all of the blocks that I would use the would use wordpress core modules rather than latest ones available on npm. Basically my problem can get solved both ways, If I solve dev, then production will not need a hack and will basically do similar stuff that dev server does but compressed. If I do same global replace for dev server it will operate like my production stage. |
But that would mean that all of the blocks that I would use the would use
wordpress core modules rather than latest ones available on npm.
Exactly that is the truth. You got it.
And you cannot change that except you deliver your own bundled version of
Gutenberg with your blocks (which is not the case as I guess).
Remember : Almost every @wordpress/* module (except icons imported from
@wordpress/icons and similar things) are provided by the Gutenberg plugin
in WordPress, and not by our transpiled block.
In other words - your blocks will use the modules provided / loaded by the
Gutenberg plugin in production and never ever the @wordpress/* modules
installed by you in your block project.
Am Di., 13. Sept. 2022 um 17:25 Uhr schrieb Andrius Solopovas <
***@***.***>:
… I should be able to come out with something like this,
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/utils/*": ["componentpath/*"],
}
}
}
But that would mean that all of the blocks that I would use the would use
wordpress core modules rather than latest ones available on npm. Basically
my problem can get solved both ways, If I solve dev, then production will
not need a hack and will basically do similar stuff that dev server does
but compressed. If I do same global replace for dev server it will operate
like my production stage.
—
Reply to this email directly, view it on GitHub
<#25077 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAT5NZSDSY435JJMGJBF2LV6CMG7ANCNFSM4QYPREKA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Problem
In my experience, build tools often introduce a lot of delays and frustrations, which create a poor devex for contributors.
They're often slow, and break for a hundred different reasons, at random times. When they break, it can take a long time to figure out how to fix them.
Potential Solution
Can many of the tasks be removed from the
dev
scripts, and only used inbuild
?Modern browsers support
import
and many of the other features that these tools provide, and nearly all developers use modern browsers, so many tasks are really only needed for production builds. Removing them from the dev scripts would make contributing simpler and more enjoyable.The text was updated successfully, but these errors were encountered: