@pollora/vite-config 0.0.0-stage → 1.0.0
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/LICENSE +21 -0
- package/README.md +50 -2
- package/package.json +46 -5
- package/src/index.d.ts +37 -0
- package/src/index.js +199 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 RuBee group (https://rubee.group)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,51 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @pollora/vite-config
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The Vite configuration shared by [Pollora](https://pollora.dev) themes, plugins and modules: where each one builds, its hot file, a dev server that works inside DDEV or Docker, its Gutenberg blocks, Tailwind CSS v4 and a page reload on Blade changes.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
// vite.config.js
|
|
7
|
+
import { defineConfig } from 'vite';
|
|
8
|
+
import pollora from '@pollora/vite-config';
|
|
9
|
+
|
|
10
|
+
export default defineConfig({
|
|
11
|
+
plugins: [pollora({ type: 'module' })],
|
|
12
|
+
});
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
It is a dev dependency of each theme, plugin or module, like `laravel-vite-plugin`. Nothing is shared at build time: each package keeps its own `package.json`, build and hot file, and pins its own version.
|
|
16
|
+
|
|
17
|
+
## What `type` sets
|
|
18
|
+
|
|
19
|
+
| `type` | Build directory (served by the framework) | Hot file | Default port | Extra |
|
|
20
|
+
| --- | --- | --- | --- | --- |
|
|
21
|
+
| `theme` | `public/build/theme/<name>` | `public/<name>.hot` | 5173 | `theme.json` generated from the `@theme` tokens (`wordpressThemeJson`) |
|
|
22
|
+
| `plugin` | `public/build/plugin/<name>` | `public/<name>.hot` | 5174 | Page reload on `.php` changes |
|
|
23
|
+
| `module` | `public/build/module/<kebab-name>` | `public/<kebab-name>.hot` | 5175 | Page reload on `.php` changes |
|
|
24
|
+
|
|
25
|
+
`<name>` is the directory name (`Modules/BlocksDemo` → `blocks-demo` for a module).
|
|
26
|
+
|
|
27
|
+
## Options
|
|
28
|
+
|
|
29
|
+
| Option | Default | |
|
|
30
|
+
| --- | --- | --- |
|
|
31
|
+
| `type` | required | `theme`, `plugin` or `module` |
|
|
32
|
+
| `name` | directory name | Name the build is served under |
|
|
33
|
+
| `input` | `resources/assets/app.js` when it exists | Entries besides blocks |
|
|
34
|
+
| `blocks` | `true` | Build `resources/views/blocks/*/{index,view}.{js,jsx,ts,tsx}` and `{editor,style}.css`, and add `@roots/vite-plugin`'s `wordpressPlugin` |
|
|
35
|
+
| `tailwind` | `true` | Add `@tailwindcss/vite` |
|
|
36
|
+
| `themeJson` | `{ baseThemeJsonPath: './theme.json' }` | Options for `wordpressThemeJson` (themes), or `false` |
|
|
37
|
+
| `wordpress` | `{}` | Options for `wordpressPlugin` |
|
|
38
|
+
| `port` | `VITE_PORT`, else the type's port | Dev server port |
|
|
39
|
+
| `refresh` | `[]` | Extra paths that reload the page |
|
|
40
|
+
| `reloadOn` | theme: `['.blade.php']`, plugin and module: `['.blade.php', '.php']` | File endings whose change reloads the page (a block theme adds `.html`) |
|
|
41
|
+
| `assets` | theme: `resources/assets/{images,fonts}/**` | Static assets copied to the build |
|
|
42
|
+
| `publicDirectory` | the project's `public/`, relative to the package | |
|
|
43
|
+
| `root` | working directory | Package root |
|
|
44
|
+
|
|
45
|
+
## Requirements
|
|
46
|
+
|
|
47
|
+
Node 20.19+, `vite` 7 or 8, `laravel-vite-plugin` 2 or 3. `@tailwindcss/vite` and `@roots/vite-plugin` are needed when Tailwind CSS, blocks or `theme.json` generation are on.
|
|
48
|
+
|
|
49
|
+
## License
|
|
50
|
+
|
|
51
|
+
MIT, © [RuBee group](https://rubee.group).
|
package/package.json
CHANGED
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@pollora/vite-config",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Vite configuration shared by Pollora themes, plugins and modules",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "RuBee group (https://rubee.group)",
|
|
7
|
+
"homepage": "https://pollora.dev",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/Pollora/vite-config.git"
|
|
11
|
+
},
|
|
12
|
+
"keywords": ["pollora", "vite", "wordpress", "laravel", "tailwindcss"],
|
|
13
|
+
"type": "module",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./src/index.d.ts",
|
|
17
|
+
"default": "./src/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": ["src"],
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=20.19"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"test": "node --test test/*.test.js"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"glob": "^11.0.0"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"@roots/vite-plugin": "^2.0.0",
|
|
32
|
+
"@tailwindcss/vite": "^4.0.0",
|
|
33
|
+
"laravel-vite-plugin": "^2.0.0 || ^3.0.0",
|
|
34
|
+
"vite": "^7.0.0 || ^8.0.0"
|
|
35
|
+
},
|
|
36
|
+
"peerDependenciesMeta": {
|
|
37
|
+
"@roots/vite-plugin": { "optional": true },
|
|
38
|
+
"@tailwindcss/vite": { "optional": true }
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@roots/vite-plugin": "^2.0.0",
|
|
42
|
+
"@tailwindcss/vite": "^4.2.3",
|
|
43
|
+
"laravel-vite-plugin": "^3.0.1",
|
|
44
|
+
"tailwindcss": "^4.2.3",
|
|
45
|
+
"vite": "^8.0.9"
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { PluginOption } from 'vite';
|
|
2
|
+
|
|
3
|
+
export interface PolloraOptions {
|
|
4
|
+
/** What is being built: sets the build directory, hot file and default port */
|
|
5
|
+
type: 'theme' | 'plugin' | 'module';
|
|
6
|
+
/** Name it is served under (build/<type>/<name>); defaults to the directory name, kebab-cased for a module */
|
|
7
|
+
name?: string;
|
|
8
|
+
/** Package root; defaults to the current working directory */
|
|
9
|
+
root?: string;
|
|
10
|
+
/** Entries besides blocks; defaults to resources/assets/app.js when it exists */
|
|
11
|
+
input?: string[];
|
|
12
|
+
/** The project's public directory, relative to the package root */
|
|
13
|
+
publicDirectory?: string;
|
|
14
|
+
/** Dev server port; defaults to VITE_PORT, else 5173 (theme), 5174 (plugin), 5175 (module) */
|
|
15
|
+
port?: number;
|
|
16
|
+
/** Build the blocks in resources/views/blocks (default true) */
|
|
17
|
+
blocks?: boolean;
|
|
18
|
+
/** Add @tailwindcss/vite (default true) */
|
|
19
|
+
tailwind?: boolean;
|
|
20
|
+
/** Options for @roots/vite-plugin's wordpressThemeJson, or false to skip it (themes only) */
|
|
21
|
+
themeJson?: Record<string, unknown> | false;
|
|
22
|
+
/** Options for @roots/vite-plugin's wordpressPlugin, used when there are blocks */
|
|
23
|
+
wordpress?: Record<string, unknown>;
|
|
24
|
+
/** File endings that reload the whole page in development; .blade.php for themes, plus .php for plugins and modules */
|
|
25
|
+
reloadOn?: string[];
|
|
26
|
+
/** Extra paths that reload the page in development */
|
|
27
|
+
refresh?: string[];
|
|
28
|
+
/** Static assets copied to the build (laravel-vite-plugin's assets option) */
|
|
29
|
+
assets?: string[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default function pollora(options: PolloraOptions): PluginOption[];
|
|
33
|
+
export { pollora };
|
|
34
|
+
|
|
35
|
+
export function kebab(name: string): string;
|
|
36
|
+
export function blockEntries(root: string): Record<string, string>;
|
|
37
|
+
export function devServer(port: number): Record<string, unknown>;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { globSync } from 'glob';
|
|
4
|
+
import laravel, { refreshPaths } from 'laravel-vite-plugin';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Where each kind of Pollora package builds, relative to the project root, and
|
|
8
|
+
* how far its own root sits below the project's public directory.
|
|
9
|
+
*/
|
|
10
|
+
const TYPES = {
|
|
11
|
+
theme: {
|
|
12
|
+
// themes/<name>
|
|
13
|
+
publicDirectory: '../../public',
|
|
14
|
+
port: 5173,
|
|
15
|
+
reloadOn: ['.blade.php'],
|
|
16
|
+
assets: ['resources/assets/images/**', 'resources/assets/fonts/**'],
|
|
17
|
+
},
|
|
18
|
+
plugin: {
|
|
19
|
+
// public/content/plugins/<name>
|
|
20
|
+
publicDirectory: '../../../../public',
|
|
21
|
+
port: 5174,
|
|
22
|
+
reloadOn: ['.blade.php', '.php'],
|
|
23
|
+
assets: [],
|
|
24
|
+
},
|
|
25
|
+
module: {
|
|
26
|
+
// Modules/<Name>
|
|
27
|
+
publicDirectory: '../../public',
|
|
28
|
+
port: 5175,
|
|
29
|
+
reloadOn: ['.blade.php', '.php'],
|
|
30
|
+
assets: [],
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const BLOCK_ENTRIES = [
|
|
35
|
+
'./resources/views/blocks/*/{index,view}.{js,jsx,ts,tsx}',
|
|
36
|
+
'./resources/views/blocks/*/{editor,style}.css',
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const DEFAULT_INPUT = ['./resources/assets/app.js'];
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Turn a directory name into the slug the framework serves a module under:
|
|
43
|
+
* BlocksDemo → blocks-demo, as Str::kebab() does.
|
|
44
|
+
*/
|
|
45
|
+
export function kebab(name) {
|
|
46
|
+
return name
|
|
47
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
48
|
+
.replace(/[\s_]+/g, '-')
|
|
49
|
+
.toLowerCase();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Vite entries of every block script and stylesheet, keyed by path so blocks
|
|
54
|
+
* sharing a file name never overwrite each other.
|
|
55
|
+
*/
|
|
56
|
+
export function blockEntries(root) {
|
|
57
|
+
return globSync(BLOCK_ENTRIES, { cwd: root, posix: true })
|
|
58
|
+
.sort()
|
|
59
|
+
.reduce((entries, file) => {
|
|
60
|
+
entries[file.replace(/^\.\//, '').replace(/\.\w+$/, '')] = file;
|
|
61
|
+
return entries;
|
|
62
|
+
}, {});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function baseUrl() {
|
|
66
|
+
return process.env.APP_URL || process.env.DDEV_PRIMARY_URL || 'http://localhost';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function isDocker() {
|
|
70
|
+
return Boolean(process.env.IS_DOCKER || process.env.DOCKER_ENV || process.env.DDEV_PRIMARY_URL);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Dev server reachable from the site: inside DDEV or Docker it listens on every
|
|
75
|
+
* interface and announces the site's own host, elsewhere it serves localhost.
|
|
76
|
+
*/
|
|
77
|
+
export function devServer(port) {
|
|
78
|
+
const url = baseUrl();
|
|
79
|
+
const isHttps = url.startsWith('https');
|
|
80
|
+
const hostname = new URL(url).hostname;
|
|
81
|
+
const common = {
|
|
82
|
+
port,
|
|
83
|
+
strictPort: true,
|
|
84
|
+
cors: {
|
|
85
|
+
origin: '*',
|
|
86
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
|
87
|
+
credentials: true,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
if (isDocker()) {
|
|
92
|
+
return {
|
|
93
|
+
...common,
|
|
94
|
+
host: '0.0.0.0',
|
|
95
|
+
origin: `${url}:${port}`,
|
|
96
|
+
hmr: { protocol: isHttps ? 'wss' : 'ws', host: hostname },
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
...common,
|
|
102
|
+
https: isHttps,
|
|
103
|
+
host: isHttps ? hostname : 'localhost',
|
|
104
|
+
hmr: { protocol: isHttps ? 'wss' : 'ws', host: hostname },
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function resolvePort(option, fallback) {
|
|
109
|
+
const port = option ?? process.env.VITE_PORT;
|
|
110
|
+
|
|
111
|
+
return port === undefined || port === '' ? fallback : Number(port);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The Vite plugins a Pollora theme, plugin or module builds with.
|
|
116
|
+
*
|
|
117
|
+
* @param {import('./index').PolloraOptions} options
|
|
118
|
+
* @returns {import('vite').PluginOption[]}
|
|
119
|
+
*/
|
|
120
|
+
export default function pollora(options = {}) {
|
|
121
|
+
const type = options.type;
|
|
122
|
+
|
|
123
|
+
if (!TYPES[type]) {
|
|
124
|
+
throw new Error(`@pollora/vite-config: "type" must be one of ${Object.keys(TYPES).join(', ')}, got ${JSON.stringify(type)}.`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const defaults = TYPES[type];
|
|
128
|
+
const root = path.resolve(options.root ?? process.cwd());
|
|
129
|
+
const directoryName = path.basename(root);
|
|
130
|
+
const name = options.name ?? (type === 'module' ? kebab(directoryName) : directoryName);
|
|
131
|
+
// 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}`;
|
|
135
|
+
const port = resolvePort(options.port, defaults.port);
|
|
136
|
+
|
|
137
|
+
const blocks = options.blocks === false ? {} : blockEntries(root);
|
|
138
|
+
const hasBlocks = Object.keys(blocks).length > 0;
|
|
139
|
+
const input = (options.input ?? DEFAULT_INPUT.filter((file) => fs.existsSync(path.join(root, file))));
|
|
140
|
+
|
|
141
|
+
// File endings that reload the whole page in development (block themes add .html)
|
|
142
|
+
const reloadOn = options.reloadOn ?? defaults.reloadOn;
|
|
143
|
+
const refresh = [
|
|
144
|
+
// A literal resources/views/** turns every block JSX change into a full reload
|
|
145
|
+
...refreshPaths.filter((refreshPath) => refreshPath !== 'resources/views/**'),
|
|
146
|
+
'resources/views/**/*.blade.php',
|
|
147
|
+
...(reloadOn.includes('.php') ? ['app/**/*.php'] : []),
|
|
148
|
+
...(options.refresh ?? []),
|
|
149
|
+
];
|
|
150
|
+
|
|
151
|
+
const plugins = [
|
|
152
|
+
{
|
|
153
|
+
name: 'pollora:config',
|
|
154
|
+
config: () => ({
|
|
155
|
+
base,
|
|
156
|
+
build: { emptyOutDir: false },
|
|
157
|
+
server: devServer(port),
|
|
158
|
+
}),
|
|
159
|
+
},
|
|
160
|
+
];
|
|
161
|
+
|
|
162
|
+
if (options.tailwind !== false) {
|
|
163
|
+
plugins.push(import('@tailwindcss/vite').then((module) => module.default()));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
plugins.push(laravel({
|
|
167
|
+
input: [...input, ...Object.values(blocks)],
|
|
168
|
+
publicDirectory,
|
|
169
|
+
// Written from the working directory, unlike the build directory resolved from the root
|
|
170
|
+
hotFile: path.resolve(root, publicDirectory, `${name}.hot`),
|
|
171
|
+
buildDirectory,
|
|
172
|
+
refresh,
|
|
173
|
+
assets: options.assets ?? defaults.assets,
|
|
174
|
+
}));
|
|
175
|
+
|
|
176
|
+
if (type === 'theme' && options.themeJson !== false) {
|
|
177
|
+
plugins.push(import('@roots/vite-plugin').then(({ wordpressThemeJson }) => wordpressThemeJson({
|
|
178
|
+
baseThemeJsonPath: './theme.json',
|
|
179
|
+
...(options.themeJson ?? {}),
|
|
180
|
+
})));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (hasBlocks) {
|
|
184
|
+
plugins.push(import('@roots/vite-plugin').then(({ wordpressPlugin }) => wordpressPlugin(options.wordpress ?? {})));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
plugins.push({
|
|
188
|
+
name: 'pollora:blade-reload',
|
|
189
|
+
handleHotUpdate({ file, server }) {
|
|
190
|
+
if (reloadOn.some((extension) => file.endsWith(extension))) {
|
|
191
|
+
server.ws.send({ type: 'full-reload', path: '*' });
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
return plugins;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export { pollora };
|