JavaScript chat summary, October 29nd, 2019

Below is a summary of the discussion from last week’s JavaScript chat (agendaSlack Transcript)

Have a topic for discussion for the next meeting? Leave a suggested edit on this week’s agenda.

React prerelease channels

Slack Conversation

There was an announcement from the React team about official prerelease channels:

The long story short is they are promoting react@next prereleases and share some guidelines on how to test projects with the upcoming changes to their libraries. If you want to get involved and explore how the Gutenberg project could participate please comment on the corresponding issue.

Time of the meeting

Slack Conversation

Weekly meetings discuss JavaScript in the context of the WordPress ecosystem and we value the input from people working with JavaScript in WordPress. We wanted to survey people whether they would like to participate in the weekly chat if there was a different time?

As of today, we expect you’ll come to the meeting prepared to contribute your perspectives and help influence direction. You can also share in comments what would you expect from such meetings.

Testing components

Slack Conversation

There is an ongoing discussion about different approaches to testing UI components on GitHub. It isn’t a new topic. We have already considered removing enzyme in the past when some React APIs weren’t covered, but we gave up because of its wide usage.

We agreed that we can live with enzyme in old files following Code Refactoring guidelines, but we should plan to make it easier to contribute with tests when working on new features. @nerrad emphasized that it would be good to iron out what testing approach we want to recommend going forward. If anything the discussion in that issue highlights, we should include it in the Testing Overview documentation as the very first step.

@gziolo proposed we consider the E2E testing approach with the instance of Storybook as the testing environment given that it is a static site working like a single page application. @itsjonq shared that he’s done storybook E2E testing using Cypress in the past. It was something that could be automated by CI (Travis) and it worked great.

#core-js, #corejs, #javascript, #js, #meeting-notes

JavaScript chat summary, October 22nd, 2019

Below is a summary of the discussion from last week’s JavaScript chat (agendaSlack Transcript)

Have a topic for discussion for the next meeting? Leave a suggested edit on this week’s agenda.

Agenda: Node LTS

Slack Conversation

Recently, Node 12 became the new LTS version for Node. A pull request to make WordPress scripts compatible with Node 12 was merged.

Agenda: Code style

Slack Conversation

A change to the JSDoc plugin triggered new ESLint warnings. These were fixed in a pull request: https://github.com/WordPress/gutenberg/pull/18025.

Another PR tries to bring WP Prettier into WP Scripts. WP Prettier is a Prettier fork that follows the WordPress code conventions that allows to easily reformat all of WordPress JavaScript but also enable other developers in the community who leverage WP scripts to do the same.

Agenda: Storybook

Slack Conversation

In September, Storybook was added to Gutenberg. There’s an issue open discussing next steps, which includes adding stories for all @wordpress/components and adding support for React Native components. @mkaz published a tutorial video on his blog on how to code a storybook story.

The following questions could be explored:

  • How can we enable plugin and theme developers to leverage storybook in their own workflows? It was suggested storybook could be added to WP scripts.
  • How can we integrate storybook into https://developer.wordpress.org/block-editor/? Storybook could be a replacement for the components reference.

A few concerns were raised with regard to using storybook on wordpress.org:

– How do we keep the WP dev site header?
– How do we avoid iframes (and include the header) to keep routing?
– How do we keep the READMEs (or some aspects of them) as there’s a lot of good info there?

It seems storybook allows for enough customization to be able to address these concerns. Some help from the meta team would be required.

Open floor: Card component

Slack Conversation

@itsjonq worked on a PR for a new Card component. There’s still some ongoing discussion about the introduction of css-in-js and Enzyme in that PR. Feedback appreciated!

#core-js, #corejs, #javascript, #js, #meeting-notes

JavaScript chat summary, May 14th, 2019

Below is a summary of the discussion from last week’s JavaScript chat (agendaSlack Transcript)

Have a topic for discussion for the next meeting? Leave a suggested edit on this week’s agenda.

Agenda: React Hooks for Data

Slack Conversation

We discussed an issue to introduce a useSelect React hook to the @wordpress/data package. The discussion focused on determining what the best API would be and a concern was raised to investigate the potential performance impact. We agreed it would be best to have a single useSelect function which allows to pass in a mapping callback for more complex conditional type use-cases involving multiple selectors/stores. We could create utility functions for simple cases.

Open floor: Node compatibility

The version of node-sass we use isn’t compatible with Node 12.x. A PR to update node-sass to a compatible version is now merged.

#core-js, #corejs, #javascript, #js

The Case for JS Modules

I originally posted some of this content here: Split javascript files in media into modules

The patch on that ticket breaks up the Backbone classes in media-models.js, media-views.js, media-audiovideo.js, and media-grid.js into modules and injects them via Browserify on build/watch into a built file. Let’s start at the beginning.

Brain overload

Files that are 1000s of lines long are hard to consume. We try to alleviate this by adding copious amounts of docs. Still, it’s a lot to look at. Ideally, we would break our files into smaller modules and then somehow join them together in a build process.

