@pollora/vite-config 1.0.0 → 1.1.1

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 CHANGED
@@ -24,6 +24,30 @@ It is a dev dependency of each theme, plugin or module, like `laravel-vite-plugi
24
24
 
25
25
  `<name>` is the directory name (`Modules/BlocksDemo` → `blocks-demo` for a module).
26
26
 
27
+ ## A classic theme, a plugin or a Bedrock site
28
+
29
+ Outside a Pollora project there is no shared `public/` directory to build into. `layout: 'standalone'` builds the package inside itself, where [`pollora/assets`](https://github.com/Pollora/assets) looks for it:
30
+
31
+ ```js
32
+ // wp-content/themes/my-theme/vite.config.js, or web/app/themes/my-theme/vite.config.js
33
+ import { defineConfig } from 'vite';
34
+ import pollora from '@pollora/vite-config';
35
+
36
+ export default defineConfig({
37
+ plugins: [pollora({ type: 'theme', layout: 'standalone' })],
38
+ });
39
+ ```
40
+
41
+ | | `layout: 'pollora'` (default) | `layout: 'standalone'` |
42
+ | --- | --- | --- |
43
+ | Build | `public/build/<type>/<name>/` | `build/` in the package |
44
+ | Hot file | `public/<name>.hot` | `hot` at the root of the package |
45
+ | `base` (URLs in the built CSS and chunks) | `/build/<type>/<name>/` | `./`: relative, so the build works wherever WordPress serves the folder from |
46
+ | Dev server | serves under the build path | serves from its root: the hot file holds the origin (`http://localhost:5173`) |
47
+ | Entry points | `resources/assets/app.js`, blocks | the same |
48
+
49
+ `buildDirectory` (`build`) and `hotFile` (`hot`) rename the two, and `publicDirectory` (`.`) moves the folder they sit in; give the same values to the container on the PHP side (`build_directory`, `hot_file`, `public_path`). The manifest keys do not change (`resources/assets/app.js`), so a file is looked up the same way in both layouts.
50
+
27
51
  ## Options
28
52
 
29
53
  | Option | Default | |
