How To Write JS and CSS in WordPress with Industry Standard Tools

When you create a WordPress Theme or a Plugin, you can write plain Javascript and CSS the old way. But the industry standard today is to use a “build tool”, which creates a single JS (or CSS) file dynamically, which is the only one you have to “include” on every web page (single-page application (SPA)).

Fortunately, WordPress offers @wordpress/scripts, a great tool (based on Webpack) with all software you need for this purpose.

It is recommended to write Object Oriented Javascript using ES6 modules. Also use SCSS and modules in your CSS.

The following guide is about this fantastic tool.

Install node.js

If you haven’t already, install node.js in your development workstation.

Detailed instructions https://nodejs.org/en/

It is recommended to use the LTS version.Edit

Prepare package.json

Use npm init

Example with one of my projects:

pontikis@athena:/data/projects/wp/cliowp$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
 
See `npm help init` for definitive documentation on these fields
and exactly what they do.
 
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
 
Press ^C at any time to quit.
package name: (cliowp) 
version: (1.0.0) 
description: ClioWP is a WordPress Starter Theme for Developers.
entry point: (index.js) 
test command: 
git repository: https://github.com/pontikis/cliowp
keywords: WordPress, Theme
author: Christos Pontikis
license: (ISC) GPL-2.0-or-later
About to write to /data/projects/wp/cliowp/package.json:
 
{
  "name": "cliowp",
  "version": "1.0.0",
  "description": "ClioWP is a WordPress Starter Theme for Developers.",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/pontikis/cliowp.git"
  },
  "keywords": [
    "WordPress",
    "Theme"
  ],
  "author": "Christos Pontikis",
  "license": "GPL-2.0-or-later",
  "bugs": {
    "url": "https://github.com/pontikis/cliowp/issues"
  },
  "homepage": "https://github.com/pontikis/cliowp#readme"
}
 
 
Is this OK? (yes) yes

Add @wordpress/scripts

Read https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/

npm install @wordpress/scripts --save-dev

Add normalize.css

Optional, but recommended.

Read https://necolas.github.io/normalize.css/

npm install normalize.css

Add scripts to package.json

The most important are:

  "scripts": {
    "start": "wp-scripts start",
    "build": "wp-scripts build"
  }

Final package.json

So, the “final” package.json will look like

{
  "name": "cliowp",
  "version": "1.0.0",
  "description": "ClioWP is a WordPress Starter Theme for Developers.",
  "main": "index.js",
  "scripts": {
    "start": "wp-scripts start",
    "build": "wp-scripts build",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/pontikis/cliowp.git"
  },
  "keywords": [
    "WordPress",
    "Theme"
  ],
  "author": "Christos Pontikis",
  "license": "GPL-2.0-or-later",
  "bugs": {
    "url": "https://github.com/pontikis/cliowp/issues"
  },
  "homepage": "https://github.com/pontikis/cliowp#readme",
  "devDependencies": {
    "@wordpress/scripts": "^23.7.0"
  },
  "dependencies": {
    "normalize.css": "^8.0.1"
  }
}

Development environment

Create basic folders and files

mkdir css
mkdir css/modules
cd css
nano style.scss

Example code

/* 3rd party packages */
@import "../node_modules/normalize.css/normalize.css";
 
/* Modules */
@import "modules/typography.scss";
@import "modules/cliowp.scss";
@import "modules/wordpress.scss";
mkdir src
cd src
nano index.js

Example code

import "../css/style.scss"
 
// ES6 modules
import Search from "./modules/Search"
 
// Instantiate new objects
const search = new Search()

npm run start

Just run

npm run start

The first time, it will create the build folder. It will output the final scripts (CSS and JS) there.

This script will continuously run in the background listening for changes. In this case, it will automatically create the final scripts in the build folder.

To stop the “start script” (when you finish your work), use CTRL+C

Example output

pontikis@athena:/data/projects/wp/cliowp$ npm run start
 
> cliowp@1.0.0 start
> wp-scripts start
 
asset index.js 6.59 KiB [emitted] (name: index) 1 related asset
asset index.css 6.4 KiB [emitted] (name: index) 1 related asset
asset ./style-index.css 1.52 KiB [emitted] (name: ./style-index) (id hint: style) 1 related asset
asset index.asset.php 84 bytes [emitted] (name: index)
Entrypoint index 14.6 KiB (15.4 KiB) = ./style-index.css 1.52 KiB index.css 6.4 KiB index.js 6.59 KiB index.asset.php 84 bytes 3 auxiliary assets
orphan modules 21.2 KiB (javascript) 937 bytes (runtime) [orphan] 8 modules
runtime modules 2.83 KiB 4 modules
cacheable modules 77 bytes (javascript) 6.77 KiB (css/mini-extract)
  javascript modules 77 bytes
    ./src/index.js 27 bytes [built] [code generated]
    ./css/style.scss 50 bytes [built] [code generated]
  css modules 6.77 KiB
    css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[3].use[1]!./node_modules/normalize.css/normalize.css 5.99 KiB [built] [code generated]
    css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[3].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[3].use[2]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[3].use[3]!./css/style.scss 799 bytes [built] [code generated]
webpack 5.74.0 compiled successfully in 1086 ms

Enqueue scripts from the build folder

As an example use the following code in function.php

function load_front_end_assets()
{
    wp_enqueue_script('load_main_js', get_theme_file_uri('/build/index.js'), ['jquery'], '1.0', true);
    wp_enqueue_style('load_main_css', get_theme_file_uri('/build/style-index.css'));
    wp_enqueue_style('load_extra_css', get_theme_file_uri('/build/index.css'));
}
 
add_action('wp_enqueue_scripts', 'load_front_end_assets');

Summary

  • Before starting your development, run npm run start
  • Write CSS (modules) or use a third-party module and import them on css/style.scss
  • Write JS (modules) and import them on src/index.js
  • The final scripts are created at build folder

References