Migrando para o wp-scripts: análise de dois casos

O wp-scripts (@wordpress/scripts1) é um pacote com um conjunto de scripts para padronizar e simplificar o desenvolvimento de projetos WordPress que precisam transformar e otimizar o código JavaScript e outros assets (images, fontes, arquivos CSS, etc) para que seja compatível com a maioria dos navegadores.

Dessa forma, ao invés de configurar ferramentas como webpack2, Babel3 e ESLint4, você pode usar o wp-scripts para que essa única dependência seja responsável por isso e você possa se concentrar em outros aspectos do seu projeto WordPress.

Motivos para migrar

  • Você não precisa aprender e configurar várias ferramentas (webpack, Babel, ESLint, etc)
  • Reduz o número de depêndencias do projeto
  • Facilidade na manutenção e atualização em especial se você trabalha com vários projetos ao mesmo tempo
  • Ajuda manter a qualidade do código
  • Ajuda a seguir os padrões de formatação de código do WordPress

Motivos para não migrar

Dependendo da estrutura do seu projeto, você vai precisar customizar o wp-scripts. A customização pode ser passar um parâmetro adicional na hora de executar um script e/ou usar o seu próprio arquivo de configuração do webpack.

Preparando o ambiente

Será usado o node v20.11.0 e npm v10.2.4. Vamos iniciar um projeto npm e instalar o pacote wp-scripts como dependência do ambiente de desenvolvimento.

# Inicia um projeto com os valores padrão
npm init -y

# Instala o pacote wp-scripts 
npm install @wordpress/scripts --save-dev

No arquivo package.json, vamos adicionar alguns scripts básicos chamando o wp-scripts. Existem outros, mas vamos nos concentrar nesses que eu julgo serem os mais importantes se você quer migrar para o wp-scripts.

{
	[...]
	"scripts": {
		"build": "wp-scripts build",
		"format": "wp-scripts format",
		"lint:css": "wp-scripts lint-style",
		"lint:js": "wp-scripts lint-js"
	},
	[...]
}

Por fim, vamos adicionar três arquivos na pasta src: index.js, style.scss e image.png.

// index.js

console.log('Hello world!');
// style.scss

.my-class {
	background-color: #9ca3af;
}

A estrutura do projeto vai ficar dessa forma:

wp-scripts-post/
├── src/
│   ├── index.js
│   ├── style.scss
│   └── image.png
├── package.json
├── node_modules/ (gerado automaticamente)
└── package-lock.json (gerado automaticamente)

Casos

#1

O caso mais ideal é onde os arquivos JavaScript importam os demais assets via import. Nesse cenário, você basicamente precisa rodar o comando build e uma nova pasta será criada como resultado.

Para chegarmos nesse cenário usando os arquivos inicias do nosso projeto, precisamos atualizar o arquivo index.js para importar os arquivos style.scss e image.png.

// index.js

import './style.scss';
import 'image.png';


console.log('Hello world!');

Após executar o comando npm run build, teremos a seguinte estrutura:

wp-scripts-post/
├── build/
│   ├── index.asset.php
│   ├── index.js
│   ├── style.scss
│   └── image.png
├── src/
│   ├── index.js
│   ├── style.scss
│   └── image.png
├── package.json
├── node_modules/ (gerado automaticamente)
└── package-lock.json (gerado automaticamente)

Note que index.asset.php também é criado. Este arquivo é útil na hora de inserir o script em uma página por meio da função wp_enqueue_script5 pois nele temos as dependências do script e um número de versão.

Podemos ter uma varição desse cenário ideal que é quando seus arquivos fonte não estão na pasta src e/ou o resultado do script build não deve ficar na pasta build. Por exemplo, os arquivo estão na pasta source e o resultado deve ser colocado na pasta dist.

Nesse caso, podemos seguir dois caminhos. O primeiro é passar parâmetros adicionais ao comando build para especificar qual deve ser a pasta utilizada como entrada e qual pasta deve ser utilizada como saída. Os parâmetros nesse caso são --webpack-src-dir e --output-path.

{
	[...]
	"scripts": {
		"build": "wp-scripts build --webpack-src-dir=source --output-path=dist",
		[...]
	},
	[...]
}

