@lilaquadrat/design-core 0.2.1 → 0.3.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/README.md +76 -3
- package/html/index.server.html +1 -8
- package/package.json +54 -54
- package/src/client-entry.ts +8 -8
- package/src/components/partials/error.partial.vue +19 -19
- package/src/components/partials/main-components.partial.vue +75 -70
- package/src/components/partials/qrcode.partial.vue +8 -8
- package/src/functions/AuthProviderFactory.ts +30 -0
- package/src/functions/PaymenyProviderFactory.ts +11 -11
- package/src/functions/auth0.provider.ts +75 -0
- package/src/functions/keycloak.provider.ts +228 -0
- package/src/functions/lila-dom.ts +50 -50
- package/src/functions/shopify.provider.ts +176 -154
- package/src/functions/stripe.provider.ts +120 -108
- package/src/globals.d.ts +1 -2
- package/src/index.ts +9 -7
- package/src/interfaces/AuthCallbackResult.interface.ts +5 -0
- package/src/interfaces/AuthConfig.interface.ts +13 -0
- package/src/interfaces/AuthProvider.interface.ts +15 -0
- package/src/interfaces/FrontendConfig.interface.ts +11 -40
- package/src/interfaces/GenericEvents.interface.ts +1 -1
- package/src/interfaces/IdTokenExtended.interface.ts +13 -4
- package/src/interfaces/PaymentProvider.interface.ts +2 -2
- package/src/interfaces/RenderOptions.interface.ts +12 -0
- package/src/libs/ActionNotice.ts +125 -125
- package/src/libs/Models.class.ts +219 -221
- package/src/main.ts +41 -36
- package/src/mixins/createCookieString.ts +50 -36
- package/src/mixins/createModelDeclaration.ts +22 -19
- package/src/mixins/createRouter.ts +12 -12
- package/src/mixins/date.ts +4 -2
- package/src/mixins/formatSize.ts +5 -5
- package/src/mixins/getAnchor.ts +1 -1
- package/src/mixins/getRoutes.ts +13 -25
- package/src/mixins/hasSlotContent.ts +22 -16
- package/src/mixins/hooks.ts +101 -60
- package/src/mixins/loadComponents.ts +60 -58
- package/src/mixins/logger.ts +17 -13
- package/src/mixins/replaceVariables.ts +10 -8
- package/src/mixins/scroll.ts +61 -45
- package/src/models/Address.model.ts +7 -7
- package/src/models/Contact.model.ts +14 -14
- package/src/plugins/analytics.ts +198 -0
- package/src/plugins/auth.ts +74 -60
- package/src/plugins/currency.ts +10 -10
- package/src/plugins/events.ts +101 -97
- package/src/plugins/filters.ts +21 -18
- package/src/plugins/replacer.ts +7 -6
- package/src/plugins/signupFlow.ts +45 -43
- package/src/plugins/traceable.ts +28 -26
- package/src/plugins/translations.ts +9 -9
- package/src/plugins/youtube.ts +39 -34
- package/src/routes.ts +108 -108
- package/src/server-entry.ts +75 -77
- package/src/stores/calls.store.ts +14 -14
- package/src/stores/cart.store.ts +116 -107
- package/src/stores/content.store.ts +87 -45
- package/src/stores/editor.store.ts +16 -16
- package/src/stores/files.store.ts +72 -72
- package/src/stores/main.store.ts +155 -109
- package/src/stores/user.store.ts +72 -68
- package/src/translations/de.ts +127 -127
- package/src/views/content.view.vue +81 -143
- package/src/views/download.view.vue +25 -23
- package/src/views/editor.view.vue +150 -125
- package/src/views/login.view.vue +35 -36
- package/src/views/signup-account.view.vue +14 -14
- package/tooling/cypress/config.ts +68 -54
- package/tooling/cypress/manifest-utils.mjs +34 -22
- package/tooling/cypress/run-parallel.mjs +41 -35
- package/tooling/cypress/support/commands.ts +458 -300
- package/tooling/eslint.config.js +1 -223
- package/tooling/preview.plugin.js +132 -0
- package/tooling/ssr-test/index.mjs +205 -203
- package/tooling/vite.d.ts +36 -0
- package/tooling/vite.js +234 -0
- package/src/interfaces/EditorConfiguration.interface.ts +0 -15
- package/tooling/preview.plugin.ts +0 -134
- package/tooling/stylelint.config.mjs +0 -24
- package/tooling/vite.ts +0 -260
package/tooling/vite.js
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { fileURLToPath, URL } from 'node:url';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
|
|
5
|
+
import { defineConfig } from 'vite';
|
|
6
|
+
import vue from '@vitejs/plugin-vue';
|
|
7
|
+
|
|
8
|
+
import { visualizer } from 'rollup-plugin-visualizer';
|
|
9
|
+
|
|
10
|
+
import previewBundle, { dropPreviewAssets, previewBuildOptions } from './preview.plugin.js';
|
|
11
|
+
|
|
12
|
+
function resolveTarget(mode) {
|
|
13
|
+
|
|
14
|
+
if(mode === 'production') return 'live';
|
|
15
|
+
if(mode === 'next') return 'next';
|
|
16
|
+
|
|
17
|
+
return 'local';
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* the html templates the ssr build emits alongside the bundle. a project may
|
|
23
|
+
* override either by keeping a file of the same name in its root, otherwise the
|
|
24
|
+
* package template is used.
|
|
25
|
+
*/
|
|
26
|
+
function resolveTemplate(root, name) {
|
|
27
|
+
|
|
28
|
+
const projectTemplate = resolve(root, name);
|
|
29
|
+
|
|
30
|
+
if(existsSync(projectTemplate)) return projectTemplate;
|
|
31
|
+
|
|
32
|
+
return fileURLToPath(new URL(`../html/${name}`, import.meta.url));
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function createViteConfig(options) {
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* absolute on purpose: the globalVars below are prepended to every less file,
|
|
40
|
+
* including the ones inside the package, where a project relative path would
|
|
41
|
+
* resolve against node_modules
|
|
42
|
+
*/
|
|
43
|
+
const lessDir = resolve(options.root, options.lessDir ?? './src/assets/less');
|
|
44
|
+
const ssrEntry = options.ssrEntry ?? '/src/server-entry.ts';
|
|
45
|
+
const ssrFixturesEntry = options.ssrFixturesEntry ?? '/src/ssr-test.fixtures.ts';
|
|
46
|
+
|
|
47
|
+
return defineConfig((settings) => {
|
|
48
|
+
|
|
49
|
+
const target = resolveTarget(settings.mode);
|
|
50
|
+
const isProduction = target === 'live';
|
|
51
|
+
/**
|
|
52
|
+
* shareable static module gallery: preview routes, hash history, no auth and
|
|
53
|
+
* inlined assets, so the output runs from file:// without a server
|
|
54
|
+
*/
|
|
55
|
+
const isPreview = settings.mode === 'preview';
|
|
56
|
+
/**
|
|
57
|
+
* a second ssr bundle holding nothing but the design's fixtures, so the ssr
|
|
58
|
+
* preflight can read viewData and the registries while still rendering
|
|
59
|
+
* through the real dist/server build
|
|
60
|
+
*/
|
|
61
|
+
const isSsrTest = settings.mode === 'ssr-test';
|
|
62
|
+
/**
|
|
63
|
+
* builds meant to be handed out rather than debugged: minified, no
|
|
64
|
+
* sourcemaps, no vue dev instrumentation
|
|
65
|
+
*/
|
|
66
|
+
const isOptimized = isProduction || isPreview;
|
|
67
|
+
// const config = options.config[target];
|
|
68
|
+
const viteConfig = {
|
|
69
|
+
plugins: [
|
|
70
|
+
vue(),
|
|
71
|
+
visualizer(),
|
|
72
|
+
...isPreview ? [previewBundle()] : [dropPreviewAssets()]
|
|
73
|
+
],
|
|
74
|
+
base: './',
|
|
75
|
+
server: {
|
|
76
|
+
host: '0.0.0.0',
|
|
77
|
+
},
|
|
78
|
+
optimizeDeps: {
|
|
79
|
+
// design-core ships source, and its less needs the project variables
|
|
80
|
+
// injected below - a prebundle would not see them.
|
|
81
|
+
//
|
|
82
|
+
// @lilaquadrat/frontend rides along because design-core imports it:
|
|
83
|
+
// prebundling it there and serving it raw here would give the resize and
|
|
84
|
+
// inview singletons two module identities, and a second scroll listener
|
|
85
|
+
// with it
|
|
86
|
+
exclude: ['@lilaquadrat/design-core', '@lilaquadrat/frontend']
|
|
87
|
+
},
|
|
88
|
+
build: {
|
|
89
|
+
cssCodeSplit: false,
|
|
90
|
+
cssMinify: isOptimized,
|
|
91
|
+
sourcemap: !isOptimized,
|
|
92
|
+
minify: isOptimized,
|
|
93
|
+
rolldownOptions: {
|
|
94
|
+
output: {
|
|
95
|
+
dir: 'dist/app',
|
|
96
|
+
// rolldown chunking: only auth0 and qrcode get their own files,
|
|
97
|
+
// every other dependency stays in the entry. minSize 0 forces a
|
|
98
|
+
// group to be captured regardless of size; the global minSize keeps
|
|
99
|
+
// automatic grouping from emitting hundreds of tiny chunks.
|
|
100
|
+
codeSplitting: {
|
|
101
|
+
minSize: 30_000,
|
|
102
|
+
groups: [
|
|
103
|
+
{ name: 'auth0', test: /[\\/]node_modules[\\/]@auth0[\\/]/, minSize: 0 },
|
|
104
|
+
{ name: 'qrcode', test: /[\\/]node_modules[\\/]qrcode[\\/]/, minSize: 0 },
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
assetFileNames: (assetInfo) => {
|
|
108
|
+
|
|
109
|
+
if (assetInfo.name?.endsWith('woff') || assetInfo.name?.endsWith('png')) {
|
|
110
|
+
|
|
111
|
+
return '[name][extname]';
|
|
112
|
+
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return '[name]-[hash][extname]';
|
|
116
|
+
|
|
117
|
+
},
|
|
118
|
+
chunkFileNames: '[name]-[hash].js',
|
|
119
|
+
entryFileNames: '[name]-[hash].js',
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
css: {
|
|
124
|
+
devSourcemap: true,
|
|
125
|
+
preprocessorOptions: {
|
|
126
|
+
less: {
|
|
127
|
+
sourceMap: true,
|
|
128
|
+
globalVars: {
|
|
129
|
+
globalVariables: `true; @import (reference) "${lessDir}/variables.less";`,
|
|
130
|
+
globalMixins: `true; @import (reference) "${lessDir}/mixins.less";`,
|
|
131
|
+
globalFonts: `true; @import (reference) "${lessDir}/fonts.less";`,
|
|
132
|
+
},
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
resolve: {
|
|
137
|
+
alias: {
|
|
138
|
+
'~fonts': resolve(options.root, 'src/assets/fonts'),
|
|
139
|
+
'@': resolve(options.root, 'src'),
|
|
140
|
+
},
|
|
141
|
+
/**
|
|
142
|
+
* a linked @lilaquadrat/design-core resolves these from its own
|
|
143
|
+
* node_modules, which would give the app a second vue and a second
|
|
144
|
+
* pinia - one app instance registering into a store nobody reads.
|
|
145
|
+
* dedupe pins every shared runtime to the project copy.
|
|
146
|
+
*/
|
|
147
|
+
dedupe: [
|
|
148
|
+
'vue',
|
|
149
|
+
'vue-router',
|
|
150
|
+
'vue-i18n',
|
|
151
|
+
'pinia',
|
|
152
|
+
// holds a static request cache, so a second copy would cache twice
|
|
153
|
+
'@lilaquadrat/sdk',
|
|
154
|
+
// resize and inview are singletons: a second copy means a second
|
|
155
|
+
// scroll listener and a second set of refs nobody reads
|
|
156
|
+
'@lilaquadrat/frontend',
|
|
157
|
+
'@auth0/auth0-spa-js',
|
|
158
|
+
'axios',
|
|
159
|
+
'dayjs',
|
|
160
|
+
],
|
|
161
|
+
/**
|
|
162
|
+
* @lilaquadrat/studio is deliberately NOT deduped: it is the backend
|
|
163
|
+
* package and a project may still hold a copy for other reasons, while
|
|
164
|
+
* a second one costs nothing here.
|
|
165
|
+
*
|
|
166
|
+
* @lilaquadrat/interfaces is types only, so it has nothing to dedupe.
|
|
167
|
+
*/
|
|
168
|
+
},
|
|
169
|
+
define: {
|
|
170
|
+
// '__FRONTEND_CONFIG__' : JSON.stringify(config),
|
|
171
|
+
'__TARGET__': JSON.stringify(target),
|
|
172
|
+
'__PREVIEW__': JSON.stringify(isPreview),
|
|
173
|
+
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: isOptimized ? 'false' : 'true',
|
|
174
|
+
__VUE_PROD_DEVTOOLS__: isOptimized ? 'false' : 'true',
|
|
175
|
+
...options.define
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
if (isPreview) {
|
|
180
|
+
|
|
181
|
+
viteConfig.build = previewBuildOptions(viteConfig.build);
|
|
182
|
+
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (settings.isSsrBuild) {
|
|
186
|
+
|
|
187
|
+
viteConfig.build = {
|
|
188
|
+
...viteConfig.build,
|
|
189
|
+
rolldownOptions: {
|
|
190
|
+
input: isSsrTest ? ssrFixturesEntry : ssrEntry,
|
|
191
|
+
plugins: isSsrTest
|
|
192
|
+
? []
|
|
193
|
+
: [
|
|
194
|
+
{
|
|
195
|
+
name: 'emit-html-templates',
|
|
196
|
+
async generateBundle() {
|
|
197
|
+
|
|
198
|
+
const { readFile } = await import('node:fs/promises');
|
|
199
|
+
const [mailHtml, serverHtml] = await Promise.all([
|
|
200
|
+
readFile(resolveTemplate(options.root, 'index.mail.html'), 'utf-8'),
|
|
201
|
+
readFile(resolveTemplate(options.root, 'index.server.html'), 'utf-8'),
|
|
202
|
+
]);
|
|
203
|
+
|
|
204
|
+
this.emitFile({ type: 'asset', fileName: 'index.mail.html', source: mailHtml });
|
|
205
|
+
this.emitFile({ type: 'asset', fileName: 'index.server.html', source: serverHtml });
|
|
206
|
+
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
],
|
|
210
|
+
output: {
|
|
211
|
+
...viteConfig.build?.rolldownOptions?.output,
|
|
212
|
+
codeSplitting: false,
|
|
213
|
+
dir: isSsrTest ? 'dist/ssr-test' : 'dist/server',
|
|
214
|
+
entryFileNames: '[name].js',
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
ssrManifest: !isSsrTest,
|
|
218
|
+
}
|
|
219
|
+
viteConfig.ssr = {
|
|
220
|
+
target: 'webworker',
|
|
221
|
+
noExternal: true,
|
|
222
|
+
external: ['node:stream', 'http', 'https', 'crypto', 'path', 'highlight.js'],
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return viteConfig;
|
|
228
|
+
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export default createViteConfig;
|
|
234
|
+
export { previewBundle, dropPreviewAssets, previewBuildOptions };
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export interface EditorTitleDescription {
|
|
2
|
-
short?: string
|
|
3
|
-
full?: string
|
|
4
|
-
}
|
|
5
|
-
export default interface EditorConfiguration {
|
|
6
|
-
|
|
7
|
-
editorUrl?: string
|
|
8
|
-
breakpointTablet?: string
|
|
9
|
-
breakpointDesktop?: string
|
|
10
|
-
breakpointWide?: string
|
|
11
|
-
preloadImages?: boolean
|
|
12
|
-
title?: EditorTitleDescription
|
|
13
|
-
description?: EditorTitleDescription
|
|
14
|
-
|
|
15
|
-
}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import type { Plugin, UserConfig } from 'vite';
|
|
2
|
-
|
|
3
|
-
const OUTPUT_DIR = 'dist/preview';
|
|
4
|
-
const PREVIEW_ASSET_DIR = 'previewAssets';
|
|
5
|
-
|
|
6
|
-
function escapeRegExp (input: string) {
|
|
7
|
-
|
|
8
|
-
return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* drops the gallery fixture images from every build that is not the preview.
|
|
14
|
-
*
|
|
15
|
-
* the viewData fixtures import them statically, and vite emits an imported asset
|
|
16
|
-
* while transforming - so even though rolldown tree shakes preview.view.vue out
|
|
17
|
-
* of the app bundle, the images survive as orphans nobody references.
|
|
18
|
-
*/
|
|
19
|
-
export function dropPreviewAssets (): Plugin {
|
|
20
|
-
|
|
21
|
-
return {
|
|
22
|
-
name : 'drop-preview-assets',
|
|
23
|
-
enforce: 'post',
|
|
24
|
-
apply : 'build',
|
|
25
|
-
generateBundle (_options, bundle: Record<string, any>) {
|
|
26
|
-
|
|
27
|
-
Object.keys(bundle).forEach((fileName) => {
|
|
28
|
-
|
|
29
|
-
const single = bundle[fileName];
|
|
30
|
-
|
|
31
|
-
if(single.type !== 'asset') return;
|
|
32
|
-
|
|
33
|
-
const origins: string[] = [single.originalFileName, ...single.originalFileNames ?? []].filter(Boolean);
|
|
34
|
-
|
|
35
|
-
if(origins.some((origin) => origin.includes(PREVIEW_ASSET_DIR))) delete bundle[fileName];
|
|
36
|
-
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* build overrides for the shareable static gallery (yarn build:preview).
|
|
46
|
-
*
|
|
47
|
-
* everything here exists because the output is opened straight from disk, where
|
|
48
|
-
* each file is its own opaque origin.
|
|
49
|
-
*/
|
|
50
|
-
export function previewBuildOptions (base: UserConfig['build']): UserConfig['build'] {
|
|
51
|
-
|
|
52
|
-
return {
|
|
53
|
-
...base,
|
|
54
|
-
/**
|
|
55
|
-
* inline fonts and images as data URIs: browsers block the font fetches a
|
|
56
|
-
* separate .woff would need
|
|
57
|
-
*/
|
|
58
|
-
assetsInlineLimit: 512 * 1024,
|
|
59
|
-
rolldownOptions : {
|
|
60
|
-
...base?.rolldownOptions,
|
|
61
|
-
output: {
|
|
62
|
-
...base?.rolldownOptions?.output,
|
|
63
|
-
// a single classic script: file:// blocks `type="module"` as cross origin
|
|
64
|
-
dir : OUTPUT_DIR,
|
|
65
|
-
format : 'iife',
|
|
66
|
-
codeSplitting : false,
|
|
67
|
-
entryFileNames: '[name].js',
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* folds the script and the stylesheet into index.html, so the preview is a self
|
|
76
|
-
* contained file that opens over file:// with no server.
|
|
77
|
-
*/
|
|
78
|
-
export default function previewBundle (): Plugin {
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
name : 'preview-bundle',
|
|
82
|
-
enforce: 'post',
|
|
83
|
-
apply : 'build',
|
|
84
|
-
generateBundle (_options, bundle: Record<string, any>) {
|
|
85
|
-
|
|
86
|
-
const html = bundle['index.html'];
|
|
87
|
-
|
|
88
|
-
if(!html) return;
|
|
89
|
-
|
|
90
|
-
let source = html.source.toString();
|
|
91
|
-
let script = '';
|
|
92
|
-
|
|
93
|
-
Object.keys(bundle).forEach((fileName) => {
|
|
94
|
-
|
|
95
|
-
const single = bundle[fileName];
|
|
96
|
-
|
|
97
|
-
if(fileName === 'index.html') return;
|
|
98
|
-
|
|
99
|
-
if(single.type === 'chunk') {
|
|
100
|
-
|
|
101
|
-
// a literal </script> inside the code would end the tag early
|
|
102
|
-
script += single.code.replace(/<\/script>/gi, '<\\/script>');
|
|
103
|
-
source = source.replace(new RegExp(`<script[^>]*src="[^"]*${escapeRegExp(fileName)}"[^>]*></script>\\s*`), '');
|
|
104
|
-
delete bundle[fileName];
|
|
105
|
-
return;
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if(fileName.endsWith('.css')) {
|
|
110
|
-
|
|
111
|
-
// replacer functions only: a replacement string would expand $& and
|
|
112
|
-
// $\` in the asset as substitution patterns
|
|
113
|
-
source = source.replace(new RegExp(`<link[^>]*href="[^"]*${escapeRegExp(fileName)}"[^>]*>`), () => `<style>${single.source}</style>`);
|
|
114
|
-
delete bundle[fileName];
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
source = source.replace(/<link[^>]*rel="modulepreload"[^>]*>\s*/g, '');
|
|
121
|
-
// the manifest is the one head asset a file:// origin cannot fetch
|
|
122
|
-
source = source.replace(/<link[^>]*rel="manifest"[^>]*>\s*/g, '');
|
|
123
|
-
Object.keys(bundle).filter((fileName) => fileName.endsWith('.webmanifest')).forEach((fileName) => delete bundle[fileName]);
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* at the end of the body, not in place: an inline script has no `defer`,
|
|
127
|
-
* so in the head it would run before #app exists
|
|
128
|
-
*/
|
|
129
|
-
html.source = source.replace('</body>', () => `<script>${script}</script>\n</body>`);
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/** @type {import('stylelint').Config} */
|
|
2
|
-
export default {
|
|
3
|
-
'extends': [
|
|
4
|
-
'stylelint-config-html',
|
|
5
|
-
'stylelint-config-recommended-vue'
|
|
6
|
-
],
|
|
7
|
-
'plugins': [
|
|
8
|
-
'stylelint-order'
|
|
9
|
-
],
|
|
10
|
-
'overrides': [
|
|
11
|
-
{
|
|
12
|
-
'files' : ['*.vue', '**/*.vue'],
|
|
13
|
-
'customSyntax': 'postcss-html'
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
'files' : ['*.less', '**/*.less'],
|
|
17
|
-
'customSyntax': 'postcss-less'
|
|
18
|
-
}
|
|
19
|
-
],
|
|
20
|
-
'rules': {
|
|
21
|
-
'media-query-no-invalid' : null,
|
|
22
|
-
'declaration-property-value-no-unknown': null
|
|
23
|
-
}
|
|
24
|
-
}
|
package/tooling/vite.ts
DELETED
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
import { fileURLToPath, URL } from 'node:url';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
|
-
import { resolve } from 'node:path';
|
|
4
|
-
|
|
5
|
-
import { defineConfig, type UserConfig } from 'vite';
|
|
6
|
-
import vue from '@vitejs/plugin-vue';
|
|
7
|
-
|
|
8
|
-
import { visualizer } from 'rollup-plugin-visualizer';
|
|
9
|
-
|
|
10
|
-
import previewBundle, { dropPreviewAssets, previewBuildOptions } from './preview.plugin.ts';
|
|
11
|
-
|
|
12
|
-
export type Target = 'local' | 'next' | 'live';
|
|
13
|
-
|
|
14
|
-
export interface ViteFactoryOptions {
|
|
15
|
-
/**
|
|
16
|
-
* the project config keyed by target, as exported from its own config.ts.
|
|
17
|
-
* it is only serialised into __FRONTEND_CONFIG__, so its shape is the
|
|
18
|
-
* project's business
|
|
19
|
-
*/
|
|
20
|
-
config: Record<Target, unknown>
|
|
21
|
-
/**
|
|
22
|
-
* absolute path to the project root (the folder holding index.html)
|
|
23
|
-
*/
|
|
24
|
-
root: string
|
|
25
|
-
/**
|
|
26
|
-
* project relative path to the less folder holding variables, mixins and
|
|
27
|
-
* fonts - these are the design and never ship with the package
|
|
28
|
-
*/
|
|
29
|
-
lessDir?: string
|
|
30
|
-
/**
|
|
31
|
-
* project relative entry for the ssr build
|
|
32
|
-
*/
|
|
33
|
-
ssrEntry?: string
|
|
34
|
-
/**
|
|
35
|
-
* project relative entry for the ssr preflight fixtures (mode ssr-test).
|
|
36
|
-
* it exports the design's viewData and module registries so the test suite
|
|
37
|
-
* can read them without a bundler of its own
|
|
38
|
-
*/
|
|
39
|
-
ssrFixturesEntry?: string
|
|
40
|
-
/**
|
|
41
|
-
* additional defines merged over the framework ones
|
|
42
|
-
*/
|
|
43
|
-
define?: Record<string, string>
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function resolveTarget (mode: string): Target {
|
|
47
|
-
|
|
48
|
-
if(mode === 'production') return 'live';
|
|
49
|
-
if(mode === 'next') return 'next';
|
|
50
|
-
|
|
51
|
-
return 'local';
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* the html templates the ssr build emits alongside the bundle. a project may
|
|
57
|
-
* override either by keeping a file of the same name in its root, otherwise the
|
|
58
|
-
* package template is used.
|
|
59
|
-
*/
|
|
60
|
-
function resolveTemplate (root: string, name: string) {
|
|
61
|
-
|
|
62
|
-
const projectTemplate = resolve(root, name);
|
|
63
|
-
|
|
64
|
-
if(existsSync(projectTemplate)) return projectTemplate;
|
|
65
|
-
|
|
66
|
-
return fileURLToPath(new URL(`../html/${name}`, import.meta.url));
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export function createViteConfig (options: ViteFactoryOptions) {
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* absolute on purpose: the globalVars below are prepended to every less file,
|
|
74
|
-
* including the ones inside the package, where a project relative path would
|
|
75
|
-
* resolve against node_modules
|
|
76
|
-
*/
|
|
77
|
-
const lessDir = resolve(options.root, options.lessDir ?? './src/assets/less');
|
|
78
|
-
const ssrEntry = options.ssrEntry ?? '/src/server-entry.ts';
|
|
79
|
-
const ssrFixturesEntry = options.ssrFixturesEntry ?? '/src/ssr-test.fixtures.ts';
|
|
80
|
-
|
|
81
|
-
return defineConfig((settings): UserConfig => {
|
|
82
|
-
|
|
83
|
-
const target = resolveTarget(settings.mode);
|
|
84
|
-
const isProduction = target === 'live';
|
|
85
|
-
/**
|
|
86
|
-
* shareable static module gallery: preview routes, hash history, no auth and
|
|
87
|
-
* inlined assets, so the output runs from file:// without a server
|
|
88
|
-
*/
|
|
89
|
-
const isPreview = settings.mode === 'preview';
|
|
90
|
-
/**
|
|
91
|
-
* a second ssr bundle holding nothing but the design's fixtures, so the ssr
|
|
92
|
-
* preflight can read viewData and the registries while still rendering
|
|
93
|
-
* through the real dist/server build
|
|
94
|
-
*/
|
|
95
|
-
const isSsrTest = settings.mode === 'ssr-test';
|
|
96
|
-
/**
|
|
97
|
-
* builds meant to be handed out rather than debugged: minified, no
|
|
98
|
-
* sourcemaps, no vue dev instrumentation
|
|
99
|
-
*/
|
|
100
|
-
const isOptimized = isProduction || isPreview;
|
|
101
|
-
const config = options.config[target];
|
|
102
|
-
const viteConfig: UserConfig = {
|
|
103
|
-
plugins: [
|
|
104
|
-
vue(),
|
|
105
|
-
visualizer(),
|
|
106
|
-
...isPreview ? [previewBundle()] : [dropPreviewAssets()]
|
|
107
|
-
],
|
|
108
|
-
base : './',
|
|
109
|
-
server: {
|
|
110
|
-
host: '0.0.0.0',
|
|
111
|
-
},
|
|
112
|
-
optimizeDeps: {
|
|
113
|
-
// design-core ships source, and its less needs the project variables
|
|
114
|
-
// injected below - a prebundle would not see them.
|
|
115
|
-
//
|
|
116
|
-
// @lilaquadrat/frontend rides along because design-core imports it:
|
|
117
|
-
// prebundling it there and serving it raw here would give the resize and
|
|
118
|
-
// inview singletons two module identities, and a second scroll listener
|
|
119
|
-
// with it
|
|
120
|
-
exclude: ['@lilaquadrat/design-core', '@lilaquadrat/frontend']
|
|
121
|
-
},
|
|
122
|
-
build: {
|
|
123
|
-
cssCodeSplit : false,
|
|
124
|
-
cssMinify : isOptimized,
|
|
125
|
-
sourcemap : !isOptimized,
|
|
126
|
-
minify : isOptimized,
|
|
127
|
-
rolldownOptions: {
|
|
128
|
-
output: {
|
|
129
|
-
dir : 'dist/app',
|
|
130
|
-
// rolldown manual chunking: split deps into a vendor chunk, but
|
|
131
|
-
// never emit a chunk smaller than minSize - small groups fall back
|
|
132
|
-
// into the entry instead of producing hundreds of tiny files.
|
|
133
|
-
codeSplitting: {
|
|
134
|
-
minSize: 30_000,
|
|
135
|
-
groups : [
|
|
136
|
-
{ name: 'qrcode', test: /[\\/]node_modules[\\/]qrcode[\\/]/, minSize: 0 },
|
|
137
|
-
{ name: 'vendor', test: /[\\/]node_modules[\\/]/ },
|
|
138
|
-
],
|
|
139
|
-
},
|
|
140
|
-
assetFileNames: (assetInfo: { name?: string }) => {
|
|
141
|
-
if (assetInfo.name?.endsWith('woff') || assetInfo.name?.endsWith('png')) {
|
|
142
|
-
return '[name][extname]';
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return '[name]-[hash][extname]';
|
|
146
|
-
},
|
|
147
|
-
chunkFileNames: '[name]-[hash].js',
|
|
148
|
-
entryFileNames: '[name]-[hash].js',
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
css: {
|
|
153
|
-
devSourcemap : true,
|
|
154
|
-
preprocessorOptions: {
|
|
155
|
-
less: {
|
|
156
|
-
sourceMap : true,
|
|
157
|
-
globalVars: {
|
|
158
|
-
globalVariables: `true; @import (reference) "${lessDir}/variables.less";`,
|
|
159
|
-
globalMixins : `true; @import (reference) "${lessDir}/mixins.less";`,
|
|
160
|
-
globalFonts : `true; @import (reference) "${lessDir}/fonts.less";`,
|
|
161
|
-
},
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
},
|
|
165
|
-
resolve: {
|
|
166
|
-
alias: {
|
|
167
|
-
'~fonts': resolve(options.root, 'src/assets/fonts'),
|
|
168
|
-
'@' : resolve(options.root, 'src'),
|
|
169
|
-
},
|
|
170
|
-
/**
|
|
171
|
-
* a linked @lilaquadrat/design-core resolves these from its own
|
|
172
|
-
* node_modules, which would give the app a second vue and a second
|
|
173
|
-
* pinia - one app instance registering into a store nobody reads.
|
|
174
|
-
* dedupe pins every shared runtime to the project copy.
|
|
175
|
-
*/
|
|
176
|
-
dedupe: [
|
|
177
|
-
'vue',
|
|
178
|
-
'vue-router',
|
|
179
|
-
'vue-i18n',
|
|
180
|
-
'pinia',
|
|
181
|
-
// holds a static request cache, so a second copy would cache twice
|
|
182
|
-
'@lilaquadrat/sdk',
|
|
183
|
-
// resize and inview are singletons: a second copy means a second
|
|
184
|
-
// scroll listener and a second set of refs nobody reads
|
|
185
|
-
'@lilaquadrat/frontend',
|
|
186
|
-
'@auth0/auth0-spa-js',
|
|
187
|
-
'axios',
|
|
188
|
-
'dayjs',
|
|
189
|
-
],
|
|
190
|
-
/**
|
|
191
|
-
* @lilaquadrat/studio is deliberately NOT deduped: it is the backend
|
|
192
|
-
* package and a project may still hold a copy for other reasons, while
|
|
193
|
-
* a second one costs nothing here.
|
|
194
|
-
*
|
|
195
|
-
* @lilaquadrat/interfaces is types only, so it has nothing to dedupe.
|
|
196
|
-
*/
|
|
197
|
-
},
|
|
198
|
-
define: {
|
|
199
|
-
'__FRONTEND_CONFIG__' : JSON.stringify(config),
|
|
200
|
-
'__TARGET__' : JSON.stringify(target),
|
|
201
|
-
'__PREVIEW__' : JSON.stringify(isPreview),
|
|
202
|
-
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: isOptimized ? 'false' : 'true',
|
|
203
|
-
__VUE_PROD_DEVTOOLS__ : isOptimized ? 'false' : 'true',
|
|
204
|
-
...options.define
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
if (isPreview) {
|
|
209
|
-
|
|
210
|
-
viteConfig.build = previewBuildOptions(viteConfig.build);
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (settings.isSsrBuild) {
|
|
215
|
-
|
|
216
|
-
viteConfig.build = {
|
|
217
|
-
...viteConfig.build,
|
|
218
|
-
rolldownOptions: {
|
|
219
|
-
input : isSsrTest ? ssrFixturesEntry : ssrEntry,
|
|
220
|
-
plugins: isSsrTest ? [] : [
|
|
221
|
-
{
|
|
222
|
-
name: 'emit-html-templates',
|
|
223
|
-
async generateBundle () {
|
|
224
|
-
const { readFile } = await import('node:fs/promises');
|
|
225
|
-
const [mailHtml, serverHtml] = await Promise.all([
|
|
226
|
-
readFile(resolveTemplate(options.root, 'index.mail.html'), 'utf-8'),
|
|
227
|
-
readFile(resolveTemplate(options.root, 'index.server.html'), 'utf-8'),
|
|
228
|
-
]);
|
|
229
|
-
|
|
230
|
-
this.emitFile({ type: 'asset', fileName: 'index.mail.html', source: mailHtml });
|
|
231
|
-
this.emitFile({ type: 'asset', fileName: 'index.server.html', source: serverHtml });
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
],
|
|
235
|
-
output: {
|
|
236
|
-
...viteConfig.build?.rolldownOptions?.output,
|
|
237
|
-
codeSplitting : false,
|
|
238
|
-
inlineDynamicImports: true,
|
|
239
|
-
dir : isSsrTest ? 'dist/ssr-test' : 'dist/server',
|
|
240
|
-
entryFileNames : '[name].js',
|
|
241
|
-
}
|
|
242
|
-
},
|
|
243
|
-
ssrManifest: !isSsrTest,
|
|
244
|
-
}
|
|
245
|
-
viteConfig.ssr = {
|
|
246
|
-
target : 'webworker',
|
|
247
|
-
noExternal: true,
|
|
248
|
-
external : ['node:stream', 'http', 'https', 'crypto', 'path', 'highlight.js'],
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return viteConfig;
|
|
254
|
-
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
export default createViteConfig;
|
|
260
|
-
export { previewBundle, dropPreviewAssets, previewBuildOptions };
|