@@ -35,6 +59,10 @@ It is a dev dependency of each theme, plugin or module, like `laravel-vite-plugi
35
59
  | `tailwind` | `true` | Add `@tailwindcss/vite` |
36
60
  | `themeJson` | `{ baseThemeJsonPath: './theme.json' }` | Options for `wordpressThemeJson` (themes), or `false` |
37
61
  | `wordpress` | `{}` | Options for `wordpressPlugin` |
62
+ | `layout` | `'pollora'` | `'pollora'` (a Pollora project) or `'standalone'` (a classic theme, a plugin, Bedrock) |
63
+ | `publicDirectory` | the type's directory in a Pollora project, `.` when standalone | The public directory the build and hot file sit in, relative to the package root |
64
+ | `buildDirectory` | `build` (standalone only) | Build directory, relative to the public directory |
65
+ | `hotFile` | `hot` (standalone only) | Hot file, relative to the public directory |
38
66
  | `port` | `VITE_PORT`, else the type's port | Dev server port |
39
67
  | `refresh` | `[]` | Extra paths that reload the page |
40
68
  | `reloadOn` | theme: `['.blade.php']`, plugin and module: `['.blade.php', '.php']` | File endings whose change reloads the page (a block theme adds `.html`) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pollora/vite-config",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "Vite configuration shared by Pollora themes, plugins and modules",
5
5
  "license": "MIT",
6
6
  "author": "RuBee group (https://rubee.group)",
package/src/index.d.ts CHANGED
@@ -9,8 +9,17 @@ export interface PolloraOptions {
9
9
  root?: string;
10
10
  /** Entries besides blocks; defaults to resources/assets/app.js when it exists */
11
11
  input?: string[];
12
- /** The project's public directory, relative to the package root */
12
+ /**
13
+ * `pollora` (default): a Pollora project, built under its public directory as build/<type>/<name>.
14
+ * `standalone`: a classic theme, a plugin or a Bedrock site: built inside the package, into build/, with a hot file at its root.
15
+ */
16
+ layout?: 'pollora' | 'standalone';
17
+ /** The project's public directory, relative to the package root; the package root itself (`.`) for a standalone layout */
13
18
  publicDirectory?: string;
19
+ /** Standalone layout: the build directory, relative to the public directory (default `build`) */
20
+ buildDirectory?: string;
21
+ /** Standalone layout: the hot file, relative to the public directory (default `hot`) */
22
+ hotFile?: string;
14
23
  /** Dev server port; defaults to VITE_PORT, else 5173 (theme), 5174 (plugin), 5175 (module) */
15
24
  port?: number;
16
25
  /** Build the blocks in resources/views/blocks (default true) */
@@ -32,6 +41,17 @@ export interface PolloraOptions {
32
41
  export default function pollora(options: PolloraOptions): PluginOption[];
33
42
  export { pollora };
34
43
 
44
+ export function layoutOf(settings: {
45
+ layout?: 'pollora' | 'standalone';
46
+ type: 'theme' | 'plugin' | 'module';
47
+ name: string;
48
+ root: string;
49
+ publicDirectory?: string;
50
+ buildDirectory?: string;
51
+ hotFile?: string;
52
+ }): { publicDirectory: string; buildDirectory: string; hotFile: string; base: string | null };
53
+
35
54
  export function kebab(name: string): string;
36
55
  export function blockEntries(root: string): Record<string, string>;
37
56
  export function devServer(port: number): Record<string, unknown>;
57
+ export function usesWsOption(version?: string): boolean;
package/src/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import fs from 'node:fs';
3
3
  import { globSync } from 'glob';
4
+ import { version as viteVersion } from 'vite';
4
5
  import laravel, { refreshPaths } from 'laravel-vite-plugin';
5
6
 
6
7
  /**
@@ -70,6 +71,16 @@ function isDocker() {
70
71
  return Boolean(process.env.IS_DOCKER || process.env.DOCKER_ENV || process.env.DDEV_PRIMARY_URL);
71
72
  }
72
73
 
74
+ /**
75
+ * Vite 8.3.1 moved the WebSocket options from `server.hmr` to `server.ws` and
76
+ * deprecated the old place; earlier versions only know `server.hmr`.
77
+ */
78
+ export function usesWsOption(version = viteVersion) {
79
+ const [major, minor, patch] = version.split('.').map((part) => parseInt(part, 10));
80
+
81
+ return major > 8 || (major === 8 && (minor > 3 || (minor === 3 && patch >= 1)));
82
+ }
83
+
73
84
  /**
74
85
  * Dev server reachable from the site: inside DDEV or Docker it listens on every
75
86
  * interface and announces the site's own host, elsewhere it serves localhost.
@@ -78,6 +89,8 @@ export function devServer(port) {
78
89
  const url = baseUrl();
79
90
  const isHttps = url.startsWith('https');
80
91
  const hostname = new URL(url).hostname;
92
+ const socket = { protocol: isHttps ? 'wss' : 'ws', host: hostname };
93
+ const websocket = usesWsOption() ? { ws: socket } : { hmr: socket };
81
94
  const common = {
82
95
  port,
83
96
  strictPort: true,
@@ -93,7 +106,7 @@ export function devServer(port) {
93
106
  ...common,
94
107
  host: '0.0.0.0',
95
108
  origin: `${url}:${port}`,
96
- hmr: { protocol: isHttps ? 'wss' : 'ws', host: hostname },
109
+ ...websocket,
97
110
  };
98
111
  }
99
112
 
@@ -101,7 +114,7 @@ export function devServer(port) {
101
114
  ...common,
102
115
  https: isHttps,
103
116
  host: isHttps ? hostname : 'localhost',
104
- hmr: { protocol: isHttps ? 'wss' : 'ws', host: hostname },
117
+ ...websocket,
105
118
  };
106
119
  }
107
120
 
@@ -111,6 +124,39 @@ function resolvePort(option, fallback) {
111
124
  return port === undefined || port === '' ? fallback : Number(port);
112
125
  }
113
126
 
127
+ const LAYOUTS = ['pollora', 'standalone'];
128
+
129
+ /**
130
+ * Where a package builds, and where its dev server is announced.
131
+ *
132
+ * `pollora` is a Pollora project: every package builds under the project's
133
+ * public directory, as build/<type>/<name> with a <name>.hot file beside it.
134
+ * `standalone` is a classic theme, a plugin or a Bedrock site, which have no
135
+ * shared public directory: the package builds inside itself, into `build/`
136
+ * with a `hot` file at its root, and `base` is relative so the built CSS and
137
+ * chunks find each other wherever WordPress serves the folder from.
138
+ *
139
+ * @param {object} settings
140
+ * @returns {{ publicDirectory: string, buildDirectory: string, hotFile: string, base: string|null }}
141
+ */
142
+ export function layoutOf({ layout, type, name, root, publicDirectory, buildDirectory, hotFile }) {
143
+ if (layout === 'standalone') {
144
+ return {
145
+ publicDirectory: publicDirectory ?? '.',
146
+ buildDirectory: buildDirectory ?? 'build',
147
+ hotFile: path.resolve(root, publicDirectory ?? '.', hotFile ?? 'hot'),
148
+ base: null,
149
+ };
150
+ }
151
+
152
+ return {
153
+ publicDirectory: publicDirectory ?? TYPES[type].publicDirectory,
154
+ buildDirectory: path.join('build', type, name),
155
+ hotFile: path.resolve(root, publicDirectory ?? TYPES[type].publicDirectory, `${name}.hot`),
156
+ base: `/build/${type}/${name}`,
157
+ };
158
+ }
159
+
114
160
  /**
115
161
  * The Vite plugins a Pollora theme, plugin or module builds with.
116
162
  *
@@ -124,14 +170,23 @@ export default function pollora(options = {}) {
124
170
  throw new Error(`@pollora/vite-config: "type" must be one of ${Object.keys(TYPES).join(', ')}, got ${JSON.stringify(type)}.`);
125
171
  }
126
172
 
173
+ const layout = options.layout ?? 'pollora';
174
+
175
+ if (!LAYOUTS.includes(layout)) {
176
+ throw new Error(`@pollora/vite-config: "layout" must be one of ${LAYOUTS.join(', ')}, got ${JSON.stringify(layout)}.`);
177
+ }
178
+
127
179
  const defaults = TYPES[type];
128
180
  const root = path.resolve(options.root ?? process.cwd());
129
181
  const directoryName = path.basename(root);
130
182
  const name = options.name ?? (type === 'module' ? kebab(directoryName) : directoryName);
131
183
  // Relative to the package root: laravel-vite-plugin strips a leading slash
132
- const publicDirectory = options.publicDirectory ?? defaults.publicDirectory;
133
- const buildDirectory = path.join('build', type, name);
134
- const base = `/build/${type}/${name}`;
184
+ const { publicDirectory, buildDirectory, hotFile, base } = layoutOf({
185
+ layout, type, name, root,
186
+ publicDirectory: options.publicDirectory,
187
+ buildDirectory: options.buildDirectory,
188
+ hotFile: options.hotFile,
189
+ });
135
190
  const port = resolvePort(options.port, defaults.port);
136
191
 
137
192
  const blocks = options.blocks === false ? {} : blockEntries(root);
@@ -151,8 +206,9 @@ export default function pollora(options = {}) {
151
206
  const plugins = [
152
207
  {
153
208
  name: 'pollora:config',
154
- config: () => ({
155
- base,
209
+ // A standalone build is relative to wherever it is served from; its dev server serves from the root
210
+ config: (config, { command }) => ({
211
+ ...(base === null ? (command === 'build' ? { base: './' } : {}) : { base }),
156
212
  build: { emptyOutDir: false },
157
213
  server: devServer(port),
158
214
  }),
@@ -167,7 +223,7 @@ export default function pollora(options = {}) {
167
223
  input: [...input, ...Object.values(blocks)],
168
224
  publicDirectory,
169
225
  // Written from the working directory, unlike the build directory resolved from the root
170
- hotFile: path.resolve(root, publicDirectory, `${name}.hot`),
226
+ hotFile,
171
227
  buildDirectory,
172
228
  refresh,
173
229
  assets: options.assets ?? defaults.assets,