Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# dependencies
/node_modules
node_modules

# misc
.DS_Store
Expand Down
76 changes: 43 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,53 @@
# react-wp-scripts

A wrapper for create-react-app's [`react-scripts`](https://github.com/facebookincubator/create-react-app/tree/master/packages/react-scripts) to allow seamless usage of scripts and styles served from `webpack-dev-server` while developing a theme or plugin.
Create React-based WordPress plugins and themes with no build configuration, just like [Create React App](https://github.com/facebook/create-react-app).

**Important Note**: This project is brand new, and largely untested. We recommend using it as a learning tool rather than depending on it for critical development work.
* [Creating a Plugin or Theme](#easy-setup) - How to create a React-based plugin or theme.
* [Adding to an Existing Project](#adding-to-an-existing-project) - How to add `react-wp-scripts` to your existing React project.
* [User Guide](packages/react-wp-scripts/README.md) - How to develop plugins and themes bootstrapped with `react-wp-scripts`

## Installation & Usage
## Easy Setup

Run `create-react-app --scripts-version react-wp-scripts --php-namespace="Your_Namespace" /path/to/your/project/folder` to generate a new create-react-app project configured to use these custom scripts.
The easiest way to get started with `react-wp-scripts` for new projects is to use the setup command to create a new project:

The file `react-wp-scripts.php` will be created within your generated project folder. Replace `Your_Namespace` with the PHP namespace you would like to use for this file; it will default to `ReactWPScripts`.
```sh
# For plugins:
npx create-react-wp-plugin my-app

# For themes:
npx create-react-wp-theme my-app
```

You'll get a plugin or theme ready to activate in WordPress. You'll also want to start the JS development server:

```sh
cd my-app
npm start
```

You can use any of the normal `react-scripts` [commands](https://github.com/facebookincubator/create-react-app/blob/master/README.md#npm-start-or-yarn-start) as normal while you develop.

### Adding to an Existing Project

If you already have a project created with `create-react-app`, you can easily switch it to `react-wp-scripts`:

```sh
npm install --save react-wp-scripts
```

You'll need to edit the `scripts` in your `package.json`. Replace `react-scripts` with `react-wp-scripts`:

```json
"scripts": {
"start": "react-wp-scripts start",
"build": "react-wp-scripts build",
"test": "react-wp-scripts test --env=jsdom",
"eject": "react-wp-scripts eject"
}
```

Finally, you'll need to load your assets into WordPress. Copy [the loader file](packages/react-wp-scripts/template/common/loader.php) into your project, and replace `%%NAMESPACE%%` with your desired namespace. Then, hook it in to WordPress:

Once installed, you can require this file from your theme or plugin code:
```php
require __DIR__ . '/react-wp-scripts.php';

Expand All @@ -26,19 +63,6 @@ add_action( 'wp_enqueue_scripts', 'myproject_enqueue_assets' );

This will load all generated JS and CSS into your theme or plugin.

You may now use the `react-scripts` [commands](https://github.com/facebookincubator/create-react-app/blob/master/README.md#npm-start-or-yarn-start) as normal while you develop.

## PHP Interface

### `enqueue_assets`

The `enqueue_assets` function takes two arguments: the filesystem path to the project directory containing the `src` and `build` folders, and an optional array argument which may be used to customize script handles and dependencies. Available options:

- `base_url`: The URL of the project base that contains the `src` and `build` directories. If not specified, this URL will be inferred from the provided directory path string.
- `handle`: The handle to use when registering the app's script and stylesheet. This will default to the last part of the directory passed to enqueue_assets.
- `scripts`: An array of script dependencies to load before your bundle.
- `styles`: An array of stylesheet dependencies to load before your bundle.

## How It Works

This project solves two issues that prevent seamless usage of Webpack projects in WordPress themes and plugins:
Expand All @@ -53,17 +77,3 @@ Running `npm start`, on the other hand, doesn't output a thing: this is because
`react-wp-scripts` wraps the default `react-scripts` "start" command with code that tweaks the development Webpack and `webpack-dev-server` configuration objects, injecting cross-origin headers, a `webpack-manifest-plugin` plugin configured to output from within `webpack-dev-server`, and other optimizations to allow WordPress and the Webpack build to properly communicate. All successful builds will now create an `assets-manifest.json` file, either at the project root (when the development server is running) or in the `build/` directory (as part of a static build).

Finally, the PHP in `loader.php` uses the location of the generated `assets-manifest.json` file to enqueue scripts either from the development server or from the static `build/` directory.

## Troubleshooting

### Server will not start

If the development server will not start or WordPress is showing script errors, try deleting the `assets-manifest.json` in the project root then re-start the development server.

### Scripts do not load

If the development server is not running, the root `assets-manifest.json` is not present, and scripts still will not load, re-run `npm run build` to re-generate any build assets that may be missing.

### Fatal Error: Cannot redeclare ReactWPScripts...

If you get an error that you cannot reduplicate a method in the `ReactWPScripts` namespace, the cause is likely that two copies of `loader.php` are present in separate plugins or themes. Switch the copy in the plugin or theme under development to use a different namespace to avoid collision.
9 changes: 9 additions & 0 deletions lerna.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"lerna": "2.9.0",
"npmClient": "yarn",
"useWorkspaces": true,
"packages": [
"packages/*"
],
"version": "independent"
}
33 changes: 7 additions & 26 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,28 +1,9 @@
{
"name": "react-wp-scripts",
"description": "A wrapper for react-scripts to allow seamless usage of webpack-dev-server while developing a WordPress theme or plugin.",
"version": "0.1.1",
"contributors": [
"Ryan McCue",
"K. Adam White",
"Human Made"
],
"license": "GPL-2.0+",
"repository": {
"type": "git",
"url": "git+https://github.com/humanmade/react-wp-scripts.git"
},
"bugs": {
"url": "https://github.com/humanmade/react-wp-scripts/issues"
},
"homepage": "https://github.com/humanmade/react-wp-scripts#readme",
"bin": {
"react-wp-scripts": "./bin/react-wp-scripts.js"
},
"dependencies": {
"chalk": "^2.3.2",
"minimist": "^1.2.0",
"react-scripts": "1.0.17",
"signal-exit": "^3.0.2"
}
"private": true,
"workspaces": [
"packages/*"
],
"devDependencies": {
"lerna": "^2.9.0"
}
}
7 changes: 7 additions & 0 deletions packages/create-react-wp-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# create-react-wp-plugin

This package includes the global plugin command for [react-wp-scripts](https://github.com/humanmade/react-wp-scripts).

Please refer to its documentation:

* [Getting Started](https://github.com/humanmade/react-wp-scripts/blob/master/README.md#easy-setup) – How to create a new app.
6 changes: 6 additions & 0 deletions packages/create-react-wp-plugin/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env node

const packageJson = require( './package.json' );
const run = require( '@humanmade/create-react-wp-project' );

run( 'plugin', packageJson );
25 changes: 25 additions & 0 deletions packages/create-react-wp-plugin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "create-react-wp-plugin",
"description": "Easily create a React-based WordPress plugin.",
"version": "0.0.1",
"contributors": [
"Ryan McCue",
"K. Adam White",
"Human Made"
],
"license": "GPL-2.0+",
"repository": {
"type": "git",
"url": "git+https://github.com/humanmade/react-wp-scripts.git"
},
"bugs": {
"url": "https://github.com/humanmade/react-wp-scripts/issues"
},
"homepage": "https://github.com/humanmade/react-wp-scripts#readme",
"bin": {
"create-react-wp-plugin": "./index.js"
},
"dependencies": {
"@humanmade/create-react-wp-project": "^0.0.1"
}
}
7 changes: 7 additions & 0 deletions packages/create-react-wp-project/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# create-react-wp-project

This package includes the common core for [react-wp-scripts commands](https://github.com/humanmade/react-wp-scripts).

Please refer to its documentation:

* [Getting Started](https://github.com/humanmade/react-wp-scripts/blob/master/README.md#easy-setup) – How to create a new app.
153 changes: 153 additions & 0 deletions packages/create-react-wp-project/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#!/usr/bin/env node

const chalk = require( 'chalk' );
const commander = require( 'commander' );
const child_process = require( 'child_process' );
const envinfo = require( 'envinfo' );
const fs = require( 'fs-extra' );
const path = require( 'path' );
const upperCamelCase = require( 'uppercamelcase' );

const craPath = require.resolve( 'create-react-app' );

function runCRA( args, namespace ) {
// Run, with our default flags.
const opts = {
stdio: 'inherit',
};
args.unshift(
'--using-crwp',
'--scripts-version',
'react-wp-scripts',
'--php-namespace',
namespace,
);

return new Promise( resolve => {
const proc = child_process.spawn( craPath, args, opts );
proc.on( 'close', code => {
if ( code !== 0 ) {
process.exit( code );
}

resolve();
} );
} );
}

function runAdditionalScripts( type, name, autoNamespace ) {
const rootDir = path.resolve( name );
const appName = path.basename( rootDir );

const originalDirectory = process.cwd();
process.chdir( rootDir );

// Run our follow-up.
const scriptsPath = path.resolve(
process.cwd(),
'node_modules',
'react-wp-scripts',
'scripts',
'init-extra.js'
);
const initExtra = require( scriptsPath );
initExtra( type, rootDir, appName, autoNamespace );
}

module.exports = function ( projectType, packageJson ) {
const args = process.argv;

let projectName;
const program = new commander.Command( packageJson.name )
.version( packageJson.version )
.arguments( '<project-directory>' )
.usage( `${chalk.green('<project-directory>')} [options]` )
.action( name => {
projectName = name;
} )
.option( '--verbose', 'print additional logs' )
.option( '--info', 'print environment debug info' )
.option( '--use-npm' )
.allowUnknownOption()
.on( '--help', () => {
console.log( ` Only ${chalk.green('<project-directory>')} is required.` );
console.log();
console.log(
` If you have any problems, do not hesitate to file an issue:`
);
console.log(
` ${chalk.cyan(
'https://github.com/humanmade/react-wp-scripts/issues/new'
)}`
);
console.log();
} )
.parse( process.argv );

if ( typeof projectName === 'undefined' ) {
if (program.info) {
envinfo.print( {
packages: ['react', 'react-dom', 'react-wp-scripts'],
noNativeIDE: true,
duplicates: true,
} );
process.exit( 0 );
}
console.error( 'Please specify the project directory:' );
console.log(
` ${chalk.cyan(program.name())} ${chalk.green('<project-directory>')}`
);
console.log();
console.log( 'For example:' );
console.log( ` ${chalk.cyan(program.name())} ${chalk.green('my-react-app')}` );
console.log();
console.log(
`Run ${chalk.cyan(`${program.name()} --help`)} to see all options.`
);
process.exit( 1 );
}

// Resolve the supplied path into an actual name.
const fullProjectPath = path.resolve( process.cwd(), projectName );
const autoNamespace = upperCamelCase( path.basename( fullProjectPath ) );

// Run create-react-app with all the additional arguments.
runCRA( args.slice( 2 ), autoNamespace )
.then( () => runAdditionalScripts(
projectType,
projectName,
autoNamespace,
) )
.catch( reason => {
console.log();
console.log( 'Aborting installation.' );
if ( reason.command ) {
console.log( ` ${chalk.cyan(reason.command)} has failed.` );
} else {
console.log( chalk.red( 'Unexpected error. Please report it as a bug:' ) );
console.log( reason );
}
console.log();

// On 'exit' we will delete these files from target directory.
const knownGeneratedFiles = [
'functions.php',
'style.css',
'plugin.php',
];
const currentFiles = fs.readdirSync(path.join(root));
currentFiles.forEach(file => {
knownGeneratedFiles.forEach(fileToMatch => {
// This will catch `(npm-debug|yarn-error|yarn-debug).log*` files
// and the rest of knownGeneratedFiles.
if (
(fileToMatch.match(/.log/g) && file.indexOf(fileToMatch) === 0) ||
file === fileToMatch
) {
console.log(`Deleting generated file... ${chalk.cyan(file)}`);
fs.removeSync(path.join(root, file));
}
});
});
} );
}
20 changes: 20 additions & 0 deletions packages/create-react-wp-project/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@humanmade/create-react-wp-project",
"description": "Private tools shared between create-react-wp-plugin and create-react-wp-theme.",
"version": "0.0.1",
"publishConfig": {
"access": "public"
},
"dependencies": {
"chalk": "^1.1.1",
"commander": "^2.9.0",
"create-react-app": "^1.5.2",
"envinfo": "3.4.2",
"fs-extra": "^1.0.0",
"semver": "^5.0.3",
"tar-pack": "^3.4.0",
"tmp": "0.0.31",
"uppercamelcase": "^3.0.0",
"validate-npm-package-name": "^3.0.0"
}
}
7 changes: 7 additions & 0 deletions packages/create-react-wp-theme/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# create-react-wp-theme

This package includes the global theme command for [react-wp-scripts](https://github.com/humanmade/react-wp-scripts).

Please refer to its documentation:

* [Getting Started](https://github.com/humanmade/react-wp-scripts/blob/master/README.md#easy-setup) – How to create a new app.
6 changes: 6 additions & 0 deletions packages/create-react-wp-theme/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env node

const packageJson = require( './package.json' );
const run = require( '@humanmade/create-react-wp-project' );

run( 'theme', packageJson );
Loading