Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for declaring specific endpoints to be built #120

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
42 changes: 42 additions & 0 deletions __tests__/cli.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,48 @@ describe('CLI Build Command', () => {
expect(process.stdout.write).toHaveBeenCalledWith(` * my-theme `);
});

it('runs specific projects and entrypoints mode when requested', () => {
mockFs({
...requiredRealDirs,
plugins: {
'my-plugin': {
'package.json': JSON.stringify({
name: 'my-plugin',
}),
src: {
entrypoints: {
'some-file.js': 'console.log("file content here");',
'frontend.js': 'console.log("file content here");',
},
},
},
},
themes: {
'my-theme': {
'package.json': JSON.stringify({
name: 'my-theme',
}),
src: {
entrypoints: {
'some-file.js': 'console.log("file content here");',
},
},
},
},
'client-mu-plugins': {},
});

runCommand('build', '--once', 'my-plugin@frontend,my-theme');

expect(mockWebpack).toHaveBeenCalled();
expect(process.stdout.write).toHaveBeenCalledWith(
`\x1b[1mCompiling \x1b[4mlist\x1b[0m\x1b[1m of projects in development mode.\x1b[0m\n`,
);
expect(process.stdout.write).toHaveBeenCalledWith('Processing the following projects:\n');
expect(process.stdout.write).toHaveBeenCalledWith(` * my-plugin `);
expect(process.stdout.write).toHaveBeenCalledWith(` * my-theme `);
});