Para os scripts format, lint-css e lint-js é preciso passar o caminho para o diretório na frente do comando.

{
	[...]
	"scripts": {
		[...]
		"format": "wp-scripts format ./source",
		"lint:css": "wp-scripts lint-style ./source",
		"lint:js": "wp-scripts lint-js ./source"
	},
	[...]
}

A segunda forma de especificar as pastas de entrada e saída é por meio de um arquivo de configuração do webpack. Para isso precisamos criar um arquivo webpack.config.js.

wp-scripts-post/
├── build/
│   ├── index.asset.php
│   ├── index.js
│   ├── style.scss
│   └── image.png
├── src/
│   ├── index.js
│   ├── style.scss
│   └── image.png
├── webpack.config.js <-- <-- <--
├── package.json
├── node_modules/ (gerado automaticamente)
└── package-lock.json (gerado automaticamente)

No webpack.config.js vamos modificar duas configurações: entry6 e output.path7. Note que no arquivo abaixo nós modificamos apenas essas duas configurações e continuamos usando as configurações padrão do wp-scripts. O que facilita o uso das configurações padrão é o spread operator8 (…)

const path = require('path');
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );

module.exports = {
    ...defaultConfig,
	entry: './source',
	output: {
		...defaultConfig.output,
		/**
		 * A configuração `output.path` espera um caminho
		 * absoluto e por isso usamos a função `path.resolve`.
		 */
		path: path.resolve(__dirname, 'dist')
	},
}

Ao executar o comando npm run build o arquivo webpack.config.js será utilizado automaticamente pois ele está no mesmo diretório que o arquivo package.json. Também é possível especificar um caminho para o arquivo webpack.config.js por meio da opção --config.

#2

Nesse segundo caso, suponha que você tenha mais de um arquivo JavaScript, CSS e imagem. Além disso, você não importa os arquivos de CSS e imagem nos arquivos JavaScript. Apesar de ser possível atualizar os arquivos JavaScript para importar os assets, nesse primeiro momento você quer apenas incorporar o wp-scripts ao seu projeto sem alterar os seus arquivos fontes.

Apenas para recapitular, temos essa estrutura de pastas e arquivos:

wp-scripts-post/
├── src/
│   ├── index.js
│   ├── style.scss
│   └── image.png
├── package.json
├── node_modules/ (gerado automaticamente)
└── package-lock.json (gerado automaticamente)
// index.js

console.log('Hello world!');
// style.scss

.my-class {
	background-color: #9ca3af;
}

Sem fazer nenhuma alteração e executando o wp-scripts build (npm run build), teremos como resultado na pasta build apenas os arquivos index.js e index.asset.php:

wp-scripts-post/
├── build/
│   ├── index.js
│   └── index.asset.php
├── src/
│   ├── index.js
│   ├── style.scss
│   └── image.png
├── package.json
├── node_modules/ (gerado automaticamente)
└── package-lock.json (gerado automaticamente)

Isso ocorre pois o arquivo style.scss e image.png não foram importados no arquivo index.js. Dessa forma, não é possível que o script de build saiba da existência desses arquivos.

Nesse cenário, vamos utilizar o arquivo webpack.config.js para informar os arquivos que queremos utilizar como entrada na configuração entry. Ao invés de passarmos uma string, vamos passar um objeto onde a chave será o nome da nossa entrada e o valor um array de strings com o caminho dos arquivos de JavaScript e SCSS:

const path = require('path');
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );

module.exports = {
    ...defaultConfig,
	entry: {
		index: ['./src/index.js', './src/style.scss']
	},
}

Ao executar o comando npm run build, teremos o seguinte resultado na pasta build:

wp-scripts-post/
├── build/
│   ├── index.js
│   ├── style-index.css
│   └── index.asset.php

[...]

Apesar dos dois arquivos terem sido gerados, o nome do arquivo CSS teve uma mudança de style.scss para style-index.css. Como isso pode ser um problema pois teríamos que alterar o nome desse arquivo onde ele é usado, vamos ajustar nossa configuração para gerar o arquivo CSS com o nome style.css.

O webpack é uma ferramenta que possui muitas configurações e que consegue lidar com diversos cenários. Além disso, permite que suas funcionalidades sejam extendidas por meio de uma interface para plugins9.