It is common practice to serve (sometimes very large) minified files for JS and CSS that have concatenated many smaller files together and uglify’d (minified/obfuscated) them. It is no longer common or best practice to develop with huge files. We can learn a lot from emerging front end development trends, especially those from the Node/NPM community. In some cases, we can even share code.

We’ll use Media as the main culprit, but this could apply to any “manifest” – a term I use to describe files that contain the entire public API for a feature. Something like media-views.js, it might be nice to bounce from view to view in the same file, provided you know exactly what you are looking at, what depends on what, etc.

I have found, it is completely overwhelming for almost everyone. It would be great if each discreet piece could be viewed in isolation with its dependencies clearly stated.

There are many ways to accomplish the splitting of large files. I want to focus on 2 of the most common.

Vocabulary

Backbone is one of a growing number of MV* frameworks for JavaScript. A large majority of the code related to media either belongs to a handful of Models or to the increasingly large library of Views and View Templates.

Views are the building blocks for the presentation of Media (you know, “the Media Modal” or 4.0’s “Media Grid”).

The main canvas on which these Views are stitched together are called Frames, which are themselves Views – tilting our use of Backbone more towards MVP, P standing for Presenter.

We have Controllers, which are called States, but they belong to a Frame (Presenter! also a View!), so anyways…. for now….

When we create new UIs, we are more than likely adding new Views/Templates, or updating existing Views.

If we wanted to move from one large file to many files that each contain a class, we would create Modules.

Grunt is a task runner. We use Grunt to build our src directory into our build directory.

Require

Require is a great tool for converting AMD modules into built files. Require leans on Dependency Injection in its syntax:

define([
    'models/taco',
    'models/burrito',
    'controllers/meal'
], function (Taco, Burrito, Meal) {
    var Dinner = Meal.extend({
        // taco-related code
    });
    return Dinner;
});

This syntax works great, unless you have way more dependencies. Refactoring code could unwind a module that has a lot of dependencies, but if you are just trying to convert legacy classes into a module, Require starts to get a little weird. Concrete example: Frames have a TON of dependencies.

Require becomes a Grunt task to make one big file by recursing the dependency tree in an initial manifest. Require, by default, loads JS asynchronously, which can cause race conditions with plugins or themes that expect code to be registered on $(document).ready() or window.onload.

Require works even if you don’t build via Grunt.

Browserify

Browserify is a tool that allows you to use Node-style modules and run them in a browser without changing from the Node syntax. Browserify requires a build for this to work.

Using our example from above, this is the syntax for Browserify:

var Taco = require( './models/taco.js' ),
    Burrito = require( './models/burrito.js' ),
    Meal = require( './controllers/meal.js' ),
    Dinner;

Dinner = Meal.extend({
    // taco-related code
});

module.exports = Dinner;

Browserify leans more towards the Service Locator pattern.

Browserify scans the abstract syntax tree (AST) of your JS code to compile dependencies. Your modules themselves get wrapped in their own scope like so:

(function (require, module, exports) { 
    .....YOUR_MODULE..... 
})

After spending a lot of time messing around with both: I think we should use Browserify.

Converting “Legacy” Code

The media JS code is some of the most “modern” code in WordPress, but it still clunkily lives in huge files. To convert the code into modules, we need to make a lot of individual files (one for each Backbone class).

We also need to make sure we maintain the existing wp.media namespaces for backwards compatibility. We don’t want any existing functionality to change, we just want to build the files differently.

Even though the code is defined differently, wrapped in a new scope, and looks different when “built”, we can still maintain our current API design: what is publicly accessible now will remain publicly accessible.

In the patch

Disclaimer: this patch is for experimentation only. It will go stale probably before this post is published. It works, but it is only a playground for now. If this moves forward, it will be a laborious Subversion process to create a bunch of new files.

I have added a folder to wp-includes/js, media, that contains the modules and the built manifests. My patch adjusts script-loader.php to use these new paths.

media contains the following files/folders:

controllers/
models/
routers/
utils/
views/ (with another round of subfolders)
audio-video.manifest.js
grid.manifest.js
models.manifest.js
views.manifest.js

The build pipeline

If you are following along with that patch and want to see this in action, run in the project root:

npm install

Afterwards, run:

grunt watch

*.manifest.js files get built into *.js files when you change a file in media/*, provided you are running the grunt watch task. The watcher will automatically call browserify:media and uglify:media when those files change. This allows you to run your site from src or build, and you will still get Browserify’d files. SCRIPT_DEBUG will either run *.js or *.min.js, just like any other minified JS in core.

This is a proposal

I would like to hear feedback from the overall community and certainly from our fair share of JS-trained ninjas. A common reason to *not* do something like this is the barrier to entry for new developers. I would argue in this case that the code becomes MORE readable and understandable. I was shocked myself to see how much simpler it was to absorb one piece at a time once the code was laid out in modules.

#backbone, #js, #media

Working on wp-lists, colors, fades

Working on wp-lists, colors, fades

#js