cayo 0.9.9 → 0.9.11
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 +504 -5
- package/cayo.js +1 -298
- package/devlog.md +177 -0
- package/dist/cayo.svelte.js +80 -0
- package/dist/entry.svelte.js +16 -0
- package/dist/index.js +2 -0
- package/docs/config-reference.md +349 -0
- package/docs/how-cayo-works.md +28 -0
- package/docs/why-i-created-cayo.md +21 -0
- package/lib/cli/build.js +34 -0
- package/lib/cli/cli.js +152 -0
- package/lib/cli/dev.js +12 -0
- package/lib/cli/serve.js +25 -0
- package/lib/cli/watch.js +125 -0
- package/lib/core/bundle.js +155 -0
- package/lib/core/codegen.js +156 -0
- package/lib/core/compile/cayos.js +65 -0
- package/lib/core/compile/index.js +3 -0
- package/lib/core/compile/pages.js +61 -0
- package/lib/core/compile/template.js +24 -0
- package/lib/core/component.js +62 -0
- package/lib/core/config.js +206 -0
- package/lib/core/dependencies.js +167 -0
- package/lib/core/entry.js +24 -0
- package/lib/core/files.js +99 -0
- package/lib/core/logger.js +47 -0
- package/lib/core/page.js +59 -0
- package/lib/core/render/prerender.js +240 -0
- package/lib/core/render/renderer.js +52 -0
- package/lib/core/utils.js +60 -0
- package/package.json +21 -10
- package/scripts/build.js +60 -0
- package/src/cayo-warnings.js +37 -0
- package/src/cayo.svelte +36 -0
- package/src/entry.svelte +6 -0
- package/template/cayo.config.js +3 -0
- package/template/package.json +7 -0
- package/template/public/vite.svg +1 -0
- package/{tests/basic cases (old)/src/__index.svelte → template/src/__template.svelte} +3 -6
- package/template/src/components/counter.cayo.svelte +27 -0
- package/template/src/index.js +4 -0
- package/template/src/pages/index.svelte +15 -0
- package/template/src/style.css +13 -0
- package/lib/cli.js +0 -69
- package/lib/codegen.js +0 -79
- package/lib/components/Cayo.svelte +0 -25
- package/lib/config.js +0 -155
- package/lib/files.js +0 -84
- package/lib/prerender.js +0 -181
- package/lib/renderer.js +0 -49
- package/lib/runtime.js +0 -6
- package/lib/utils.js +0 -126
- package/lib/vite.config.js +0 -16
- package/notes.md +0 -3
- package/test/cayo.config.js +0 -35
- package/test/public/assets/cow.js +0 -1
- package/test/public/images/app-icon.png +0 -0
- package/test/src/__layout.svelte +0 -20
- package/test/src/components/Cool.cayo.svelte +0 -5
- package/test/src/components/Some.svelte +0 -1
- package/test/src/components/Test.cayo.svelte +0 -5
- package/test/src/index.js +0 -17
- package/test/src/main2.js +0 -1
- package/test/src/pages/hey.svelte +0 -8
- package/test/src/pages/howdy.svelte +0 -11
- package/test/src/pages/index.svelte +0 -38
- package/test/src/pages/some/page.svelte +0 -2
- package/tests/asset-dir/cayo.config.js +0 -38
- package/tests/asset-dir/package-lock.json +0 -1435
- package/tests/asset-dir/package.json +0 -19
- package/tests/asset-dir/public/images/app-icon.png +0 -0
- package/tests/asset-dir/src/__layout.svelte +0 -20
- package/tests/asset-dir/src/components/CayoExample.svelte +0 -5
- package/tests/asset-dir/src/components/Some.cayo.svelte +0 -6
- package/tests/asset-dir/src/index.js +0 -5
- package/tests/asset-dir/src/pages/index.svelte +0 -19
- package/tests/base-path/cayo.config.js +0 -36
- package/tests/base-path/package-lock.json +0 -1435
- package/tests/base-path/package.json +0 -19
- package/tests/base-path/public/assets/cow.js +0 -1
- package/tests/base-path/public/images/app-icon.png +0 -0
- package/tests/base-path/src/__layout.svelte +0 -20
- package/tests/base-path/src/components/CayoExample.svelte +0 -5
- package/tests/base-path/src/components/Some.cayo.svelte +0 -6
- package/tests/base-path/src/index.js +0 -5
- package/tests/base-path/src/pages/howdy.svelte +0 -12
- package/tests/base-path/src/pages/index.svelte +0 -20
- package/tests/basic/notcayo.config.js +0 -35
- package/tests/basic/package-lock.json +0 -1435
- package/tests/basic/package.json +0 -19
- package/tests/basic/public/assets/cow.js +0 -1
- package/tests/basic/public/images/app-icon.png +0 -0
- package/tests/basic/src/__layout.svelte +0 -20
- package/tests/basic/src/components/Cool.cayo.svelte +0 -4
- package/tests/basic/src/components/Some.svelte +0 -1
- package/tests/basic/src/index.js +0 -5
- package/tests/basic/src/main2.js +0 -1
- package/tests/basic/src/pages/hey.svelte +0 -8
- package/tests/basic/src/pages/howdy.svelte +0 -11
- package/tests/basic/src/pages/index.svelte +0 -33
- package/tests/basic/src/pages/some/some.svelte +0 -2
- package/tests/basic cases (old)/src/components/Cool.cayo.svelte +0 -4
- package/tests/basic cases (old)/src/components/Some.svelte +0 -1
- package/tests/basic cases (old)/src/components/dir/Cool.cayo.svelte +0 -4
- package/tests/basic cases (old)/src/main.js +0 -1
- package/tests/basic cases (old)/src/main2.js +0 -1
- package/tests/basic cases (old)/src/pages/hey.svelte +0 -2
- package/tests/basic cases (old)/src/pages/howdy.svelte +0 -11
- package/tests/basic cases (old)/src/pages/index.svelte +0 -27
- package/tests/nested-pages/cayo.config.js +0 -35
- package/tests/nested-pages/package-lock.json +0 -1435
- package/tests/nested-pages/package.json +0 -19
- package/tests/nested-pages/public/assets/cow.js +0 -1
- package/tests/nested-pages/public/images/app-icon.png +0 -0
- package/tests/nested-pages/src/__layout.svelte +0 -20
- package/tests/nested-pages/src/components/Cool.cayo.svelte +0 -4
- package/tests/nested-pages/src/index.js +0 -5
- package/tests/nested-pages/src/main2.js +0 -1
- package/tests/nested-pages/src/pages/index.svelte +0 -18
- package/tests/nested-pages/src/pages/some/other/page.svelte +0 -7
- package/tests/nested-pages/src/pages/some/page.svelte +0 -6
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { JSDOM } from 'jsdom';
|
|
4
|
+
import { Renderer } from './renderer.js';
|
|
5
|
+
import { compileCayos } from '../compile/cayos.js';
|
|
6
|
+
import { generateCayoRuntime, generateRuntimeIssuesScript } from '../codegen.js';
|
|
7
|
+
import { generateCayoComponentId } from '../utils.js';
|
|
8
|
+
import logger from '../logger.js';
|
|
9
|
+
|
|
10
|
+
export async function prerender(page, _cayo) {
|
|
11
|
+
const renderer = new Renderer(page.layout);
|
|
12
|
+
const componentList = new Set();
|
|
13
|
+
|
|
14
|
+
const content = await renderer.render(page, _cayo.config);
|
|
15
|
+
// Postprocess the content, get deps and inject dep references
|
|
16
|
+
const processed = await processPage(
|
|
17
|
+
content,
|
|
18
|
+
page,
|
|
19
|
+
_cayo,
|
|
20
|
+
logger
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const { cayoInstances } = processed;
|
|
24
|
+
|
|
25
|
+
Object.keys(cayoInstances).forEach(component => componentList.add(component))
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
...processed,
|
|
29
|
+
components: [...componentList],
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Derive JS dependencies from the prerendered html
|
|
34
|
+
export async function processPage(content, page, _cayo, logger) {
|
|
35
|
+
const { config } = _cayo;
|
|
36
|
+
// JSDOM Initialization
|
|
37
|
+
const dom = new JSDOM(content.html);
|
|
38
|
+
const { document } = dom.window;
|
|
39
|
+
// For storing issues while we process the page
|
|
40
|
+
const warnings = {
|
|
41
|
+
cayos: {},
|
|
42
|
+
page: {},
|
|
43
|
+
};
|
|
44
|
+
const errors = {
|
|
45
|
+
cayos: {},
|
|
46
|
+
page: {},
|
|
47
|
+
};
|
|
48
|
+
// For generated file contents
|
|
49
|
+
let js = { code: '' };
|
|
50
|
+
let entry = { path: '' };
|
|
51
|
+
// Get component instance info
|
|
52
|
+
const cayoIds = [];
|
|
53
|
+
const cayoInstances = {};
|
|
54
|
+
const cayoAssets = {};
|
|
55
|
+
// Find all cayo instances in the markup
|
|
56
|
+
for (const el of document.querySelectorAll('[data-cayo-src]')) {
|
|
57
|
+
let src = el.dataset.cayoSrc;
|
|
58
|
+
if (src !== '') {
|
|
59
|
+
const { id, name } = generateCayoComponentId(src);
|
|
60
|
+
cayoIds.push(id);
|
|
61
|
+
el.dataset.cayoId = id;
|
|
62
|
+
|
|
63
|
+
// Get warnings added by the Cayo component during compile time
|
|
64
|
+
if (el.dataset.cayoWarn && el.dataset.cayoWarn !== '{}') {
|
|
65
|
+
warnings.cayos[id] = JSON.parse(el.dataset.cayoWarn);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Add cayos to stats for dependency handling
|
|
69
|
+
let absoluteSrc = path.resolve(config.components, src);
|
|
70
|
+
if (_cayo.stats.cayoComponents[name]) {
|
|
71
|
+
_cayo.stats.cayoComponents[name].src = absoluteSrc;
|
|
72
|
+
_cayo.stats.cayoComponents[name].pages.add(page.sourcePath);
|
|
73
|
+
} else {
|
|
74
|
+
_cayo.stats.cayoComponents[name] = {
|
|
75
|
+
src: absoluteSrc,
|
|
76
|
+
pages: new Set([page.sourcePath]),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
_cayo.stats.dependencies.pages[page.sourcePath].add(absoluteSrc);
|
|
80
|
+
|
|
81
|
+
// Compile cayos & keep track of them for this page
|
|
82
|
+
const [cayo] = await compileCayos({ [name]: _cayo.stats.cayoComponents[name] }, _cayo);
|
|
83
|
+
// Store references of each cayo instance on the page
|
|
84
|
+
if (cayoInstances[name]) {
|
|
85
|
+
cayoInstances[name].push(id);
|
|
86
|
+
} else {
|
|
87
|
+
cayoInstances[name] = [id];
|
|
88
|
+
}
|
|
89
|
+
// Include the assets needed by a cayo
|
|
90
|
+
// CSS is the only thing currently output other than the component JS
|
|
91
|
+
if (cayo && !cayoAssets[name]) {
|
|
92
|
+
cayoAssets[name] = {
|
|
93
|
+
css: {
|
|
94
|
+
code: cayo.output.css.code
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
} else {
|
|
100
|
+
// At least one error will be reported if the src is invalid
|
|
101
|
+
if (el.dataset.cayoWarn) {
|
|
102
|
+
warnings.cayos['undefined'] = JSON.parse(el.dataset.cayoWarn);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Clean up data attributes we don't need during runtime
|
|
106
|
+
delete el.dataset.cayoSrc;
|
|
107
|
+
delete el.dataset.cayoWarn;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
let cayoAssetCssElements = '';
|
|
111
|
+
for (const [name, cayo] of Object.entries(cayoAssets)) {
|
|
112
|
+
if (cayo.css.code !== '') {
|
|
113
|
+
cayoAssetCssElements += config.css.internal
|
|
114
|
+
? `<style>/* ${name} CSS */${cayo.css.code}</style>\n`
|
|
115
|
+
: `<link rel="stylesheet" href="/${name}.css">\n`
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const cayoAssetsCssMarker = document.querySelector('link[data-cayo-assets-css]');
|
|
119
|
+
cayoAssetsCssMarker.outerHTML = cayoAssetCssElements;
|
|
120
|
+
|
|
121
|
+
// Get user-specified entry placeholder
|
|
122
|
+
const entryScriptPlaceholder = document.querySelector('script[data-cayo-entry]');
|
|
123
|
+
let entryScriptSrc = entryScriptPlaceholder ? entryScriptPlaceholder.src : '';
|
|
124
|
+
// This is injected by Renderer.render based on the template
|
|
125
|
+
const entryScript = document.querySelector(`script[type="module"][src="./index.js"]`);
|
|
126
|
+
|
|
127
|
+
if (entryScriptSrc) {
|
|
128
|
+
// Remove user-specified entry file placeholder
|
|
129
|
+
entryScriptPlaceholder.remove();
|
|
130
|
+
// Validate the file path
|
|
131
|
+
const absoluteEntrySrcPath = path.resolve(config.src, entryScriptSrc);
|
|
132
|
+
if (!fs.pathExistsSync(absoluteEntrySrcPath)) {
|
|
133
|
+
let relativePath = entryScriptSrc.replace(config.projectRoot, '');
|
|
134
|
+
errors.page.entryFileDoesNotExist = {
|
|
135
|
+
title: `Bad entry file`,
|
|
136
|
+
src: page.sourcePath.replace(config.pages, ''),
|
|
137
|
+
message: `Entry file '${relativePath}' does not exist.`,
|
|
138
|
+
log: `Entry file '${entryScriptSrc}' does not exist.`,
|
|
139
|
+
}
|
|
140
|
+
// Remove the entry file script because the file doesn't exist
|
|
141
|
+
entryScript.remove();
|
|
142
|
+
} else {
|
|
143
|
+
entry.path = absoluteEntrySrcPath;
|
|
144
|
+
_cayo.stats.dependencies.pages[page.sourcePath].add(absoluteEntrySrcPath);
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
if (cayoIds.length > 0) {
|
|
148
|
+
let message = 'An entry file is required in order to render Cayos on the page.'
|
|
149
|
+
warnings.page.noEntryFile = {
|
|
150
|
+
title: `No entry file`,
|
|
151
|
+
src: page.sourcePath.replace(config.pages, ''),
|
|
152
|
+
message: message,
|
|
153
|
+
log: `No entry file found. ${message}`,
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
// Remove the entry point script tag because the page doesn't need any JS
|
|
157
|
+
entryScript.remove();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Generate JS for cayos to run in the browser as needed
|
|
162
|
+
const cayoRuntimePath = page.url === '/' ? `/index.js` : `${page.url}/index.js`;
|
|
163
|
+
js = generateCayoRuntime(cayoInstances, cayoRuntimePath, _cayo);
|
|
164
|
+
|
|
165
|
+
// Indicate that we need to make this entry ready to render cayos later,
|
|
166
|
+
// if there are cayo instances on this page
|
|
167
|
+
if (cayoIds.length > 0) {
|
|
168
|
+
entry.renderCayos = true;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Append runtime warnings
|
|
172
|
+
const {
|
|
173
|
+
script: warningScript,
|
|
174
|
+
logs: warningLogs
|
|
175
|
+
} = generateRuntimeIssuesScript({ config, document, page }, warnings, 'warning');
|
|
176
|
+
if (config.mode === 'development') {
|
|
177
|
+
document.body.appendChild(warningScript);
|
|
178
|
+
}
|
|
179
|
+
// Append runtime errors
|
|
180
|
+
const {
|
|
181
|
+
script: errorScript,
|
|
182
|
+
logs: errorLogs,
|
|
183
|
+
} = generateRuntimeIssuesScript({ config, document, page }, errors, 'error');
|
|
184
|
+
if (config.mode === 'development') {
|
|
185
|
+
document.body.appendChild(errorScript);;
|
|
186
|
+
}
|
|
187
|
+
// Log any runtime warnings and errors
|
|
188
|
+
for (const message of [...warningLogs, ...errorLogs]) {
|
|
189
|
+
logger.log.info(
|
|
190
|
+
message,
|
|
191
|
+
{ timestamp: true, clear: false, }
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Construct the correct HTML string based on the document structure
|
|
196
|
+
// that was rendered from the source (jsdom wraps the source HTML in a document,
|
|
197
|
+
// which always includes `html`, `head`, and `body`, even if the source doesn't)
|
|
198
|
+
const tags = tagsExist(content.html);
|
|
199
|
+
let processedHTML = '';
|
|
200
|
+
if (tags.doctype) {
|
|
201
|
+
processedHTML += tags.doctype;
|
|
202
|
+
}
|
|
203
|
+
if (tags.html) {
|
|
204
|
+
processedHTML += document.documentElement.outerHTML;
|
|
205
|
+
} else {
|
|
206
|
+
if (tags.head) {
|
|
207
|
+
processedHTML += document.head.outerHTML;
|
|
208
|
+
} else {
|
|
209
|
+
processedHTML += document.head.innerHTML;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (tags.body) {
|
|
213
|
+
processedHTML += document.body.outerHTML;
|
|
214
|
+
} else {
|
|
215
|
+
processedHTML += document.body.innerHTML;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
html: processedHTML,
|
|
221
|
+
css: content.css.code,
|
|
222
|
+
js,
|
|
223
|
+
cayoInstances,
|
|
224
|
+
cayoAssets,
|
|
225
|
+
entry,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function tagsExist(source) {
|
|
230
|
+
const doctype = source.match(/\<!DOCTYPE\s\w*\>/g);
|
|
231
|
+
const head = source.match(/\<head[\s\S]*\>(?<innerHTML>[\s\S]*)\<\/head\>/g);
|
|
232
|
+
const body = source.match(/\<body[\s\S]*\>(?<innerHTML>[\s\S]*)\<\/body\>/g);
|
|
233
|
+
const html = source.match(/\<html[\s\S]*\>(?<innerHTML>[\s\S]*)\<\/html\>/g);
|
|
234
|
+
return {
|
|
235
|
+
doctype: doctype === null ? false : doctype,
|
|
236
|
+
head: head === null ? false : true,
|
|
237
|
+
body: body === null ? false : true,
|
|
238
|
+
html: html === null ? false : true,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export class Renderer {
|
|
2
|
+
|
|
3
|
+
constructor(template) {
|
|
4
|
+
this.template = template;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
async render(page, config) {
|
|
8
|
+
const { css: cssOptions } = config;
|
|
9
|
+
const Component = await page.load();
|
|
10
|
+
const res = Component.render();
|
|
11
|
+
const { html, css, head } = res;
|
|
12
|
+
|
|
13
|
+
let cssElements = '';
|
|
14
|
+
if (cssOptions.internal === false) {
|
|
15
|
+
if (this.template.css && this.template.css.code !== '') {
|
|
16
|
+
cssElements += `<link rel="stylesheet" href="/__index.css">\n`;
|
|
17
|
+
}
|
|
18
|
+
cssElements += `<link rel="stylesheet" href="./index.css">`;
|
|
19
|
+
|
|
20
|
+
} else {
|
|
21
|
+
if (this.template.css && this.template.css.code !== '') {
|
|
22
|
+
cssElements += `<style>/* Template CSS */${this.template.css.code}</style>\n`;
|
|
23
|
+
}
|
|
24
|
+
cssElements += `<style>${css.code}</style>`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
cssElements += '\n<link data-cayo-assets-css>';
|
|
28
|
+
|
|
29
|
+
const title = () => {
|
|
30
|
+
let title = page.name;
|
|
31
|
+
title = title.charAt(0).toUpperCase() + title.substring(1);
|
|
32
|
+
return `<title>${title}</title>`
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Note: Q: why the `() => str` for 2nd replacement arg?
|
|
36
|
+
// A: In case there's dollar signs in that there string
|
|
37
|
+
// https://stackoverflow.com/questions/9423722/string-replace-weird-behavior-when-using-dollar-sign-as-replacement
|
|
38
|
+
return {
|
|
39
|
+
html: this.template.html
|
|
40
|
+
// FIXME#83: this regex is bad; accidentally removes elements like head
|
|
41
|
+
// Ignore placeholders wrapped in HTML comments
|
|
42
|
+
// .replace(/<!--[^]*\%cayo\.\w+\%[^]*-->/g, '')
|
|
43
|
+
.replace('%cayo.title%', () => !head.includes('<title>') ? title() : '')
|
|
44
|
+
.replace('%cayo.head%', () => head)
|
|
45
|
+
.replace('%cayo.body%', () => html)
|
|
46
|
+
.replace('%cayo.css%', () => cssElements)
|
|
47
|
+
// Vite needs the entry file in this format
|
|
48
|
+
.replace('%cayo.script%', () => `<script type="module" src="./index.js"></script>`),
|
|
49
|
+
css,
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import crypto from 'crypto';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
|
|
5
|
+
// https://github.com/sveltejs/svelte/blob/master/src/compiler/compile/utils/hash.ts
|
|
6
|
+
export function hash(str = '', bytes = 5) {
|
|
7
|
+
const random = crypto.randomBytes(bytes).toString('hex');
|
|
8
|
+
str += random;
|
|
9
|
+
|
|
10
|
+
str = str.replace(/\r/g, '');
|
|
11
|
+
let hash = 5381;
|
|
12
|
+
let i = str.length;
|
|
13
|
+
|
|
14
|
+
while (i--) hash = ((hash << bytes) - hash) ^ str.charCodeAt(i);
|
|
15
|
+
return (hash >>> 0).toString(36);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function generateSafeName(inputPath) {
|
|
19
|
+
return inputPath
|
|
20
|
+
.replace(/^\.\//g, '')
|
|
21
|
+
.replace(/\/+/g, '__')
|
|
22
|
+
.replace(/\-+/g, '_');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function generateCayoComponentId(componentPath) {
|
|
26
|
+
const name = generateSafeName(componentPath)
|
|
27
|
+
.replace('.cayo.svelte', '');
|
|
28
|
+
|
|
29
|
+
const id = `${name}-${hash(name)}`;
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
id,
|
|
33
|
+
name,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Credit: https://github.com/snowpackjs/astro
|
|
38
|
+
/** Add / to the end of string (but don’t double-up) */
|
|
39
|
+
export function addTrailingSlash(_path) {
|
|
40
|
+
return _path.replace(/\/?$/, '/');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function normalizePath(root, _path) {
|
|
44
|
+
if (root === _path) return root;
|
|
45
|
+
return path.normalize(path.join(root, addTrailingSlash(_path)));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// TODO: need to use this somewhere?
|
|
49
|
+
export function getOutDir(config) {
|
|
50
|
+
return config.mode === 'production' ? config.buildOptions.outDir : config.cayoPath;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function debugStats(_cayo) {
|
|
54
|
+
const { stats, config } = _cayo;
|
|
55
|
+
fs.outputFile(path.resolve(config.cayoPath, './__cayo/stats.json'), JSON.stringify(
|
|
56
|
+
stats,
|
|
57
|
+
(key, value) => value instanceof Set ? [...value] : value,
|
|
58
|
+
2
|
|
59
|
+
));
|
|
60
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cayo",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"start": "node cayo dev --projectRoot test"
|
|
6
|
+
"start": "node cayo dev --projectRoot test",
|
|
7
|
+
"build": "node scripts/build"
|
|
8
|
+
},
|
|
9
|
+
"imports": {
|
|
10
|
+
"#core/*": "./lib/core/*"
|
|
7
11
|
},
|
|
8
12
|
"bin": {
|
|
9
13
|
"cayo": "cayo.js"
|
|
10
14
|
},
|
|
15
|
+
"svelte": "./dist/index.js",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./package.json": "./package.json"
|
|
21
|
+
},
|
|
11
22
|
"repository": {
|
|
12
23
|
"type": "git",
|
|
13
24
|
"url": "git+https://github.com/matthew-ia/cayo.git"
|
|
@@ -18,21 +29,21 @@
|
|
|
18
29
|
"url": "https://github.com/matthew-ia/cayo/issues"
|
|
19
30
|
},
|
|
20
31
|
"homepage": "https://github.com/matthew-ia/cayo#readme",
|
|
21
|
-
"devDependencies": {
|
|
22
|
-
"@vitejs/plugin-legacy": "^1.6.2"
|
|
23
|
-
},
|
|
24
32
|
"dependencies": {
|
|
25
|
-
"@
|
|
33
|
+
"@rollup/plugin-json": "^4.1.0",
|
|
26
34
|
"chalk": "^2.4.2",
|
|
27
35
|
"chokidar": "^3.5.2",
|
|
28
36
|
"deepmerge": "^4.2.2",
|
|
29
37
|
"fast-glob": "^3.2.7",
|
|
30
38
|
"fs-extra": "^10.0.0",
|
|
31
39
|
"jsdom": "^18.0.0",
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
40
|
+
"precinct": "^9.0.0",
|
|
41
|
+
"prettier": "^2.7.1",
|
|
42
|
+
"rollup": "^2.70.1",
|
|
43
|
+
"rollup-plugin-import-css": "^3.0.3",
|
|
44
|
+
"rollup-plugin-svelte": "^7.1.0",
|
|
45
|
+
"svelte": "^3.49.0",
|
|
46
|
+
"vite": "^3.1.2",
|
|
36
47
|
"yargs-parser": "^20.2.9",
|
|
37
48
|
"zod": "^3.10.3"
|
|
38
49
|
}
|
package/scripts/build.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Build
|
|
4
|
+
// - Compile Svelte components to JS
|
|
5
|
+
// - Generate an index file for these components to be
|
|
6
|
+
// used as the Cayo package's exports
|
|
7
|
+
|
|
8
|
+
import fs from 'fs-extra';
|
|
9
|
+
import { validateConfig } from '../lib/core/config.js';
|
|
10
|
+
import { build } from '../lib/core/bundle.js';
|
|
11
|
+
import logger from '../lib/core/logger.js';
|
|
12
|
+
import chalk from 'chalk';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
|
|
15
|
+
async function compileComponents(components, config) {
|
|
16
|
+
const output = {};
|
|
17
|
+
for (const component of components) {
|
|
18
|
+
try {
|
|
19
|
+
const inputPath = path.resolve(`./src/${component}.svelte`);
|
|
20
|
+
const outputPath = path.resolve(`./dist/${component}.svelte.js`);
|
|
21
|
+
const { js } = await build(inputPath, config);
|
|
22
|
+
await fs.outputFile(outputPath, js.code);
|
|
23
|
+
output[component] = { path: `./${component}.svelte.js` }
|
|
24
|
+
console.log(chalk.green.bold(`Compiled ${component}.svelte → ${component}.svelte.js`));
|
|
25
|
+
console.log(chalk.dim(`./dist/${component}.svelte.js`));
|
|
26
|
+
} catch (err) {
|
|
27
|
+
throw new Error(`Cayo Internal Error: Could not compile ./src/${component}.svelte`, { cause: err });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return output;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function generateIndex(modules) {
|
|
35
|
+
let js = '';
|
|
36
|
+
for (const m of modules) {
|
|
37
|
+
js += `export { default as ${m[0]} } from '${m[1]}';\n`;
|
|
38
|
+
}
|
|
39
|
+
return { code: js };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const cayoConfig = await validateConfig({});
|
|
44
|
+
const output = await compileComponents(['cayo', 'entry'], cayoConfig);
|
|
45
|
+
const index = generateIndex([
|
|
46
|
+
// Tuples of modules to import in the index file
|
|
47
|
+
['Cayo', output.cayo.path],
|
|
48
|
+
['Entry', output.entry.path],
|
|
49
|
+
]);
|
|
50
|
+
await fs.outputFile('./dist/index.js', index.code)
|
|
51
|
+
.then(() => {
|
|
52
|
+
console.log(chalk.green.bold(`✅ Components built.`));
|
|
53
|
+
console.log(chalk.dim(`./dist/index.js`));
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
} catch (err) {
|
|
57
|
+
logger.error(err);
|
|
58
|
+
console.error(err.stack);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export function getWarnings(src, badProps) {
|
|
2
|
+
const warnings = {};
|
|
3
|
+
checkInvalidSrc(warnings, src);
|
|
4
|
+
checkBadProps(warnings, src, badProps);
|
|
5
|
+
return warnings;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// Warning: invalid src prop')
|
|
9
|
+
function checkInvalidSrc(warnings, src) {
|
|
10
|
+
if (!src || typeof src !== 'string') {
|
|
11
|
+
warnings.invalidSrc = {
|
|
12
|
+
title: `Invalid src prop`,
|
|
13
|
+
src: !src ? 'undefined' : typeof src,
|
|
14
|
+
message: `The src prop is required and must be a string.`,
|
|
15
|
+
log: `Use of <Cayo> without a src prop found. No cayo instance will be rendered.`,
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Warning: unserializable props
|
|
21
|
+
function checkBadProps(warnings, src, keys) {
|
|
22
|
+
if (keys.length > 0) {
|
|
23
|
+
let propsStr = '';
|
|
24
|
+
for (let i = 0; i < keys.length; i++) {
|
|
25
|
+
propsStr += `'${keys[i]}'`;
|
|
26
|
+
if (i+1 < keys.length) {
|
|
27
|
+
propsStr += `, `;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
warnings.badProps = {
|
|
31
|
+
title: `Bad props`,
|
|
32
|
+
src,
|
|
33
|
+
message: `Unserializable props found: ${propsStr}. Cayo component props must be serializable in order to be used for hydration.`,
|
|
34
|
+
log: `Unserializable instance props found: ${propsStr}.`,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
package/src/cayo.svelte
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
export let src;
|
|
3
|
+
import { getWarnings } from './cayo-warnings.js';
|
|
4
|
+
|
|
5
|
+
// Save unserializable prop keys (during stringification)
|
|
6
|
+
// so we can report them later
|
|
7
|
+
const badProps = [];
|
|
8
|
+
function replacer(key, value) {
|
|
9
|
+
const type = typeof value;
|
|
10
|
+
if (
|
|
11
|
+
type === 'function' ||
|
|
12
|
+
type === 'undefined' ||
|
|
13
|
+
type === 'symbol'
|
|
14
|
+
) {
|
|
15
|
+
badProps.push(key);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return value;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const json = JSON.stringify({...$$restProps}, replacer);
|
|
22
|
+
const warnings = getWarnings(src, badProps);
|
|
23
|
+
const cayoInstanceData = {
|
|
24
|
+
'data-cayo-id': '',
|
|
25
|
+
'data-cayo-src': !warnings.invalidSrc ? `${src}` : '',
|
|
26
|
+
'data-cayo-props': json,
|
|
27
|
+
};
|
|
28
|
+
if (warnings) {
|
|
29
|
+
cayoInstanceData['data-cayo-warn'] = JSON.stringify(warnings);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<div {...cayoInstanceData}>
|
|
35
|
+
<slot/>
|
|
36
|
+
</div>
|
package/src/entry.svelte
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
@@ -2,17 +2,14 @@
|
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
|
-
<link rel="icon" href="/
|
|
5
|
+
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏝</text></svg>">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
%cayo.title%
|
|
8
|
+
%cayo.css%
|
|
8
9
|
%cayo.head%
|
|
9
10
|
</head>
|
|
10
11
|
<body>
|
|
11
|
-
<!--
|
|
12
|
-
TODO: Show how to condtionally render any of these pieces based on dev vs. prod
|
|
13
|
-
E.g., I need to remove head from prod, but want it there in dev
|
|
14
|
-
-->
|
|
15
12
|
%cayo.body%
|
|
16
13
|
%cayo.script%
|
|
17
14
|
</body>
|
|
18
|
-
</html>
|
|
15
|
+
</html>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
export let count = 0;
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<div class="wrapper">
|
|
6
|
+
<button on:click={() => count++}>Count: {count}</button>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<style>
|
|
10
|
+
.wrapper {
|
|
11
|
+
display: flex;
|
|
12
|
+
justify-content: center;
|
|
13
|
+
}
|
|
14
|
+
button {
|
|
15
|
+
padding: .5rem;
|
|
16
|
+
background-color: transparent;
|
|
17
|
+
border: 1px solid rgba(81, 95, 240, .75);
|
|
18
|
+
color: white;
|
|
19
|
+
border-radius: 5px;
|
|
20
|
+
transition: .2s;
|
|
21
|
+
}
|
|
22
|
+
button:hover {
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
border-color: rgb(81, 95, 240);
|
|
25
|
+
background-color: rgba(81, 95, 240, .25);
|
|
26
|
+
}
|
|
27
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { Cayo, Entry } from 'cayo';
|
|
3
|
+
const heading = '🏝 Cayo';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<h1>{heading}</h1>
|
|
7
|
+
<Cayo src="counter.cayo.svelte" />
|
|
8
|
+
<Entry src="index.js" />
|
|
9
|
+
|
|
10
|
+
<style>
|
|
11
|
+
h1 {
|
|
12
|
+
text-align: center;
|
|
13
|
+
font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
|
14
|
+
}
|
|
15
|
+
</style>
|