Se você analisar o webpack.config.js do wp-scripts10, notará que o wp-scripts utiliza alguns plugins. Um deles é o MiniCssExtractPlugin11. Este plugin extrai o CSS para um arquivo separado. Se esse plugin não fosse utilizado e executassemos npm run build, o CSS importado em um arquivo JavaScript seria inserido no arquivo JavaScript compilado.

Assim, para alterar o nome do arquivo CSS precisamos alterar a configuração filename12 do plugin MiniCssExtractPlugin. Como esse plugin é inserido pelo wp-scripts, primeiro vamos removê-lo e depois inserir novamente com a nossa configuração. A nossa configuração consiste em remover tudo depois do traço do nome do arquivo. Dessa forma, ao invés do nome do arquivo ser style-index, será apenas style.

// webpack.config.js

const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
const MiniCSSExtractPlugin = require( 'mini-css-extract-plugin' );

// Remove o plugin MiniCSSExtractPlugin da lista de plugins do wp-script.
const plugins = defaultConfig.plugins.filter(
	plugin => ! (plugin instanceof MiniCSSExtractPlugin)
);

module.exports = {
    ...defaultConfig,
	entry: {
		index: ['./src/index.js', './src/style.scss'],
	},
	plugins: [
		...plugins,
		// Adiciona o plugin MiniCSSExtractPlugin
		new MiniCSSExtractPlugin( {
			filename: ({chunk}) => {
				// Regex para remover tudo depois do `-`.
				return `${chunk.name.replace(/-.*/, '')}.css`
			},
		} ),
	]
}

Ao executar npm run build, teremos o resultado esperado:

wp-scripts-post/
├── build/
│   ├── index.js
│   ├── style.css
│   └── index.asset.php

[...]

Um detalhe interessante é que se utilizarmos uma imagem no arquivo style.scss, o wp-scripts irá copiar essa imagem para dentro da pasta build e ajustar o arquivo style.css para referenciar o nome correto da imagem na pasta build.

// style.scss

.my-class {
	background-color: #9ca3af;
	background-image: url('./image.png');
}
wp-scripts-post/
├── build/
│   ├── images/
│   │   └── image.438eef35.png
│   ├── index.js
│   ├── style.css
│   └── index.asset.php

[...]

Se você tem outros arquivos .js e .scss, basta adicioná-los na chave entry do webpack.config.js que executar o comando de build, esses arquivo também serão processados pelo wp-scripts.

Conclusão

O wp-scripts é uma boa ferramenta e pode acelerar o desenvolvimento de projetos WordPress onde o código se apoia fortemente no JavaScript. Entretanto, se o seu projeto foge um pouco do básico, configurar o wp-scripts para que se adapte a suas necessidades pode ser desafiador pois você precisará entender e ir um pouco afundo em como o webpack funciona. Somado ao fato de que é difícil encontrar tutoriais e/ou exemplos de casos não triviais.

No universo WordPress existe outra alternativa que é o 10up-toolkit. Mas se você gostaria de usar uma ferramenta que não fica no seu caminho, possui uma interface mais compreensível e uma curva de aprendizagem pequena, então Laravel Mix pode ser a ferramenta mais adequada.

Para conhecer mais opções e configurações do wp-scripts:

Notas de rodapé

  1. https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/ ↩︎
  2. https://webpack.js.org/ ↩︎
  3. https://babeljs.io/ ↩︎
  4. https://eslint.org/ ↩︎
  5. https://developer.wordpress.org/reference/functions/wp_enqueue_script/ ↩︎
  6. https://webpack.js.org/configuration/entry-context/#entry ↩︎
  7. https://webpack.js.org/configuration/output/#outputpath ↩︎
  8. https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Operators/Spread_syntax ↩︎
  9. https://webpack.js.org/plugins/ ↩︎
  10. https://github.com/WordPress/gutenberg/blob/trunk/packages/scripts/config/webpack.config.js#L306 ↩︎
  11. https://webpack.js.org/plugins/mini-css-extract-plugin ↩︎
  12. https://webpack.js.org/plugins/mini-css-extract-plugin#filename ↩︎