Create a gist now

Instantly share code, notes, and snippets.

@omarreiss /wpjs.md
Last active Feb 20, 2018

Embed
What would you like to do?

Setting up your development environment

[better title needed]

[insert table of contents]

System requirements

Node.js and npm

WordPress uses a JavaScript task runner called Grunt to build its files. It requires the most recent LTS version of the Node.js runtime. It also requires dependencies fetched via npm. npm is packaged with Node.js, so if your computer has Node.js installed you are ready to go.

If you're not sure whether you have Node.js or the right version, run this on your command line:

node --version
npm --version

If you get a "command not found" error or an outdated version for Node:

  • Windows or Mac users can download and run this Node.js installer.
  • Mac users often prefer to install Node using Homebrew. After installing Homebrew, run brew install node to install Node.js. Alternatively, installer packages are available directly from Node.js.
  • Linux users can use this guide for Node.js installation on Linux. If you get an outdated version of npm, run npm install -g npm.

Managing dependencies

WordPress ships with a list of dependencies, some of those are managed and updated with npm, some are managed manually.

npm packages

All npm dependencies are listed in the package.json file in the root of the project. Some dependencies are only used for development (like Grunt and code linters). Those are listed under devDependencies. Packages that are used in the WordPress code itself are listed under dependencies.

Installing npm packages

You can install npm dependencies by running:

npm install

Updating npm packages & version locking

The versions of the packages are locked in a package-lock.json to guarantee the same packages are installed every time you run npm install. To update a dependency, simply run:

npm update <package_name> --save

This will update also update the package-lock.json so that others will also have the new version when they now run npm install.

Adding new npm packages

You can add a package by running:

npm install <package_name> --save

If you want to add a development package, run:

npm install <package_name> --save-dev

Both commands will also update the package-lock.json to include the new package at a specific version.

Building npm packages

npm installs all packages to the node_modules directory. Sometimes we copy a dependency to WordPress and include it directly. This is configured in Gruntfile.js under copy.npm-packages. If you want to add a new package and include it in WordPress directly, you need to add it here.

Another way code from npm is included into WordPress is by importing distinct modules directly into our own code and have Webpack bundle it. In that case you don't need to worry about updating the build config.

Manual dependencies

Some dependencies in WordPress aren't available on npm. They are managed and updated manually. Some of them aren't updated at all anymore and / or might only still be present for backwards compatibility reasons. They are located in the src/js/_enqueues/vendor directory, which also includes a README.md listing the sources for those dependencies.

Building manual dependencies

The manual dependencies are built just like the rest of the source. This is configured in Gruntfile.js under copy.vendor-js.

Getting started

VVV

[insert a section about developing with VVV (VVV should automatically watch changes, take away the burden entirely)]

Building WordPress yourself

WordPress uses grunt to build its source. In order to start developing, you'll need to run an initial build. To do that, run the following command:

npm install && grunt build

When developing, you don't want to run grunt build every time you change something. Instead you can run a file watcher which will automatically rebuild when a file is changed. This can be done by running the following command:

grunt watch

Code organization and development practices

Important to note is that the structure of the JavaScript source is different from the structure of the JavaScript build. Historically, all JavaScript in WordPress has been scattered over two directories; wp-admin/js and wp-includes/js. This made it complicated to facilitate current day and modular JavaScript development practices in WordPress. That's why we've decided to introduce a unified structure for the sourcecode in src/js. In order to maintain backwards compatibility, the structure of the build remained unchanged.

Directory structure

Here's an overview of how the JavaScript source code is organized:

src/js				| All the JavaScript source.
├── _enqueues			| Any script that ends up being enqueued.
│   ├── admin 			| Procedural scripts ran in the admin.
│   ├── deprecated		| All deprecated scripts.
│   ├── lib			| All standalone lib scripts.
│   ├── vendor			| All 3rd party deps that can't be managed with NPM.
│   └── wp			| All scripts that assign something to the wp namespace.
│       ├── customize	        | Anything under wp.customize.
│       ├── editor		| Anything under wp.editor.
│       ├── media		| Anything under wp.media.
│       ├── utils		| Anything under wp.utils.
│       └── widgets		| jQuery widgets on the wp namespace.
└── media			| The media library.

As you might have noticed, most of the JavaScript is currently located in the _enqueues directory. That's where all the scripts are that eventually get copied or built to /build. Any independent JavaScript modules that we'll create in the future will be in src/js in a logical structure. An early example of this is the media folder, which contains all the separate modules for the media library. This allows us to flexibly and safely change and move around code while maintaining backwards compatibility.

JavaScript modules and Webpack

WordPress core's JavaScript aims to be modular, composable and reusable. We try to stay as close as possible to ECMAScript standards, especially since transpilers like Babel and different available polyfills have already solved all major browser compatibility problems. While many modern JavaScript features might not currently be in use in WordPress, feel free to open the discussion about adding support for one in the #core-js channel on chat.wordpress.org.

What is modular JavaScript?

In most programming languages, you can separate your code into separate modules and import those modules into your application to use the functionality contained in them. This enables developers to make code reusable and keep large projects organized. Support for modules in JavaScript wasn’t originally built into browsers, so module bundlers were created which combine all of the necessary modules into a single JavaScript file that would be loaded via a <script> tag in the HTML. WordPress uses Webpack for this.

There are multiple ways to make JavaScript modular. WordPress uses ES6 module pattern, a standard that is gaining support in all modern browsers. There is still some code left in WordPres that uses Common JS modules. This is not a big problem because Webpack can handle those too. This will probably be refactored to ES modules in the future.

For anyone wanting to learn about JS modules, Preethi Kasireddy wrote an excellent two part introduction. You can find it here:

A few guidelines with regard to modular programming

Here are a few useful and easy to understand guidelines to write modular code:

Single responsibility principle

[Explain in layman's terms + link]

Don't repeat yourself (DRY)

[Explain in layman's terms + link]

Loose coupling, high cohesion

[Might be too complex, but if we could make this easy to grasp, we're good.]

Sharing WordPress JavaScript modules on NPM

WordPress is an open source project. If we can organize our code in a way that makes it more reusable for the greater community of developers, we should try to do so.

[Documentation on WordPress packages]

Introducing new scripts

Once a script is registered in core, it cannot be removed without breaking backwards compatibility. This is because plugin and theme authors unregister / replace scripts or enqueue scripts that aren't enqueued by core on certain screens. Because of modules, anything that is in a registered script can of course be extracted away into a separate module. Anything that needs to be on the global wp object can still be assigned to it. However, using modules should eventually lead to better composition. Modules that don't need to know about global API's shouldn't depend on them or assign themselves to global objects.

Transitioning from a PHP rendered admin to a JS rendered admin

WordPress is moving towards a future where JavaScript becomes more and more responsible for rendering the admin interface through a collection of single page applications. That's a different paradigm from the one which we've had for many years, where PHP was responsible for rendering the interface and JavaScript (mostly jQuery) was used to model some basic DOM interactions on top of that. These two paradigms don't fit seamlessly on top of each other. Much of the existing JavaScript will lose relevance once interfaces start getting rendered with JavaScript entirely.

Handling legacy / old code

A lot of functionality in the legacy JavaScript code will still be useful, but might need some refactoring to fit into the new paradigm. Think of utility functions and more self-contained libraries. It might be useful to split those up into modules to enable broader reuse. WordPress historically has always been quite critical towards code refactoring. When refactoring, always make sure to have a good usecase for a proposed change. Making something available for broader reuse could be such a usecase. To learn more about refactoring guidelines for WordPress, make sure to take a look at the handbook page about refactoring.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment