Skip to content

Commit

Permalink
feat: rewrite internal compilation to use Svelte compile and preproce…
Browse files Browse the repository at this point in the history
…ss (#59)

This compilation (bundling) is uses rollup instead of the Svelte API directly (`svelte/compile` and `svelte/preprocess`), as this was initially going to use. 

---

### Fixes: 
- fix #50 
- fix #49
- fix #47
- fix #46
- fix #44
- fix #58
  • Loading branch information
matthew-ia authored Aug 14, 2022
1 parent c77c28c commit a45a906
Show file tree
Hide file tree
Showing 96 changed files with 4,417 additions and 1,073 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/node_modules/
/tests/**/node_modules
/dist/
/test/**/dist/
/tests/**/dist/
/.vscode/
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,9 @@ To run:
> node cayo dev --projectRoot test
> node cayo dev
> node cayo build
```

This is old, but:
```bash
vite build --outDir dist --ssr prerender.js --mode development && node dist/prerender.js
```
299 changes: 1 addition & 298 deletions cayo.js
Original file line number Diff line number Diff line change
@@ -1,302 +1,5 @@
#!/usr/bin/env node

import yargs from 'yargs-parser';
import chokidar from 'chokidar';
import path from 'path';
import chalk from 'chalk';
import merge from 'deepmerge';
import { createServer, createLogger, build as viteBuild } from 'vite';
import { loadConfig, checkConfigPaths } from './lib/config.js';
import { prerender } from './lib/prerender.js';
import {
writePageFiles,
writeComponentFile,
cleanCayoPath,
writeTemplateCSS,
} from './lib/files.js';
import {
hash,
getPageModules,
getComponentModules,
createTemplateManifest,
createPageManifest,
createComponentManifest,
} from './lib/utils.js';

const logger = createLogger('info', {
prefix: chalk.magenta.bold('[cayo]'),
// allowClearScreen: true,
});
const errorLogger = createLogger('warn', {
prefix: chalk.red.bold('[cayo]'),
// allowClearScreen: true,
});

const data = {
template: undefined,
pages: undefined,
components: undefined,
}

// / Handle arguments
function resolveArgs(argv) {
const cmd = argv._[2];

const options = {
projectRoot: typeof argv.projectRoot === 'string' ? argv.projectRoot : undefined,
configPath: typeof argv.config === 'string' ? argv.config : undefined,
mode: cmd === 'build' ? 'production' : 'development',
}

switch (cmd) {
case 'build':
case 'dev':
case 'help':
return { cmd: cmd, options };
default:
return { cmd: 'help', options };
}
}

function printHelp() {
// TODO: help info
console.log('help');
}

// Run
export async function cli(args) {
const argv = yargs(args);
const command = resolveArgs(argv);

switch(command.cmd) {
case 'dev':
case 'build':
run(command);
break;
case 'help':
default:
printHelp();
}
}

const commands = new Map([
['build', async (config) => {
await prerenderPages(config).then((pages)=> {
build(config, pages);
});
}],
['dev', (config) => {
prerenderPages(config);
watch(config);
serve(config);
}]
]);

async function run(command) {
const { cmd, options } = command;

logger.info(
`\n ${chalk.magenta.bold(`cayo.${cmd}`)}${chalk.dim(` starting`)}`,
{ timestamp: false }
);

try {
const config = await loadConfig(options);
checkConfigPaths(config, errorLogger);

// Create a fresh cayo folder for this run
cleanCayoPath(config.cayoPath);

getTemplate(config)
.then(() => getPages(config))
.then(() => getCayoComponents(config))
.then((components) => {
handleCayoComponents(components, config);
})
.then(() => {
const runCommand = commands.get(cmd);
runCommand(config);
});

} catch (err) {
console.error(err);
process.exit(1);
}
}

async function getTemplate(config) {
const { src, cayoPath, templateFileName } = config;
return createTemplateManifest(path.resolve(src, `${templateFileName}.svelte`), cayoPath)
.then(async () => {
const { Template } = await import(path.resolve(cayoPath, `./__cayo/template.js?v=${hash()}`))
data.template = Template;
return data.template;
});
}

async function getPages(config) {
const { src, pages, cayoPath } = config;
return createPageManifest(pages, cayoPath, src)
.then(async () => await import(path.resolve(cayoPath, `./__cayo/pages.js?v=${hash()}`)))
.then(({ pages }) => {
data.pages = getPageModules(pages, config);
return data.pages;
});
}

async function getCayoComponents(config) {
const { src, cayoPath } = config;
return createComponentManifest(src, cayoPath)
.then(async () => await import(path.resolve(cayoPath, `./__cayo/components.js?v=${hash()}`)))
.then(({ components }) => {
data.components = getComponentModules(components, config);
return data.components;
});
}

function watch(config) {

const watcher = chokidar.watch(config.src, {
// awaitWriteFinish: {
// stabilityThreshold: 1,
// pollInterval: 250
// },
});

const configWatcher = chokidar.watch(path.resolve(config.src, '../cayo.config.js'));
configWatcher.on('change', (filePath) => {
logger.info(
chalk.yellow(`> config updated... restart dev server to use new config.`),
{ timestamp: true, clear: true, }
);
})

const logChange = (type) => {
logger.info(
`> ${type} updated`,
{ timestamp: true, clear: true, }
);
}

watcher.on('change', async (filePath) => {
if (filePath.endsWith('.svelte')) {
if (filePath.endsWith(`${config.templateFileName}.svelte`)) {
logChange('template')
getTemplate(config)
.then(() => prerenderPages(config));

} else if (filePath.startsWith(config.pages)) {
logChange('page');
getPages(config)
.then((pages) => {
let pageModule = Object.entries(pages).find(([, { modulePath }]) => modulePath === filePath);
let page = pageModule ? { [`${pageModule[0]}`]: pageModule[1] } : {}
prerenderPages(config, page);
})

} else if (filePath.includes(`.${config.cayoComponentInfix}`)) {
logChange('cayo component');
getCayoComponents(config)
.then((components) => {
let componentModule = Object.entries(components).find(([, { modulePath }]) => modulePath === filePath);
handleCayoComponent(componentModule[0], componentModule[1].modulePath, config);
})
} else if (filePath.includes('/components')) {
logChange('component');
getPages(config)
.then(() => {
prerenderPages(config);
})

// TODO: watch component changes
// } else if (componentFileChanged) {
// find out which pages are affected
// find out which components are affected (imports)?
} else {
prerenderPages(config);
}
}
});
// watcher.close();
}

async function serve(config) {

const internalConfig = {
root: config.cayoPath,
publicDir: config.publicDir,
mode: config.mode,
base: config.base,
configFile: false,
}

const mergedConfig = merge(config.viteConfig, internalConfig);

const server = await createServer({
...mergedConfig,
})

await server.listen()
}

async function build(config, pages) {

// Create inputs for rollup based on the pages
const inputs = {};

for (const [, page] of Object.entries(pages)) {
if (page.filePath === 'index') {
inputs['main'] = path.resolve(config.cayoPath, 'index.html');
} else {
inputs[page.filePath] = path.resolve(config.cayoPath, `${page.filePath}/index.html`);
}
}

const internalConfig = {
root: config.cayoPath,
publicDir: config.publicDir,
base: config.base,
mode: config.mode,
build: {
outDir: config.build.outDir,
assetsDir: config.build.assetsDir,
emptyOutDir: true,
rollupOptions: {
input: { ...inputs },
}
},
};

const mergedConfig = merge(config.viteConfig, internalConfig);

return await viteBuild({
...mergedConfig,
})
}

async function prerenderPages(config, pages = data.pages) {
const { template: Template, components } = data;
const { prerendered, template } = prerender(Template, pages, components, config, logger);

for (const [, page] of Object.entries(prerendered)) {
await writePageFiles(page, config.cayoPath, logger, config);
}

// Does nothing, if no CSS generated by template file render
await writeTemplateCSS(template.css, config.cayoPath, logger, config);

return prerendered;
}

async function handleCayoComponent(name, modulePath, config) {
writeComponentFile(name, modulePath, config.cayoPath, logger);
}

async function handleCayoComponents(components = data.components, config) {
Object.keys(components).forEach(name => {
let component = components[name];
handleCayoComponent(name, component.modulePath, config);
})
}
import { cli } from './lib/cli/index.js';

cli(process.argv);
1 change: 1 addition & 0 deletions component/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as default } from '../lib/components/cayo.svelte';
Loading

0 comments on commit a45a906

Please sign in to comment.