vite-wp 0.1.8 → 0.1.9
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/README.md +8 -22
- package/{starter → defaults}/wordpress/content/mu-plugins/vitewp-bridge.php +18 -0
- package/dist/astro.js +31 -1
- package/dist/cli.js +10 -0
- package/dist/commands/composer.d.ts +1 -0
- package/dist/commands/composer.js +13 -0
- package/dist/commands/dev.js +7 -7
- package/dist/commands/doctor.d.ts +3 -1
- package/dist/commands/doctor.js +155 -2
- package/dist/commands/init.js +4 -0
- package/dist/commands/wp.d.ts +1 -0
- package/dist/commands/wp.js +41 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +1 -0
- package/dist/runtime/composer.d.ts +1 -0
- package/dist/runtime/composer.js +11 -4
- package/dist/runtime/wp-config.js +20 -1
- package/package.json +3 -1
- package/starter/wordpress/content/mu-plugins/.gitkeep +0 -0
- /package/{starter → defaults}/wordpress/content/themes/vitewp/functions.php +0 -0
- /package/{starter → defaults}/wordpress/content/themes/vitewp/index.php +0 -0
- /package/{starter → defaults}/wordpress/content/themes/vitewp/style.css +0 -0
package/README.md
CHANGED
|
@@ -2,22 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
ViteWP is an Astro-first WordPress development framework.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
```txt
|
|
8
|
-
http://localhost:3000
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
PHP and Astro still run internally, but you normally only use the unified ViteWP URL.
|
|
5
|
+
One entrypoint for everything you need, no fuzz and no magic.
|
|
12
6
|
|
|
13
7
|
## Requirements
|
|
14
8
|
|
|
15
9
|
- Node.js 20+
|
|
16
10
|
- PHP 8.2+
|
|
17
11
|
- Composer
|
|
18
|
-
- MySQL or MariaDB
|
|
19
|
-
|
|
20
|
-
ViteWP is bring-your-own database. It does not start MySQL for you.
|
|
12
|
+
- a MySQL or MariaDB server
|
|
21
13
|
|
|
22
14
|
## Get started
|
|
23
15
|
|
|
@@ -27,12 +19,11 @@ cd my-site
|
|
|
27
19
|
npm init -y
|
|
28
20
|
npx vite-wp init
|
|
29
21
|
cp .env.example .env
|
|
30
|
-
npm run dev
|
|
31
22
|
```
|
|
32
23
|
|
|
33
24
|
`vite-wp init` creates the starter files, adds the needed package dependencies, and runs install.
|
|
34
25
|
|
|
35
|
-
Edit `.env` with your database credentials, then open:
|
|
26
|
+
Edit `.env` with your database credentials, run `npm run dev`, wait for the initial configuration and then open:
|
|
36
27
|
|
|
37
28
|
```txt
|
|
38
29
|
http://localhost:3000
|
|
@@ -47,6 +38,8 @@ npm run dev # Start the local ViteWP runtime
|
|
|
47
38
|
npm run doctor # Check PHP, Composer, WordPress, config, and environment
|
|
48
39
|
npm run types # Generate WordPress-derived TypeScript types
|
|
49
40
|
npm run check # Run Astro type checking
|
|
41
|
+
npx vite-wp composer install # Run Composer in the project
|
|
42
|
+
npx vite-wp wp plugin list # Run WP-CLI when installed
|
|
50
43
|
```
|
|
51
44
|
|
|
52
45
|
For internal runtime diagnostics:
|
|
@@ -71,15 +64,15 @@ my-site/
|
|
|
71
64
|
wordpress/
|
|
72
65
|
public/ # Composer-installed WordPress core
|
|
73
66
|
content/
|
|
74
|
-
mu-plugins/
|
|
75
|
-
themes/
|
|
67
|
+
mu-plugins/ # ViteWP bridge is generated here
|
|
68
|
+
themes/ # ViteWP placeholder theme is generated here
|
|
76
69
|
plugins/
|
|
77
70
|
uploads/
|
|
78
71
|
```
|
|
79
72
|
|
|
80
73
|
## Templates
|
|
81
74
|
|
|
82
|
-
ViteWP ships default templates from the package. Create files in `src/templates` only when you want to override them.
|
|
75
|
+
ViteWP ships default templates from the package. Create files in `src/templates` only when you want to override them.
|
|
83
76
|
|
|
84
77
|
Examples:
|
|
85
78
|
|
|
@@ -106,10 +99,3 @@ const menu = await getLiveEntry('menus', { location: 'primary' });
|
|
|
106
99
|
```
|
|
107
100
|
|
|
108
101
|
After `npm run dev` or `npm run check`, collection names and filters should have TypeScript completion.
|
|
109
|
-
|
|
110
|
-
## Notes
|
|
111
|
-
|
|
112
|
-
- WordPress core is installed into `wordpress/public` by Composer.
|
|
113
|
-
- Do not commit `wordpress/public`, `.env`, `.vitewp`, or uploads.
|
|
114
|
-
- The tiny placeholder theme exists only to keep WordPress admin happy.
|
|
115
|
-
- Docker is optional, not required.
|
|
@@ -47,6 +47,24 @@ add_action('rest_api_init', function () {
|
|
|
47
47
|
},
|
|
48
48
|
]);
|
|
49
49
|
|
|
50
|
+
register_rest_route('vitewp/v1', '/health', [
|
|
51
|
+
'methods' => WP_REST_Server::READABLE,
|
|
52
|
+
'permission_callback' => '__return_true',
|
|
53
|
+
'callback' => function () {
|
|
54
|
+
return [
|
|
55
|
+
'wordpressVersion' => get_bloginfo('version'),
|
|
56
|
+
'phpVersion' => PHP_VERSION,
|
|
57
|
+
'homeUrl' => home_url('/'),
|
|
58
|
+
'siteUrl' => site_url('/'),
|
|
59
|
+
'permalinkStructure' => (string) get_option('permalink_structure'),
|
|
60
|
+
'activeTheme' => get_stylesheet(),
|
|
61
|
+
'template' => get_template(),
|
|
62
|
+
'activePlugins' => array_values((array) get_option('active_plugins', [])),
|
|
63
|
+
'muPlugins' => array_values(array_keys(get_mu_plugins())),
|
|
64
|
+
];
|
|
65
|
+
},
|
|
66
|
+
]);
|
|
67
|
+
|
|
50
68
|
register_rest_route('vitewp/v1', '/types', [
|
|
51
69
|
'methods' => WP_REST_Server::READABLE,
|
|
52
70
|
'permission_callback' => '__return_true',
|
package/dist/astro.js
CHANGED
|
@@ -5,7 +5,16 @@ export default function vitewp(_options = {}) {
|
|
|
5
5
|
return {
|
|
6
6
|
name: 'vitewp',
|
|
7
7
|
hooks: {
|
|
8
|
-
'astro:config:setup': ({ command, config, injectRoute, addDevToolbarApp, logger }) => {
|
|
8
|
+
'astro:config:setup': ({ command, config, injectRoute, addDevToolbarApp, logger, updateConfig }) => {
|
|
9
|
+
if (isSourceIntegration()) {
|
|
10
|
+
updateConfig({
|
|
11
|
+
vite: {
|
|
12
|
+
resolve: {
|
|
13
|
+
alias: sourceAliases(),
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
}
|
|
9
18
|
if (!hasProjectCatchAllRoute(fileURLToPath(config.root))) {
|
|
10
19
|
injectRoute({
|
|
11
20
|
pattern: '/[...slug]',
|
|
@@ -47,3 +56,24 @@ function getDevToolbarEntrypoint() {
|
|
|
47
56
|
}
|
|
48
57
|
return new URL('./dev-toolbar/vitewp-toolbar.js', import.meta.url);
|
|
49
58
|
}
|
|
59
|
+
function isSourceIntegration() {
|
|
60
|
+
return fileURLToPath(import.meta.url).endsWith('/src/astro.ts');
|
|
61
|
+
}
|
|
62
|
+
function sourceAliases() {
|
|
63
|
+
return [
|
|
64
|
+
alias('vite-wp/wordpress/templates', './wordpress/templates.ts'),
|
|
65
|
+
alias('vite-wp/wordpress/client', './wordpress/client.ts'),
|
|
66
|
+
alias('vite-wp/wordpress/menus', './wordpress/menus.ts'),
|
|
67
|
+
alias('vite-wp/wordpress/schemas', './wordpress/schemas.ts'),
|
|
68
|
+
alias('vite-wp/wordpress', './wordpress/index.ts'),
|
|
69
|
+
alias('vite-wp/content', './content.ts'),
|
|
70
|
+
alias('vite-wp/astro', './astro.ts'),
|
|
71
|
+
alias('vite-wp', './index.ts'),
|
|
72
|
+
];
|
|
73
|
+
}
|
|
74
|
+
function alias(find, replacement) {
|
|
75
|
+
return {
|
|
76
|
+
find,
|
|
77
|
+
replacement: fileURLToPath(new URL(replacement, import.meta.url)),
|
|
78
|
+
};
|
|
79
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -4,6 +4,8 @@ import { runDoctor } from './commands/doctor.js';
|
|
|
4
4
|
import { runSmoke } from './commands/smoke.js';
|
|
5
5
|
import { runTypes } from './commands/types.js';
|
|
6
6
|
import { runInit } from './commands/init.js';
|
|
7
|
+
import { runComposerCommand } from './commands/composer.js';
|
|
8
|
+
import { runWpCommand } from './commands/wp.js';
|
|
7
9
|
const command = process.argv[2] ?? 'help';
|
|
8
10
|
switch (command) {
|
|
9
11
|
case 'dev':
|
|
@@ -18,6 +20,12 @@ switch (command) {
|
|
|
18
20
|
case 'types':
|
|
19
21
|
await runTypes();
|
|
20
22
|
break;
|
|
23
|
+
case 'composer':
|
|
24
|
+
await runComposerCommand();
|
|
25
|
+
break;
|
|
26
|
+
case 'wp':
|
|
27
|
+
await runWpCommand();
|
|
28
|
+
break;
|
|
21
29
|
case 'smoke':
|
|
22
30
|
await runSmoke();
|
|
23
31
|
break;
|
|
@@ -36,6 +44,8 @@ function printHelp() {
|
|
|
36
44
|
vite-wp dev Start the local WordPress + Astro development runtime
|
|
37
45
|
vite-wp doctor Check the current project setup
|
|
38
46
|
vite-wp types Generate TypeScript types from WordPress metadata
|
|
47
|
+
vite-wp composer Run Composer in the ViteWP project
|
|
48
|
+
vite-wp wp Run WP-CLI for the local WordPress runtime
|
|
39
49
|
vite-wp smoke Verify the running ViteWP dev runtime
|
|
40
50
|
|
|
41
51
|
Options:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runComposerCommand(args?: string[]): Promise<void>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { loadViteWpConfig } from '../config.js';
|
|
2
|
+
import { runComposer } from '../runtime/composer.js';
|
|
3
|
+
export async function runComposerCommand(args = process.argv.slice(3)) {
|
|
4
|
+
const config = await loadViteWpConfig();
|
|
5
|
+
const composerArgs = args.length > 0 ? args : ['install'];
|
|
6
|
+
try {
|
|
7
|
+
await runComposer(config.root, composerArgs);
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
console.error(error instanceof Error ? error.message : error);
|
|
11
|
+
process.exitCode = 1;
|
|
12
|
+
}
|
|
13
|
+
}
|
package/dist/commands/dev.js
CHANGED
|
@@ -20,16 +20,16 @@ export async function runDev() {
|
|
|
20
20
|
console.log(`- templates: ${config.templates.directory}`);
|
|
21
21
|
console.log(`- database: ${config.database.driver}://${config.database.user}@${config.database.host}:${config.database.port}/${config.database.name}`);
|
|
22
22
|
console.log('');
|
|
23
|
-
const result = await runDoctorChecks(config);
|
|
24
|
-
if (result.errors > 0) {
|
|
25
|
-
console.log('');
|
|
26
|
-
console.log('Fix the errors above before starting the dev runtime.');
|
|
27
|
-
process.exitCode = 1;
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
23
|
try {
|
|
31
24
|
await ensureComposerInstall(config);
|
|
32
25
|
writeWordPressConfig(config);
|
|
26
|
+
const result = await runDoctorChecks(config, { live: false });
|
|
27
|
+
if (result.errors > 0) {
|
|
28
|
+
console.log('');
|
|
29
|
+
console.log('Fix the errors above before starting the dev runtime.');
|
|
30
|
+
process.exitCode = 1;
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
33
|
await stopAstroServer(config);
|
|
34
34
|
config.dev.phpPort = await resolveInternalPort(config.dev.phpHost, config.dev.phpPort);
|
|
35
35
|
config.dev.astroPort = await resolveInternalPort(config.dev.astroHost, config.dev.astroPort);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type LoadedViteWpConfig } from '../config.js';
|
|
2
2
|
export declare function runDoctor(): Promise<void>;
|
|
3
|
-
export declare function runDoctorChecks(config: LoadedViteWpConfig
|
|
3
|
+
export declare function runDoctorChecks(config: LoadedViteWpConfig, options?: {
|
|
4
|
+
live?: boolean;
|
|
5
|
+
}): Promise<{
|
|
4
6
|
errors: number;
|
|
5
7
|
warnings: number;
|
|
6
8
|
}>;
|
package/dist/commands/doctor.js
CHANGED
|
@@ -9,7 +9,8 @@ export async function runDoctor() {
|
|
|
9
9
|
const result = await runDoctorChecks(config);
|
|
10
10
|
process.exitCode = result.errors > 0 ? 1 : 0;
|
|
11
11
|
}
|
|
12
|
-
export async function runDoctorChecks(config) {
|
|
12
|
+
export async function runDoctorChecks(config, options = {}) {
|
|
13
|
+
const live = options.live ?? true;
|
|
13
14
|
const checks = [];
|
|
14
15
|
checks.push({
|
|
15
16
|
status: config.configFile ? 'pass' : 'warn',
|
|
@@ -19,15 +20,23 @@ export async function runDoctorChecks(config) {
|
|
|
19
20
|
checks.push(fileCheck(config.root, 'astro.config.mjs', 'Astro config'));
|
|
20
21
|
checks.push(fileCheck(config.root, 'composer.json', 'Composer manifest'));
|
|
21
22
|
checks.push(composerWordPressCheck(config.root, config.composer.wordpressPackage));
|
|
23
|
+
checks.push(composerInstallDirCheck(config));
|
|
22
24
|
checks.push(fileCheck(config.root, 'composer.lock', 'Composer lockfile'));
|
|
25
|
+
checks.push(composerLockCheck(config.root, config.composer.wordpressPackage));
|
|
23
26
|
checks.push(fileCheck(config.root, `${config.wordpress.docroot}/wp-settings.php`, 'Composer-installed WordPress core'));
|
|
24
27
|
checks.push(fileCheck(config.root, `${config.wordpress.docroot}/wp-config.php`, 'Generated wp-config.php'));
|
|
28
|
+
checks.push(fileCheck(config.root, `${config.wordpress.contentDir}/mu-plugins/vitewp-bridge.php`, 'ViteWP bridge mu-plugin'));
|
|
25
29
|
checks.push(fileCheck(config.root, `${config.wordpress.contentDir}/themes/vitewp/style.css`, 'ViteWP placeholder theme'));
|
|
26
|
-
checks.push(
|
|
30
|
+
checks.push(templateDirectoryCheck(config));
|
|
27
31
|
checks.push(databaseConfigCheck(config));
|
|
28
32
|
checks.push(await commandCheck('php', ['-v'], 'PHP runtime'));
|
|
29
33
|
checks.push(await commandCheck('composer', ['--version'], 'Composer'));
|
|
30
34
|
checks.push(gitignoreCheck(config.root, config.wordpress.docroot));
|
|
35
|
+
checks.push(runtimeFilesIgnoredCheck(config.root, config.wordpress.contentDir));
|
|
36
|
+
checks.push(...requiredPluginFileChecks(config));
|
|
37
|
+
if (live) {
|
|
38
|
+
checks.push(await wordpressHealthCheck(config));
|
|
39
|
+
}
|
|
31
40
|
printChecks(checks);
|
|
32
41
|
const errors = checks.filter((check) => check.status === 'fail').length;
|
|
33
42
|
const warnings = checks.filter((check) => check.status === 'warn').length;
|
|
@@ -41,6 +50,16 @@ function fileCheck(root, relativePath, label) {
|
|
|
41
50
|
? { status: 'pass', label, detail: relativePath }
|
|
42
51
|
: { status: 'warn', label, detail: `${relativePath} does not exist yet.` };
|
|
43
52
|
}
|
|
53
|
+
function templateDirectoryCheck(config) {
|
|
54
|
+
const directory = join(config.root, config.templates.directory);
|
|
55
|
+
return existsSync(directory)
|
|
56
|
+
? { status: 'pass', label: 'Project template overrides', detail: config.templates.directory }
|
|
57
|
+
: {
|
|
58
|
+
status: 'pass',
|
|
59
|
+
label: 'Project template overrides',
|
|
60
|
+
detail: `${config.templates.directory} is optional; package defaults will be used.`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
44
63
|
async function commandCheck(command, args, label) {
|
|
45
64
|
try {
|
|
46
65
|
const { stdout, stderr } = await execFileAsync(command, args);
|
|
@@ -114,6 +133,74 @@ function composerWordPressCheck(root, wordpressPackage) {
|
|
|
114
133
|
};
|
|
115
134
|
}
|
|
116
135
|
}
|
|
136
|
+
function composerInstallDirCheck(config) {
|
|
137
|
+
const composerPath = join(config.root, 'composer.json');
|
|
138
|
+
if (!existsSync(composerPath)) {
|
|
139
|
+
return {
|
|
140
|
+
status: 'warn',
|
|
141
|
+
label: 'Composer WordPress install dir',
|
|
142
|
+
detail: 'composer.json does not exist yet.',
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
const composer = JSON.parse(readFileSync(composerPath, 'utf8'));
|
|
147
|
+
const installDir = composer.extra?.['wordpress-install-dir'];
|
|
148
|
+
if (!installDir) {
|
|
149
|
+
return {
|
|
150
|
+
status: 'warn',
|
|
151
|
+
label: 'Composer WordPress install dir',
|
|
152
|
+
detail: 'extra.wordpress-install-dir is not set.',
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
return installDir === config.wordpress.docroot
|
|
156
|
+
? { status: 'pass', label: 'Composer WordPress install dir', detail: installDir }
|
|
157
|
+
: {
|
|
158
|
+
status: 'fail',
|
|
159
|
+
label: 'Composer WordPress install dir',
|
|
160
|
+
detail: `${installDir} does not match config docroot ${config.wordpress.docroot}.`,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
return {
|
|
165
|
+
status: 'fail',
|
|
166
|
+
label: 'Composer WordPress install dir',
|
|
167
|
+
detail: error instanceof Error ? error.message : 'Could not parse composer.json.',
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function composerLockCheck(root, wordpressPackage) {
|
|
172
|
+
const lockPath = join(root, 'composer.lock');
|
|
173
|
+
if (!existsSync(lockPath)) {
|
|
174
|
+
return {
|
|
175
|
+
status: 'warn',
|
|
176
|
+
label: 'Locked WordPress version',
|
|
177
|
+
detail: 'Run composer install to create composer.lock.',
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
const lock = JSON.parse(readFileSync(lockPath, 'utf8'));
|
|
182
|
+
const wordpress = lock.packages?.find((pkg) => pkg.name === wordpressPackage);
|
|
183
|
+
if (!wordpress?.version) {
|
|
184
|
+
return {
|
|
185
|
+
status: 'fail',
|
|
186
|
+
label: 'Locked WordPress version',
|
|
187
|
+
detail: `${wordpressPackage} was not found in composer.lock.`,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
status: 'pass',
|
|
192
|
+
label: 'Locked WordPress version',
|
|
193
|
+
detail: `${wordpressPackage}@${wordpress.version}`,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
return {
|
|
198
|
+
status: 'fail',
|
|
199
|
+
label: 'Locked WordPress version',
|
|
200
|
+
detail: error instanceof Error ? error.message : 'Could not parse composer.lock.',
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
}
|
|
117
204
|
function gitignoreCheck(root, docroot) {
|
|
118
205
|
const gitignorePath = join(root, '.gitignore');
|
|
119
206
|
if (!existsSync(gitignorePath)) {
|
|
@@ -129,6 +216,72 @@ function gitignoreCheck(root, docroot) {
|
|
|
129
216
|
detail: `Add ${normalizedDocroot} to .gitignore.`,
|
|
130
217
|
};
|
|
131
218
|
}
|
|
219
|
+
function runtimeFilesIgnoredCheck(root, contentDir) {
|
|
220
|
+
const gitignorePath = join(root, '.gitignore');
|
|
221
|
+
if (!existsSync(gitignorePath)) {
|
|
222
|
+
return { status: 'warn', label: 'WordPress runtime files ignored', detail: '.gitignore is missing.' };
|
|
223
|
+
}
|
|
224
|
+
const gitignore = readFileSync(gitignorePath, 'utf8');
|
|
225
|
+
const required = [
|
|
226
|
+
`${contentDir}/uploads/`,
|
|
227
|
+
`${contentDir}/debug.log`,
|
|
228
|
+
];
|
|
229
|
+
const missing = required.filter((entry) => !gitignore.includes(entry));
|
|
230
|
+
return missing.length === 0
|
|
231
|
+
? { status: 'pass', label: 'WordPress runtime files ignored', detail: required.join(', ') }
|
|
232
|
+
: {
|
|
233
|
+
status: 'warn',
|
|
234
|
+
label: 'WordPress runtime files ignored',
|
|
235
|
+
detail: `Add ${missing.join(', ')} to .gitignore.`,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
function requiredPluginFileChecks(config) {
|
|
239
|
+
return config.wordpress.requiredPlugins.map((plugin) => {
|
|
240
|
+
const directory = `${config.wordpress.contentDir}/plugins/${plugin}`;
|
|
241
|
+
return fileCheck(config.root, directory, `Required plugin files: ${plugin}`);
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
async function wordpressHealthCheck(config) {
|
|
245
|
+
const url = `${config.wordpress.url.replace(/\/$/, '')}/wp-json/vitewp/v1/health`;
|
|
246
|
+
const controller = new AbortController();
|
|
247
|
+
const timeout = setTimeout(() => controller.abort(), 5000);
|
|
248
|
+
try {
|
|
249
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
250
|
+
if (!response.ok) {
|
|
251
|
+
return {
|
|
252
|
+
status: 'warn',
|
|
253
|
+
label: 'WordPress health endpoint',
|
|
254
|
+
detail: `${url} returned ${response.status}. Start vite-wp dev if the runtime is offline.`,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
const health = await response.json();
|
|
258
|
+
const missingPlugins = config.wordpress.requiredPlugins.filter((plugin) => {
|
|
259
|
+
return !health.activePlugins?.some((active) => active === plugin || active.startsWith(`${plugin}/`));
|
|
260
|
+
});
|
|
261
|
+
if (missingPlugins.length > 0) {
|
|
262
|
+
return {
|
|
263
|
+
status: 'fail',
|
|
264
|
+
label: 'WordPress health endpoint',
|
|
265
|
+
detail: `Missing active plugin(s): ${missingPlugins.join(', ')}.`,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
return {
|
|
269
|
+
status: 'pass',
|
|
270
|
+
label: 'WordPress health endpoint',
|
|
271
|
+
detail: `WP ${health.wordpressVersion ?? '?'} / PHP ${health.phpVersion ?? '?'} / theme ${health.activeTheme ?? '?'} / permalinks ${health.permalinkStructure || 'plain'}`,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
return {
|
|
276
|
+
status: 'warn',
|
|
277
|
+
label: 'WordPress health endpoint',
|
|
278
|
+
detail: `Could not reach ${url}. Start vite-wp dev to run live health checks.`,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
finally {
|
|
282
|
+
clearTimeout(timeout);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
132
285
|
function printChecks(checks) {
|
|
133
286
|
console.log('ViteWP doctor');
|
|
134
287
|
console.log('');
|
package/dist/commands/init.js
CHANGED
|
@@ -59,6 +59,8 @@ function updatePackageJson(root, packageRoot) {
|
|
|
59
59
|
packageJson.scripts.dev ??= 'vite-wp dev';
|
|
60
60
|
packageJson.scripts.doctor ??= 'vite-wp doctor';
|
|
61
61
|
packageJson.scripts.types ??= 'vite-wp types';
|
|
62
|
+
packageJson.scripts.composer ??= 'vite-wp composer';
|
|
63
|
+
packageJson.scripts.wp ??= 'vite-wp wp';
|
|
62
64
|
packageJson.scripts.check ??= 'astro check';
|
|
63
65
|
packageJson.dependencies['vite-wp'] ??= `^${viteWp.version}`;
|
|
64
66
|
packageJson.dependencies.astro ??= '^7.0.6';
|
|
@@ -91,6 +93,8 @@ dist-ssr/
|
|
|
91
93
|
.vitewp/
|
|
92
94
|
.astro/
|
|
93
95
|
wordpress/public/
|
|
96
|
+
wordpress/content/mu-plugins/vitewp-bridge.php
|
|
97
|
+
wordpress/content/themes/vitewp/
|
|
94
98
|
wordpress/content/uploads/
|
|
95
99
|
wordpress/content/debug.log
|
|
96
100
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runWpCommand(args?: string[]): Promise<void>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { loadViteWpConfig } from '../config.js';
|
|
5
|
+
export async function runWpCommand(args = process.argv.slice(3)) {
|
|
6
|
+
const config = await loadViteWpConfig();
|
|
7
|
+
const command = wpBinary(config);
|
|
8
|
+
if (!command) {
|
|
9
|
+
console.error('Could not find WP-CLI. Install it globally as `wp` or add it to Composer.');
|
|
10
|
+
process.exitCode = 1;
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const wpArgs = [
|
|
14
|
+
`--path=${config.wordpress.docroot}`,
|
|
15
|
+
`--url=${config.wordpress.url}`,
|
|
16
|
+
...args,
|
|
17
|
+
];
|
|
18
|
+
const code = await spawnWp(config, command, wpArgs);
|
|
19
|
+
process.exitCode = code;
|
|
20
|
+
}
|
|
21
|
+
function wpBinary(config) {
|
|
22
|
+
const local = join(config.root, 'vendor/bin/wp');
|
|
23
|
+
if (existsSync(local)) {
|
|
24
|
+
return local;
|
|
25
|
+
}
|
|
26
|
+
return process.platform === 'win32' ? 'wp.cmd' : 'wp';
|
|
27
|
+
}
|
|
28
|
+
function spawnWp(config, command, args) {
|
|
29
|
+
return new Promise((resolve) => {
|
|
30
|
+
const child = spawn(command, args, {
|
|
31
|
+
cwd: config.root,
|
|
32
|
+
stdio: 'inherit',
|
|
33
|
+
env: process.env,
|
|
34
|
+
});
|
|
35
|
+
child.once('exit', (code) => resolve(code ?? 1));
|
|
36
|
+
child.once('error', (error) => {
|
|
37
|
+
console.error(`Could not run WP-CLI (${command}). ${error.message}`);
|
|
38
|
+
resolve(1);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
package/dist/config.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export interface ViteWpConfig {
|
|
|
14
14
|
url?: string;
|
|
15
15
|
docroot?: string;
|
|
16
16
|
contentDir?: string;
|
|
17
|
+
requiredPlugins?: string[];
|
|
17
18
|
};
|
|
18
19
|
composer?: {
|
|
19
20
|
install?: boolean;
|
|
@@ -49,6 +50,7 @@ export interface LoadedViteWpConfig {
|
|
|
49
50
|
url: string;
|
|
50
51
|
docroot: string;
|
|
51
52
|
contentDir: string;
|
|
53
|
+
requiredPlugins: string[];
|
|
52
54
|
};
|
|
53
55
|
composer: {
|
|
54
56
|
install: boolean;
|
package/dist/config.js
CHANGED
|
@@ -37,6 +37,7 @@ export async function loadViteWpConfig(root = process.cwd()) {
|
|
|
37
37
|
url: userConfig.wordpress?.url ?? 'http://localhost:3000',
|
|
38
38
|
docroot: userConfig.wordpress?.docroot ?? 'wordpress/public',
|
|
39
39
|
contentDir: userConfig.wordpress?.contentDir ?? 'wordpress/content',
|
|
40
|
+
requiredPlugins: userConfig.wordpress?.requiredPlugins ?? [],
|
|
40
41
|
},
|
|
41
42
|
composer: {
|
|
42
43
|
install: userConfig.composer?.install ?? true,
|
package/dist/runtime/composer.js
CHANGED
|
@@ -7,19 +7,23 @@ export async function ensureComposerInstall(config) {
|
|
|
7
7
|
return;
|
|
8
8
|
}
|
|
9
9
|
const lockfile = join(config.root, 'composer.lock');
|
|
10
|
+
const manifest = join(config.root, 'composer.json');
|
|
10
11
|
const vendor = join(config.root, 'vendor');
|
|
11
12
|
const wpSettings = join(config.root, config.wordpress.docroot, 'wp-settings.php');
|
|
13
|
+
if (!existsSync(manifest)) {
|
|
14
|
+
throw new Error('composer.json is missing. Run `vite-wp init` or add a Composer manifest before starting dev.');
|
|
15
|
+
}
|
|
12
16
|
if (existsSync(lockfile) && existsSync(vendor) && existsSync(wpSettings)) {
|
|
13
17
|
console.log('✓ Composer dependencies already installed');
|
|
14
18
|
return;
|
|
15
19
|
}
|
|
16
20
|
console.log('Installing Composer dependencies...');
|
|
17
|
-
await
|
|
21
|
+
await runComposer(config.root, ['install']);
|
|
18
22
|
console.log('✓ Composer dependencies ready');
|
|
19
23
|
}
|
|
20
|
-
function
|
|
24
|
+
export function runComposer(cwd, args) {
|
|
21
25
|
return new Promise((resolve, reject) => {
|
|
22
|
-
const child = spawn('composer',
|
|
26
|
+
const child = spawn('composer', args, {
|
|
23
27
|
cwd,
|
|
24
28
|
stdio: 'inherit',
|
|
25
29
|
env: { ...process.env, COMPOSER_ALLOW_SUPERUSER: process.env.COMPOSER_ALLOW_SUPERUSER ?? '1' },
|
|
@@ -29,8 +33,11 @@ function runComposerInstall(cwd) {
|
|
|
29
33
|
resolve();
|
|
30
34
|
}
|
|
31
35
|
else {
|
|
32
|
-
reject(new Error(`composer
|
|
36
|
+
reject(new Error(`composer ${args.join(' ')} failed with code ${code ?? 'unknown'}.`));
|
|
33
37
|
}
|
|
34
38
|
});
|
|
39
|
+
child.once('error', (error) => {
|
|
40
|
+
reject(new Error(`Could not run composer. Is Composer installed?\n${error.message}`));
|
|
41
|
+
});
|
|
35
42
|
});
|
|
36
43
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cpSync, existsSync, lstatSync, mkdirSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join, relative, resolve } from 'node:path';
|
|
3
3
|
import { randomBytes } from 'node:crypto';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
4
5
|
export function writeWordPressConfig(config) {
|
|
5
6
|
const docroot = resolve(config.root, config.wordpress.docroot);
|
|
6
7
|
const contentDir = resolve(config.root, config.wordpress.contentDir);
|
|
@@ -10,6 +11,7 @@ export function writeWordPressConfig(config) {
|
|
|
10
11
|
mkdirSync(join(contentDir, 'plugins'), { recursive: true });
|
|
11
12
|
mkdirSync(join(contentDir, 'mu-plugins'), { recursive: true });
|
|
12
13
|
mkdirSync(join(contentDir, 'uploads'), { recursive: true });
|
|
14
|
+
ensureDefaultContentFiles(contentDir);
|
|
13
15
|
ensureContentSymlink(docroot, contentDir);
|
|
14
16
|
writeFileSync(wpConfigPath, renderWpConfig(config, publicUrl, contentDir), 'utf8');
|
|
15
17
|
console.log(`✓ wp-config.php generated at ${relative(config.root, wpConfigPath)}`);
|
|
@@ -80,3 +82,20 @@ function ensureContentSymlink(docroot, contentDir) {
|
|
|
80
82
|
const target = relative(dirname(link), contentDir);
|
|
81
83
|
symlinkSync(target, link, 'dir');
|
|
82
84
|
}
|
|
85
|
+
function ensureDefaultContentFiles(contentDir) {
|
|
86
|
+
const packageContentDir = resolve(dirname(fileURLToPath(import.meta.url)), '../../defaults/wordpress/content');
|
|
87
|
+
copyPackageFile(join(packageContentDir, 'mu-plugins/vitewp-bridge.php'), join(contentDir, 'mu-plugins/vitewp-bridge.php'));
|
|
88
|
+
copyIfMissing(join(packageContentDir, 'themes/vitewp'), join(contentDir, 'themes/vitewp'));
|
|
89
|
+
}
|
|
90
|
+
function copyPackageFile(source, destination) {
|
|
91
|
+
if (!existsSync(source))
|
|
92
|
+
return;
|
|
93
|
+
mkdirSync(dirname(destination), { recursive: true });
|
|
94
|
+
cpSync(source, destination);
|
|
95
|
+
}
|
|
96
|
+
function copyIfMissing(source, destination) {
|
|
97
|
+
if (existsSync(destination) || !existsSync(source))
|
|
98
|
+
return;
|
|
99
|
+
mkdirSync(dirname(destination), { recursive: true });
|
|
100
|
+
cpSync(source, destination, { recursive: true });
|
|
101
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-wp",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.9",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"vite-wp": "dist/cli.js"
|
|
@@ -43,6 +43,8 @@
|
|
|
43
43
|
"scripts": {
|
|
44
44
|
"dev": "tsx src/cli.ts dev",
|
|
45
45
|
"doctor": "tsx src/cli.ts doctor",
|
|
46
|
+
"composer": "tsx src/cli.ts composer",
|
|
47
|
+
"wp": "tsx src/cli.ts wp",
|
|
46
48
|
"build": "rm -rf dist && tsc",
|
|
47
49
|
"prepack": "npm run build",
|
|
48
50
|
"pack:dry": "npm pack --dry-run",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|