Is your feature request related to a problem? Please describe.
One of the challenges for projects that want to use various WordPress packages on the frontend is keeping js bundles small. While lodash itself is small in size, the fact that wp.element
depends on it means that any code wanting to enqueue wp.element on the frontend is also going to load lodash.
Since there are many native implementations for lodash features that can be used reliably (and in some cases are faster than lodash), I think it'd be good to remove this package's dependency on lodash and replace with native implementation.
Describe the solution you'd like
Replace lodash dependency in @wordpress/element
by reimplementing any lodash features as native js.
So, the following lodash functions are relatively trivial to re-implement using native js (for the use-case in wp.element
):
However, there are a couple that are a bit more involved:
Since the last two would involve essentially copying in the same thing that lodash did I'm wondering if the effort here is still worth it.
One alternative I've been pondering when it comes to how WordPress exposes libraries now that javascript is more "first-class" is why we don't take advantage of cdn distributed scripts which to some degree can eliminate the concerns of _common_ dependencies such as lodash
, react
etc. I'm going to bring this up in the next #core-js meeting.
Since the last two would involve essentially copying in the same thing that lodash did I'm wondering if the effort here is still worth it.
One other advantage would be avoiding conflicts with other code on the page using lodash or underscore.
However, there are a couple that are a bit more involved:
kebabCase
isPlainObject
These are pretty tiny, can we just import and bundle them (or copy the code directly)?
https://github.com/lodash/lodash/blob/master/kebabCase.js
https://github.com/lodash/lodash/blob/master/isPlainObject.js
These are pretty tiny, can we just import and bundle them (or copy the code directly)?
They are tiny, but they have dependencies (follow the internal dependency chain for kebabCase for instance). I'm wondering though, if there are only a _few_ lodash helpers like these two, if we should just use the custom builds feature of lodash and create a special WP package (@wordpress/utils
?) for lodash helpers such as kebabCase
etc that have a bit more involved code than what can simply be implemented using native js?
worth a try, removing the lodash dependency feels pretty valuable, especially in the WordPress admin context.
Is @wordpress/element
the only package depending on lodash
or are there other places where we might be able to remove the dependency?
Is @wordpress/element the only package depending on lodash or are there other places where we might be able to remove the dependency?
It's extensively used in multiple packages in this repository. Ideally it'd be nice to remove it as a dependency everywhere and instead just expose a subset of lodash utils for use (via another package). I'll create another issue for discussing this.
One small concern is that as a third party developer, I've used lodash extensively within my own blocks, using the build provided in core. I can understand the appeal of removing a dependency but it feels like a small price to pay for all of the DevEx improvements it brings. Of course I can provide my own bundle if Gutenberg stops using it (or builds a custom build) but then we've just introduced a bunch of duplication as any plugin using lodash may decide to provide its own bundle.
(In other words, this feels a bit like seeing the forest for the trees. It's a nice optimization, but what challenges/duplication would it lead to for third-parties?)
I think for back compat we'd need to keep lodash available as an externally provided script in WP core. So your concern here Chris can be mitigated.
As a flipside to your argument, there is also the challenge of current WordPress packages that have a dependency on lodash unnecessarily which adds additional weight everywhere they are enqueued. This specific pull is an example of that. If someone wants to use wp.element
on the frontend (and is not needing any of the lodash functions), lodash is loaded regardless. This is something currently experienced by the WooCommerce blocks team where we don't _need_ lodash functionality in the frontend. This in turn means that for now, we're not using wp.element
and just use react
and react-dom
directly (via what's provided by WP).
Not only that, but I have also experienced issues with third party compatibility on some sites where a plugin or theme a site owner has installed is using lodash on the frontend in one of their bundled scripts directly (not enqueuing what WP provides) which leads to conflicts. It'd be nice to avoid that problem if possible.
Noting that @ZebulanStanphill has been doing some work lately to convert some usages of Lodash to native equivalents:
And a relevant comment of mine at https://github.com/WordPress/gutenberg/pull/21054#issuecomment-601875359, notably this point:
In WordPress, all of Lodash will always be loaded anyways (and it's referenced as an external), so there will be no immediate network bundle size benefit for WordPress as long as Lodash is used anywhere. Therefore, it would mostly be for the benefit of third-party package consumers.
We won't see any immediate benefit in the editor/admin of removing Lodash in individual packages, since the full module is referenced as an external to each package. It would only be at the point if and when the usage of Lodash is so little that inlining Lodash usage to respective packages would be of greater overall benefit. I'm not sure we'd ever get to that point, to be honest. It's true there's plenty of low-hanging fruit with the filter
, includes
, isFunction
, etc. functions, but there's plenty other utilities which provide benefit that aren't easily recreated in native JavaScript. And as noted in earlier comments, the implementation of Lodash is such that it reuses many base implementations. This can be beneficial in some cases, but not in the scenario where we're trying to use only a few methods per each of our packages.
That said, I am sympathetic to a few specific reasons for reducing overall usage:
Object.assign
in native browserland code moreso than any JavaScript could hope to achieve.isNull
does not bring much value to use when weighing the overhead in considering (a) what it is and (b) how it potentially differs from === null
.
Most helpful comment
I think for back compat we'd need to keep lodash available as an externally provided script in WP core. So your concern here Chris can be mitigated.
As a flipside to your argument, there is also the challenge of current WordPress packages that have a dependency on lodash unnecessarily which adds additional weight everywhere they are enqueued. This specific pull is an example of that. If someone wants to use
wp.element
on the frontend (and is not needing any of the lodash functions), lodash is loaded regardless. This is something currently experienced by the WooCommerce blocks team where we don't _need_ lodash functionality in the frontend. This in turn means that for now, we're not usingwp.element
and just usereact
andreact-dom
directly (via what's provided by WP).Not only that, but I have also experienced issues with third party compatibility on some sites where a plugin or theme a site owner has installed is using lodash on the frontend in one of their bundled scripts directly (not enqueuing what WP provides) which leads to conflicts. It'd be nice to avoid that problem if possible.