it('runs specific projects mode if some requested projects are not found', () => {
mockFs({
...requiredRealDirs,
Expand Down
14 changes: 14 additions & 0 deletions docs/CLI-Command-Usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ build-tools build my-plugin,my-theme

Notice that each defined project is not a full path, nor an entry point. We use the directory name as the project and the build tools then look for those as defined in the [Structuring Your Project guide](https://github.com/bigbite/build-tools/wiki/Project-Structuring), seeking through `client-mu-plugins`,`plugins` and `themes`.

## Individual entrypoints
You can define specific entrypoints to build by specifying them after `@` symbol and seperating entrypoints by `+` symbol.

Build all frontend entrypoints
```bash
build-tools build @frontend+editor
```

Build single project entrypoitns
```bash
build-tools build my-plugin@frontend
```


## Site-wide
If you need to build an entire sites worth of projects, which will often be the case come deployment, you can build all applicable projects by running the command from within your `wp-content` directory.

Expand Down
16 changes: 14 additions & 2 deletions src/commands/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const spinner = ora();

const { findAllProjectPaths, validateProject } = require('./../utils/projectpaths');
const { getPackage } = require('./../utils/get-package');
const { getFilteredEntryPoints } = require('./../utils/get-filtered-entrypoints');
const dirsExist = require('../utils/dirs-exist');
const getProjectConfig = require('../utils/get-project-config');

Expand Down Expand Up @@ -59,7 +60,7 @@ exports.handler = async ({

const mode = production ? 'production' : 'development';
// Use env variables if working on Webpack >=5.
const projectsList = projects.split(',').filter((item) => item.length > 0);
const projectsList = projects.split(',').filter((item) => item.length > 0).map((item) => item.split('@')[0]);
const hasTargetDirs = dirsExist(targetDirs);
const isAllProjects = (site || hasTargetDirs) && !projects;

Expand Down Expand Up @@ -115,7 +116,18 @@ exports.handler = async ({
spinner.start('Building webpack configs.\n');

const configMap = validProjects.map((packageObject) => {
const projectConfig = getProjectConfig(packageObject, mode);
// Empty array means all entrypoints.
let filteredEntrypoints = [];

if (projects.startsWith('@')) {
// Handle entrypoints when for standalone builds and all project builds.
filteredEntrypoints = projects.split('@')[1].split('+');
} else {
// Handle entrypoints for each specified project build.
filteredEntrypoints = getFilteredEntryPoints(projects)[packageObject.name];
}

const projectConfig = getProjectConfig(packageObject, mode, filteredEntrypoints);

return webpackConfig(projectConfig, mode);
});
Expand Down
2 changes: 1 addition & 1 deletion src/commands/build/webpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ module.exports = (__PROJECT_CONFIG__, mode) => {

let webpackConfig = {
mode,
entry: entrypoints(__PROJECT_CONFIG__.paths.src),
entry: entrypoints(__PROJECT_CONFIG__.paths.src, __PROJECT_CONFIG__.filteredEntrypoints),

resolve: {
modules: [__PROJECT_CONFIG__.paths.node_modules, 'node_modules'],
Expand Down
2 changes: 1 addition & 1 deletion src/utils/__tests__/entrypoints.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('Entrypoints', () => {
},
});
const src = './';
const result = entrypoints(src);
const result = entrypoints(src, []);
const cwd = process.cwd();
expect(result).toEqual({
'empty-dir': `${cwd}/entrypoints/empty-dir`,
Expand Down
21 changes: 21 additions & 0 deletions src/utils/__tests__/get-filtered-entrypoints.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const { getFilteredEntryPoints } = require('../get-filtered-entrypoints');

describe('Get filtered entrypoints', () => {
it('Return object with empty array if no filtered entry points', () => {
const projects = 'test-project';
const result = getFilteredEntryPoints(projects);
expect(result).toEqual({ 'test-project': [] });
});

it('Returns object with array of entrypoints', () => {
const projects = 'test-project@frontend+editor';
const result = getFilteredEntryPoints(projects);
expect(result).toEqual({ 'test-project': ['frontend', 'editor'] });
});

it('Return object with entrypoints where @ is present and empty array if non defined', () => {
const projects = 'test-project@editor,test-project-2';
const result = getFilteredEntryPoints(projects);
expect(result).toEqual({ 'test-project': ['editor'], 'test-project-2': []});
});
});
24 changes: 17 additions & 7 deletions src/utils/entrypoints.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ const path = require('path');
* Create entry points object from src folder.
*
* @param {string} src Project src path
* @param {array} filteredEntrypoints entry point to build (ie frontend, editor, etc).
* @returns {object} webpack entrypoints
*/
module.exports = (src) => {
module.exports = (src, filteredEntrypoints) => {
const entrypoints = `${src}/entrypoints`;
const pathToEntryPoints = path.resolve(process.cwd(), entrypoints);

Expand All @@ -16,10 +17,19 @@ module.exports = (src) => {
}

return fs.readdirSync(pathToEntryPoints).reduce(
(accumulator, file) => ({
...accumulator,
[file.split('.')[0]]: path.resolve(pathToEntryPoints, file),
}),
{},
);
(accumulator, file) => {
const type = file.split('.')[0];

// If types are provided, only watch/build those.
if (filteredEntrypoints.length > 0) {
if (!filteredEntrypoints.includes(type)) {
return accumulator;
}
}

return {
...accumulator,
[type]: path.resolve(pathToEntryPoints, file),
};
}, {});
};
37 changes: 37 additions & 0 deletions src/utils/get-filtered-entrypoints.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Get filtered entrypoints for projects.
*
* Example command: build project1@entry1+entry2,project2@entry3
* Example input: 'project1@entry1+entry2,project2@entry3'
* Example return: { project1: ['entry1', 'entry2'], project2: ['entry3'] }
*
* @param {Array} projects Projects of which to filter entrypoints for.
* @returns {object} An object with project keys of which value for each is the entrypoints to build.
*/
const getFilteredEntryPoints = (projects) => {
ampersarnie marked this conversation as resolved.
Show resolved Hide resolved
const filteredProjectEntryPoints = {};
const projectNames = projects.split(',');

projectNames.forEach((project) => {
const projectParts = project.split('@');
const projectName = projectParts[0];
const entryPoints = projectParts[1] ? projectParts[1].split('+') : [];

if (!projectName) {
return filteredProjectEntryPoints;
}

if (entryPoints.length === 0) {
filteredProjectEntryPoints[projectName] = [];
return;
}

return filteredProjectEntryPoints[projectName] = entryPoints;
});

return filteredProjectEntryPoints;
};

module.exports = {
getFilteredEntryPoints,
};
4 changes: 3 additions & 1 deletion src/utils/get-project-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ module.exports = (
},
path: './'
},
mode = 'development'
mode = 'development',
filteredEntrypoints = []
) => {
return {
name: packageObject?.name ?? '',
Expand All @@ -33,5 +34,6 @@ module.exports = (
clean: true,
copy: true,
mode,
filteredEntrypoints,
};
}