@jahia/vite-plugin 0.5.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/src/index.ts ADDED
@@ -0,0 +1,220 @@
1
+ import multiEntry from "@rollup/plugin-multi-entry";
2
+ import { addExtension } from "@rollup/pluginutils";
3
+ import sharedLibs from "javascript-modules-engine/shared-libs.mjs";
4
+ import { extname } from "node:path";
5
+ import { styleText } from "node:util";
6
+ import type { Plugin } from "rollup";
7
+ import { globSync } from "tinyglobby";
8
+ import type { PluginOption } from "vite";
9
+ import { insertFilename } from "./insert-filename.js";
10
+
11
+ // These libraries are provided by Jahia and should not be bundled
12
+ const external = Object.keys(sharedLibs);
13
+
14
+ /** Plugin to execute a callback when a build succeeds. */
15
+ function buildSuccessPlugin(callback: () => void | Promise<void>): Plugin {
16
+ let succeeded = true;
17
+ return {
18
+ name: "build-success-callback",
19
+ buildEnd(error) {
20
+ succeeded = !error;
21
+ },
22
+ async closeBundle() {
23
+ if (succeeded) await callback();
24
+ },
25
+ };
26
+ }
27
+
28
+ export default function jahia(
29
+ options: {
30
+ /** Options for the client-side loader. */
31
+ client?: {
32
+ /** Entrypoint for the client-side bundle. */
33
+ input?: {
34
+ /**
35
+ * Parent directory of the client-side code.
36
+ *
37
+ * @default "./src/client/"
38
+ */
39
+ dir?: string;
40
+ /**
41
+ * Glob pattern(s) used to find all client-side code in `dir`.
42
+ *
43
+ * See [tinyglobby](https://www.npmjs.com/package/tinyglobby) for supported patterns.
44
+ *
45
+ * @default "**‍/*.jsx"
46
+ */
47
+ glob?: string | string[];
48
+ };
49
+ /**
50
+ * Where to put the client-side bundle. It is a directory that will have the same structure as
51
+ * the source directory.
52
+ *
53
+ * @default "./javascript/client/"
54
+ */
55
+ output?: string;
56
+ };
57
+
58
+ /** Options for the server-side bundle. */
59
+ server?: {
60
+ /**
61
+ * Entrypoint for the server-side bundle.
62
+ *
63
+ * [Glob patterns are
64
+ * supported.](https://www.npmjs.com/package/@rollup/plugin-multi-entry#supported-input-types)
65
+ *
66
+ * @default "./src/index.{js,ts}"
67
+ */
68
+ input?: string;
69
+ /** Where to put the built server-side bundle. */
70
+ output?: {
71
+ /**
72
+ * Directory where to put the built server-side bundle.
73
+ *
74
+ * @default "./javascript/server/"
75
+ */
76
+ dir?: string;
77
+ /**
78
+ * Base name for the built server-side bundle.
79
+ *
80
+ * Will be appended with '.js' for the JavaScript output and '.css' for the CSS output.
81
+ *
82
+ * @default "index"
83
+ */
84
+ fileName?: string;
85
+ };
86
+ };
87
+
88
+ /**
89
+ * Function to execute when the build is complete in watch mode. Can be used to automatically
90
+ * deploy your module to a local Jahia instance.
91
+ *
92
+ * @default undefined
93
+ */
94
+ watchCallback?: () => void | Promise<void>;
95
+ } = {},
96
+ ): PluginOption {
97
+ return {
98
+ name: "@jahia/vite-plugin",
99
+
100
+ /**
101
+ * Configuration hook.
102
+ *
103
+ * Updating the configuration can be done both by mutation or by merging. We use both methods to
104
+ * offer the best experience for the user.
105
+ *
106
+ * @see https://vite.dev/guide/api-plugin.html#config
107
+ */
108
+ config(config) {
109
+ // Mutate the configuration to set base settings if they are not already set
110
+ // Build all environments https://vite.dev/guide/api-environment-frameworks.html#environments-during-build
111
+ config.builder ??= {};
112
+
113
+ // Enable the modern JSX runtime
114
+ config.esbuild ??= { jsx: "automatic" };
115
+
116
+ return {
117
+ environments: {
118
+ client: {
119
+ build: {
120
+ lib: {
121
+ // Single entry point for the client, all other files must be imported in this one
122
+ entry: globSync(options.client?.input?.glob ?? "**/*.jsx", {
123
+ cwd: options.client?.input?.dir ?? "./src/client/",
124
+ absolute: true,
125
+ }),
126
+ formats: ["es"],
127
+ },
128
+ rollupOptions: {
129
+ output: {
130
+ dir: options.client?.output ?? "./javascript/client/",
131
+ entryFileNames: ({ facadeModuleId, name }) =>
132
+ facadeModuleId
133
+ ? // Keep the original extension, add .js after it
134
+ `${addExtension(name, extname(facadeModuleId))}.js`
135
+ : addExtension(name),
136
+ preserveModules: true,
137
+ preserveModulesRoot: options.client?.input?.dir ?? "./src/client/",
138
+ },
139
+ external,
140
+ plugins: [
141
+ {
142
+ name: "forbid-library",
143
+ resolveId(id) {
144
+ this.debug(id);
145
+ console.log(id);
146
+ if (id === "@jahia/javascript-modules-library") {
147
+ throw new Error(
148
+ `You cannot import '@jahia/javascript-modules-library' in the client bundle`,
149
+ );
150
+ }
151
+ },
152
+ },
153
+ ],
154
+ },
155
+ },
156
+ },
157
+ ssr: {
158
+ build: {
159
+ lib: {
160
+ /**
161
+ * Necessary for IIFE format but not used; it's the name given to the global
162
+ * variable that will be created by the IIFE.
163
+ */
164
+ name: "serverBundle",
165
+ entry: options.server?.input ?? "./src/index.{js,ts}",
166
+ fileName: options.server?.output?.fileName ?? "index",
167
+ // Bundle the old way, as an IIFE, to replace libs with globals
168
+ formats: ["iife"],
169
+ },
170
+ rollupOptions: {
171
+ output: {
172
+ dir: options.server?.output?.dir ?? "./javascript/server/",
173
+ // Replace the imports of external libraries with the globals
174
+ globals: Object.fromEntries(
175
+ [
176
+ ...external,
177
+ // This is only available on the server, attempting to import it
178
+ // on the client will throw an error
179
+ "@jahia/javascript-modules-library",
180
+ ].map((lib) => [
181
+ lib,
182
+ // This is how a shared library is imported in the server bundle
183
+ `javascriptModulesLibraryBuilder.getSharedLibrary(${JSON.stringify(lib)})`,
184
+ ]),
185
+ ),
186
+ },
187
+ external: [...external, "@jahia/javascript-modules-library"],
188
+ plugins: [
189
+ multiEntry({
190
+ exports: false,
191
+ entryFileName: `${options.server?.output?.fileName ?? "index"}.js`,
192
+ }),
193
+ // Only add the callback plugin in watch mode
194
+ config.build?.watch &&
195
+ options.watchCallback &&
196
+ buildSuccessPlugin(options.watchCallback),
197
+ // Insert filenames in client-side components
198
+ insertFilename(
199
+ options.client?.input?.dir ?? "./src/client/",
200
+ options.client?.output ?? "./javascript/client/",
201
+ ),
202
+ ],
203
+ },
204
+ },
205
+ },
206
+ },
207
+ };
208
+ },
209
+
210
+ // Needed to run before Vite's default resolver
211
+ enforce: "pre",
212
+ resolveId(id, importer) {
213
+ if (this.environment.name === "client" && id === "@jahia/javascript-modules-library") {
214
+ this.error(
215
+ `\n\tCannot import @jahia/javascript-modules-library in the client bundle\n\tin ${importer}\n\t${styleText("bgRedBright", "This module is only available on the server.")}`,
216
+ );
217
+ }
218
+ },
219
+ };
220
+ }
@@ -0,0 +1,105 @@
1
+ import { print } from "esrap";
2
+ import type { Node } from "estree";
3
+ import { Plugin } from "rollup";
4
+ import { walk } from "zimmerframe";
5
+ import { createFilter } from "@rollup/pluginutils";
6
+ import path from "path";
7
+
8
+ /**
9
+ * This plugin adds a `__filename` property to all default exports.
10
+ *
11
+ * ```js
12
+ * export default function myFunction() {
13
+ * console.log(myFunction.__filename);
14
+ * }
15
+ * ```
16
+ *
17
+ * Becomes
18
+ *
19
+ * ```js
20
+ * export default Object.defineProperty(
21
+ * function myFunction() {
22
+ * console.log(myFunction.__filename);
23
+ * },
24
+ * "__filename",
25
+ * {
26
+ * value: "path/to/file.js",
27
+ * enumerable: false,
28
+ * },
29
+ * );
30
+ * ```
31
+ *
32
+ * @param root The root of the transformation. Files outside this directory will not be transformed,
33
+ * files inside will have their inserted path relative to this directory.
34
+ */
35
+ export const insertFilename = (root: string, prefix: string): Plugin => {
36
+ const filter = createFilter(null, null, {
37
+ resolve: root,
38
+ });
39
+ return {
40
+ name: "insert-path",
41
+
42
+ transform(code, id) {
43
+ if (!filter(id)) return;
44
+ const ast = walk(this.parse(code) as Node, null, {
45
+ // Only target `export default function`
46
+ ExportDefaultDeclaration(node) {
47
+ if (node.declaration.type !== "FunctionDeclaration") return;
48
+ return {
49
+ // export default
50
+ type: "ExportDefaultDeclaration",
51
+ leadingComments: node.leadingComments,
52
+ trailingComments: node.trailingComments,
53
+ range: node.range,
54
+ loc: node.loc,
55
+ declaration: {
56
+ // Object.defineProperty(...)
57
+ type: "CallExpression",
58
+ optional: false,
59
+ callee: {
60
+ type: "MemberExpression",
61
+ computed: false,
62
+ optional: false,
63
+ object: { type: "Identifier", name: "Object" },
64
+ property: { type: "Identifier", name: "defineProperty" },
65
+ },
66
+ arguments: [
67
+ {
68
+ // Original function
69
+ ...node.declaration,
70
+ type: "FunctionExpression",
71
+ },
72
+ { type: "Literal", value: "__filename" },
73
+ {
74
+ // { value: id, enumerable: false }
75
+ type: "ObjectExpression",
76
+ properties: [
77
+ {
78
+ type: "Property",
79
+ computed: false,
80
+ kind: "init",
81
+ method: false,
82
+ shorthand: false,
83
+ key: { type: "Identifier", name: "value" },
84
+ value: { type: "Literal", value: prefix + path.relative(root, id) },
85
+ },
86
+ {
87
+ type: "Property",
88
+ computed: false,
89
+ kind: "init",
90
+ method: false,
91
+ shorthand: false,
92
+ key: { type: "Identifier", name: "enumerable" },
93
+ value: { type: "Literal", value: false },
94
+ },
95
+ ],
96
+ },
97
+ ],
98
+ },
99
+ };
100
+ },
101
+ });
102
+ return print(ast);
103
+ },
104
+ };
105
+ };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @module
3
+ *
4
+ * Updates the package.json version, used during the maven release process.
5
+ *
6
+ * Usage: node sync-version.js 1.2.3
7
+ *
8
+ * @see {@link ./pom.xml}
9
+ */
10
+
11
+ import fs from "node:fs";
12
+
13
+ const updated = fs
14
+ .readFileSync("package.json", "utf8")
15
+ .replace(/"version": ".+"/, `"version": ${JSON.stringify(process.argv[2])}`);
16
+ fs.writeFileSync("package.json", updated);