@elementor/wp-lite-env 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
package/index.d.ts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":""}
package/index.js ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ import { cleanup, commandMap, generateFiles, getCliCommand, getConfigFilePath, getPort } from './src/run';
3
+ const command = process.argv[2];
4
+ if (!commandMap[command]) {
5
+ console.log(`Valid commands: ${Object.keys(commandMap).join(', ')}. You used ${command}`);
6
+ }
7
+ const port = getPort(process.argv);
8
+ const configFilePath = getConfigFilePath(process.argv);
9
+ const runPath = generateFiles(port, configFilePath);
10
+ const cliCommand = getCliCommand(process.argv);
11
+ try {
12
+ await commandMap[command](port, runPath, cliCommand);
13
+ }
14
+ finally {
15
+ cleanup(port, runPath);
16
+ }
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@elementor/wp-lite-env",
3
+ "version": "0.0.6",
4
+ "private": false,
5
+ "description": "A simple, lightweight, docker-based WordPress environment",
6
+ "main": "dist/index.js",
7
+ "type": "module",
8
+ "types": "dist/index.d.ts",
9
+ "bin": {
10
+ "wp-lite-env": "dist/index.js"
11
+ },
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "lint": "eslint",
15
+ "release": "npm run build && changeset publish",
16
+ "test": "jest --coverage=true"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/elementor/wp-lite-env.git"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public",
24
+ "directory": "dist"
25
+ },
26
+ "author": "Elementor Team",
27
+ "license": "ISC",
28
+ "bugs": {
29
+ "url": "https://github.com/elementor/wp-lite-env/issues"
30
+ },
31
+ "homepage": "https://github.com/elementor/wp-lite-env#readme",
32
+ "dependencies": {
33
+ "docker-compose": "^1.1.0"
34
+ },
35
+ "devDependencies": {
36
+ "@changesets/cli": "^2.27.9",
37
+ "@eslint/js": "^9.15.0",
38
+ "@jest/globals": "^29.7.0",
39
+ "@types/eslint__js": "^8.42.3",
40
+ "@types/node": "^22.9.0",
41
+ "eslint": "~9.14.0",
42
+ "jest": "^29.7.0",
43
+ "ts-jest": "^29.2.5",
44
+ "typescript": "^5.6.3",
45
+ "typescript-eslint": "^8.14.0"
46
+ }
47
+ }
@@ -0,0 +1,16 @@
1
+ export type Config = {
2
+ core?: string;
3
+ phpVersion?: string;
4
+ plugins?: {
5
+ [key: string]: string;
6
+ };
7
+ themes?: {
8
+ [key: string]: string;
9
+ };
10
+ mappings?: {
11
+ [key: string]: string;
12
+ };
13
+ config?: Record<string, string | boolean>;
14
+ };
15
+ export declare const getConfig: (configFilePath?: string) => Config;
16
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,MAAM,GAAG;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACpC,MAAM,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACnC,QAAQ,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAC,OAAO,CAAC,CAAC;CACxC,CAAA;AAED,eAAO,MAAM,SAAS,oBAAsB,MAAM,KAAI,MAuBrD,CAAC"}
package/src/config.js ADDED
@@ -0,0 +1,23 @@
1
+ import fs from 'fs';
2
+ export const getConfig = (configFilePath) => {
3
+ let configFile = {};
4
+ if (configFilePath) {
5
+ configFile = JSON.parse(fs.readFileSync(configFilePath, 'utf8'));
6
+ }
7
+ const defaultConfig = {
8
+ core: '6.7',
9
+ phpVersion: '8.1',
10
+ plugins: {},
11
+ themes: {},
12
+ mappings: {},
13
+ config: {},
14
+ };
15
+ return {
16
+ core: configFile.core || defaultConfig.core,
17
+ phpVersion: configFile.phpVersion || defaultConfig.phpVersion,
18
+ plugins: configFile.plugins || defaultConfig.plugins,
19
+ themes: configFile.themes || defaultConfig.themes,
20
+ mappings: configFile.mappings || defaultConfig.mappings,
21
+ config: configFile.config || defaultConfig.config,
22
+ };
23
+ };
package/src/run.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ export declare const start: (port: string, runPath: string) => Promise<void>;
2
+ export declare const stop: (port: string, runPath: string) => Promise<void>;
3
+ export declare const commandMap: {
4
+ [key: string]: ((port: string) => Promise<void>) | ((port: string, runPath: string, command: string) => Promise<void>);
5
+ };
6
+ export declare const generateFiles: (port: string, configFilePath: string) => string;
7
+ export declare const getConfigFilePath: (processArgs: string[]) => string;
8
+ export declare const getCliCommand: (processArgs: string[]) => string;
9
+ export declare const getPort: (processArgs: string[]) => string;
10
+ export declare const cleanup: (port: string, runPath: string) => void;
11
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/run.ts"],"names":[],"mappings":"AAgCA,eAAO,MAAM,KAAK,SAAiB,MAAM,WAAW,MAAM,kBASzD,CAAC;AAEF,eAAO,MAAM,IAAI,SAAiB,MAAM,WAAW,MAAM,kBAOxD,CAAC;AAWF,eAAO,MAAM,UAAU,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAE,CAAE,IAAI,EAAE,MAAM,KAAM,OAAO,CAAC,IAAI,CAAC,CAAE,GAAG,CAAE,CAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAM,OAAO,CAAC,IAAI,CAAC,CAAE,CAAA;CAIxJ,CAAC;AAIF,eAAO,MAAM,aAAa,SAAW,MAAM,kBAAkB,MAAM,WA4BlE,CAAC;AAYF,eAAO,MAAM,iBAAiB,gBAAkB,MAAM,EAAE,WAEvD,CAAC;AAEF,eAAO,MAAM,aAAa,gBAAkB,MAAM,EAAE,WAEnD,CAAC;AAEF,eAAO,MAAM,OAAO,gBAAkB,MAAM,EAAE,WAE7C,CAAC;AAEF,eAAO,MAAM,OAAO,SAAW,MAAM,WAAW,MAAM,SAGrD,CAAA"}
package/src/run.js ADDED
@@ -0,0 +1,105 @@
1
+ import { downAll, run, upAll } from "docker-compose";
2
+ import path from "path";
3
+ import { getConfig } from "./config";
4
+ import fs from "fs";
5
+ import { generateCliDockerfileTemplate, generateConfiguration, generateDockerComposeYmlTemplate, generateWordPressDockerfileTemplate } from "./templates";
6
+ import { createHash } from "crypto";
7
+ import os from "node:os";
8
+ const waitForServer = async (url, timeoutMs) => {
9
+ const startTime = Date.now();
10
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
11
+ while (startTime + timeoutMs > Date.now()) {
12
+ try {
13
+ const response = await fetch(url);
14
+ if (response.ok && (200 === response.status || 302 === response.status)) {
15
+ return true;
16
+ }
17
+ }
18
+ catch (e) { // eslint-disable-line @typescript-eslint/no-unused-vars
19
+ // Ignore
20
+ }
21
+ finally {
22
+ await sleep(100);
23
+ }
24
+ }
25
+ return false;
26
+ };
27
+ export const start = async (port, runPath) => {
28
+ await upAll({
29
+ commandOptions: ['--build'],
30
+ composeOptions: ['-p', `port${port}`],
31
+ cwd: runPath,
32
+ log: true,
33
+ });
34
+ await waitForServer(`http://localhost:${port}`, 10000);
35
+ await cli(port, runPath, 'bash wp-config/configure-wp.sh');
36
+ };
37
+ export const stop = async (port, runPath) => {
38
+ await downAll({
39
+ cwd: runPath,
40
+ commandOptions: ['--volumes', '--remove-orphans'],
41
+ composeOptions: ['-p', `port${port}`],
42
+ log: true,
43
+ });
44
+ };
45
+ const cli = async (port, runPath, command) => {
46
+ await run('cli', command, {
47
+ cwd: runPath,
48
+ commandOptions: ['--rm'],
49
+ composeOptions: ['-p', `port${port}`],
50
+ log: true,
51
+ });
52
+ };
53
+ export const commandMap = {
54
+ start,
55
+ stop,
56
+ cli,
57
+ };
58
+ const getWpConfigPath = (port) => path.resolve(process.cwd(), port);
59
+ export const generateFiles = (port, configFilePath) => {
60
+ const config = getConfig(configFilePath);
61
+ // Using a local path since Docker Compose cannot access /tmp
62
+ // See: https://github.com/docker/compose/issues/1153
63
+ const wpConfigPath = getWpConfigPath(port);
64
+ if (!fs.existsSync(wpConfigPath)) {
65
+ fs.mkdirSync(wpConfigPath, { recursive: true });
66
+ }
67
+ const wpConfig = generateConfiguration(config, port);
68
+ fs.writeFileSync(path.resolve(wpConfigPath, 'configure-wp.sh'), wpConfig);
69
+ const dockerComposeYmlTemplate = generateDockerComposeYmlTemplate(config, process.cwd(), port, wpConfigPath);
70
+ const wordPressDockerfileTemplate = generateWordPressDockerfileTemplate(config);
71
+ const cliDockerfileTemplate = generateCliDockerfileTemplate(config);
72
+ const hash = createHash('sha256');
73
+ hash.update(dockerComposeYmlTemplate + wordPressDockerfileTemplate + cliDockerfileTemplate + port);
74
+ const runPath = path.resolve(os.tmpdir(), `${hash.digest('hex')}`);
75
+ if (!fs.existsSync(runPath)) {
76
+ fs.mkdirSync(runPath);
77
+ }
78
+ console.log(`writing files to run path: ${runPath}`);
79
+ fs.writeFileSync(path.resolve(runPath, 'docker-compose.yml'), dockerComposeYmlTemplate);
80
+ fs.writeFileSync(path.resolve(runPath, 'WordPress.Dockerfile'), wordPressDockerfileTemplate);
81
+ fs.writeFileSync(path.resolve(runPath, 'CLI.Dockerfile'), cliDockerfileTemplate);
82
+ return runPath;
83
+ };
84
+ const getArgument = (argumentKey, processArgs) => {
85
+ for (let i = 3; i < processArgs.length; i++) {
86
+ const argument = processArgs[i];
87
+ if (argument.startsWith(`${argumentKey}=`)) {
88
+ return argument.substring(argumentKey.length + 1);
89
+ }
90
+ }
91
+ return undefined;
92
+ };
93
+ export const getConfigFilePath = (processArgs) => {
94
+ return path.resolve(getArgument('config', processArgs));
95
+ };
96
+ export const getCliCommand = (processArgs) => {
97
+ return getArgument('command', processArgs);
98
+ };
99
+ export const getPort = (processArgs) => {
100
+ return getArgument('port', processArgs) || '8888';
101
+ };
102
+ export const cleanup = (port, runPath) => {
103
+ fs.rmSync(getWpConfigPath(port), { recursive: true, force: true });
104
+ fs.rmSync(runPath, { recursive: true, force: true });
105
+ };
@@ -0,0 +1,6 @@
1
+ import { Config } from './config';
2
+ export declare const generateDockerComposeYmlTemplate: (config: Config, basePath: string, port: string, configPath: string) => string;
3
+ export declare const generateWordPressDockerfileTemplate: (config: Config) => string;
4
+ export declare const generateCliDockerfileTemplate: (config: Config) => string;
5
+ export declare const generateConfiguration: (config: Config, port: string) => string;
6
+ //# sourceMappingURL=templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,eAAO,MAAM,gCAAgC,WAAa,MAAM,YAAY,MAAM,QAAQ,MAAM,cAAc,MAAM,WA0EnH,CAAC;AAEF,eAAO,MAAM,mCAAmC,WAAa,MAAM,WASlE,CAAC;AAEF,eAAO,MAAM,6BAA6B,WAAa,MAAM,WAa5D,CAAC;AAEF,eAAO,MAAM,qBAAqB,WAAa,MAAM,QAAQ,MAAM,WAWlE,CAAC"}
@@ -0,0 +1,111 @@
1
+ import path from 'path';
2
+ export const generateDockerComposeYmlTemplate = (config, basePath, port, configPath) => {
3
+ const mappingsStringArray = Object.keys(config.mappings).map((key) => {
4
+ const value = config.mappings[key];
5
+ return ` - >-
6
+ ${path.resolve(basePath, value)}:/var/www/html/${key}\n`;
7
+ });
8
+ const pluginsStringArray = Object.keys(config.plugins).map((key) => {
9
+ const value = config.plugins[key];
10
+ return ` - >-
11
+ ${path.resolve(basePath, value)}:/var/www/html/wp-content/plugins/${key}\n`;
12
+ });
13
+ const themesStringArray = Object.keys(config.themes).map((key) => {
14
+ const value = config.themes[key];
15
+ return ` - >-
16
+ ${path.resolve(basePath, value)}:/var/www/html/wp-content/themes/${key}\n`;
17
+ });
18
+ const wpContent = ` - >-
19
+ wpcontent:/var/www/html\n`;
20
+ const wpConfig = ` - >-
21
+ ${configPath}:/var/www/html/wp-config\n`;
22
+ const volumes = mappingsStringArray.concat(pluginsStringArray).concat(themesStringArray).concat([wpContent, wpConfig]).join('');
23
+ return `services:
24
+ mysql:
25
+ image: 'mariadb:lts'
26
+ ports:
27
+ - '\${WP_ENV_MYSQL_PORT:-}:3306'
28
+ environment:
29
+ MYSQL_ROOT_HOST: '%'
30
+ MYSQL_ROOT_PASSWORD: password
31
+ MYSQL_DATABASE: wordpress
32
+ volumes:
33
+ - 'mysql:/var/lib/mysql'
34
+ wordpress:
35
+ depends_on:
36
+ - mysql
37
+ build:
38
+ context: .
39
+ dockerfile: WordPress.Dockerfile
40
+ no_cache: true
41
+ args: &ref_0
42
+ HOST_USERNAME: yotams
43
+ HOST_UID: '502'
44
+ HOST_GID: '20'
45
+ ports:
46
+ - '\${WP_ENV_PORT:-${port}}:80'
47
+ environment:
48
+ APACHE_RUN_USER: '#502'
49
+ APACHE_RUN_GROUP: '#20'
50
+ WORDPRESS_DB_USER: root
51
+ WORDPRESS_DB_PASSWORD: password
52
+ WORDPRESS_DB_NAME: wordpress
53
+ volumes: &ref_1
54
+ ${volumes}
55
+ extra_hosts:
56
+ - 'host.docker.internal:host-gateway'
57
+ cli:
58
+ depends_on:
59
+ - wordpress
60
+ build:
61
+ context: .
62
+ dockerfile: CLI.Dockerfile
63
+ args: *ref_0
64
+ volumes: *ref_1
65
+ user: '502:20'
66
+ environment:
67
+ WORDPRESS_DB_USER: root
68
+ WORDPRESS_DB_PASSWORD: password
69
+ WORDPRESS_DB_NAME: wordpress
70
+ extra_hosts:
71
+ - 'host.docker.internal:host-gateway'
72
+ volumes:
73
+ mysql: {}
74
+ wpcontent: {}
75
+ `;
76
+ };
77
+ export const generateWordPressDockerfileTemplate = (config) => {
78
+ return `FROM wordpress:${config.core}-php${config.phpVersion}
79
+ ARG HOST_USERNAME
80
+ ARG HOST_UID
81
+ ARG HOST_GID
82
+ # When the IDs are already in use we can still safely move on.
83
+ RUN groupadd -o -g $HOST_GID $HOST_USERNAME || true
84
+ RUN useradd -mlo -u $HOST_UID -g $HOST_GID $HOST_USERNAME || true
85
+ `;
86
+ };
87
+ export const generateCliDockerfileTemplate = (config) => {
88
+ return `FROM wordpress:cli-php${config.phpVersion}
89
+ ARG HOST_USERNAME
90
+ ARG HOST_UID
91
+ ARG HOST_GID
92
+ # When the IDs are already in use we can still safely move on.
93
+ RUN addgroup -g $HOST_GID $HOST_USERNAME || true
94
+ RUN useradd -mlo -u $HOST_UID -g $HOST_GID $HOST_USERNAME || true
95
+ # RUN adduser -h /home/$HOST_USERNAME -G $( getent group $HOST_GID | cut -d: -f1 ) -u $HOST_UID $HOST_USERNAME || true
96
+
97
+ # Have the container sleep infinitely to keep it alive for us to run commands on it.
98
+ CMD [ "/bin/sh", "-c", "while true; do sleep 2073600; done" ]
99
+ `;
100
+ };
101
+ export const generateConfiguration = (config, port) => {
102
+ const header = `#!/bin/bash
103
+ set -eox pipefail
104
+ `;
105
+ const configStringArray = Object.keys(config.config).map((key) => {
106
+ const value = config.config[key];
107
+ return `wp config set ${key} ${value} --raw`;
108
+ });
109
+ const wpCoreInstall = `wp core install --url="http://localhost:${port}" --title="test" --admin_user=admin --admin_password=password --admin_email=wordpress@example.com --skip-email`;
110
+ return [header, wpCoreInstall].concat(configStringArray).join('\n');
111
+ };