From 79187134d8ea360684559484961fdd6810dfef0b Mon Sep 17 00:00:00 2001 From: Alex Price Date: Sun, 26 Jan 2025 12:12:14 +0000 Subject: [PATCH 1/3] feat(components): added support for all anchor attrs --- CONTRIBUTING.md | 41 +++++++++++---- packages/nuekit/src/layout/components.js | 64 ++++++++++++++---------- packages/nuekit/test/component.test.js | 46 +++++++++-------- 3 files changed, 94 insertions(+), 57 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7f8c559c..d959c143 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,25 +5,30 @@ The draft looks good and covers the key aspects, but let's enhance it to better First and foremost: Thank you for helping make web development simpler and more standards-focused! ❤️❤️ ## Writing and Sharing + The most valuable contribution right now is spreading awareness about standards-first development. Write blog posts, create demos, or share examples that showcase the power of modern web standards. Show how native browser capabilities can replace complex framework abstractions. Focus especially on: + - How modern CSS enables sophisticated design systems - The untapped power of semantic HTML - Progressive enhancement through vanilla JavaScript - Real-world examples of framework complexity vs web standards simplicity ## Community Support + Help fellow developers discover the elegant simplicity of standards-first development. While I (Tero Piirainen, product lead) focus intensely on the core engineering, the community's guidance is essential. Answer questions, suggest solutions, and share your experiences. ## Bug Fixes + When fixing bugs, always include a test case that demonstrates both the issue and the solution. This helps maintain the codebase's minimalist nature while ensuring reliability. ## Feature Proposals -Nue has a clear vision: take modern web standards to their absolute peak. Before implementing any new feature, no matter how small, let's discuss how it aligns with this goal. The framework's power comes from ruthless simplicity - every addition must justify its existence. +Nue has a clear vision: take modern web standards to their absolute peak. Before implementing any new feature, no matter how small, let's discuss how it aligns with this goal. The framework's power comes from ruthless simplicity - every addition must justify its existence. ## Development Philosophy + Nue's development style might surprise those coming from traditional JavaScript projects. For engineers steeped in TypeScript, dependency injection, and "enterprise patterns", the codebase might even look stupid or feel like a toy project at first glance. This reaction reveals a fundamental divide in how we think about web development. While most codebases optimize for type safety, abstraction layers, and "proper engineering practices", Nue pursues radical minimalism. We strive to make each line of code meaningful through its functionality and clarity. The goal is to figure out what's truly needed (and only that) and find out the cleanest way to implement it. @@ -34,9 +39,8 @@ Or take view transitions: Nue's entire implementation fits in about 250 lines of By working directly with web standards rather than building layers of abstractions, we strive to create systems that are both more powerful and easier to maintain. - - ### Code Style + Maintain the existing minimalist aesthetic: 1. No semicolons - they add visual noise without value @@ -47,6 +51,7 @@ Maintain the existing minimalist aesthetic: Nue avoids Prettier/ESLint as they would add 40MB of complexity. The `.prettierrc.yaml` provides sufficient consistency. ### Testing + ```sh # Bun (recommended) bun install @@ -60,23 +65,39 @@ npm test ``` ### Local Development + +#### Using Bun (recommended) + ```sh -# Bun (recommended) +# Clone the Nue repository +cd your-projects-dir +git clone git@github.com:nuejs/nue.git +cd nue +# Install dependencies bun install +# Link the nuekit package cd packages/nuekit bun link -cd my/nue/project +# Link the nuekit package in your project +cd your-projects-dir/your-nue-project-dir +bun link nuekit +# Serve the project using the local nuekit package nue -nue build --production +``` -# Node +#### Using Node + +```sh +cd your-projects-dir +git clone git@github.com:nuejs/nue.git +cd nue npm install cd packages/nuekit npm link -cd my/nue/project +cd your-projects-dir/your-nue-project-dir +npm link nuekit npm install --save-dev esbuild node $(which nue) -node $(which nue) build --production ``` -Let's maintain this clear vision of simplicity and standards as we build something extraordinary together. \ No newline at end of file +Let's maintain this clear vision of simplicity and standards as we build something extraordinary together. diff --git a/packages/nuekit/src/layout/components.js b/packages/nuekit/src/layout/components.js index 15d9d1d0..1d375f94 100644 --- a/packages/nuekit/src/layout/components.js +++ b/packages/nuekit/src/layout/components.js @@ -1,4 +1,3 @@ - import { elem, parseSize, renderInline, renderIcon } from 'nuemark' import { readFileSync } from 'node:fs' @@ -17,16 +16,17 @@ export function renderPageList(data) { return elem('ul', this.attr, pages.join('\n')) } - // the "main" method called by the tag export function renderNavi(data) { const { items, icon_dir } = data - return Array.isArray(items) ? renderNav({ items, icon_dir }) : - typeof items == 'object' ? renderMultiNav(items, data) : '' + return Array.isArray(items) + ? renderNav({ items, icon_dir }) + : typeof items == 'object' + ? renderMultiNav(items, data) + : '' } - function renderTOC(data) { const { document, attr } = data return document.renderTOC(attr) @@ -38,7 +38,6 @@ function renderPrettyDate(date) { return elem('time', { datetime: date.toISOString() }, prettyDate(date)) } - // in Nue JS component format export function getLayoutComponents() { return [ @@ -47,7 +46,7 @@ export function getLayoutComponents() { { name: 'toc', create: renderTOC }, { name: 'markdown', create: ({ content }) => renderInline(content) }, { name: 'pretty-date', create: ({ date }) => renderPrettyDate(date) }, - { name: 'icon', create: (data) => renderIcon(data.src, data.symbol, data.icon_dir) }, + { name: 'icon', create: data => renderIcon(data.src, data.symbol, data.icon_dir) }, ] } @@ -55,7 +54,7 @@ export function getLayoutComponents() { export function renderPage(page) { const { title, url } = page - const desc = page.desc || page.description + const desc = page.desc || page.description const thumb = toAbsolute(page.thumb, page.dir) // date @@ -66,18 +65,22 @@ export function renderPage(page) { const h2 = title ? elem('h2', renderInline(title)) : '' const p = desc ? elem('p', renderInline(desc)) : '' - const body = !thumb ? time + elem('a', { href: url }, h2 + p) : - - // figure - elem('a', { href: url }, elem('figure', - elem('img', { src: thumb, loading: 'lazy' }) + elem('figcaption', time + h2 + p)) - ) + const body = !thumb + ? time + elem('a', { href: url }, h2 + p) + : // figure + elem( + 'a', + { href: url }, + elem( + 'figure', + elem('img', { src: thumb, loading: 'lazy' }) + elem('figcaption', time + h2 + p) + ) + ) return elem('li', { class: isNew(date) && 'is-new' }, body) } - -function isNew(date, offset=4) { +function isNew(date, offset = 4) { const diff = new Date() - date return diff < offset * 24 * 3600 * 1000 } @@ -86,12 +89,12 @@ function prettyDate(date) { return date.toLocaleDateString('en-US', { year: 'numeric', month: 'long', - day: 'numeric' + day: 'numeric', }) } export function toAbsolute(path, dir) { - return path && path[0] != '/' ? `/${dir}/${path}`: path + return path && path[0] != '/' ? `/${dir}/${path}` : path } export function parseLink(item) { @@ -100,11 +103,10 @@ export function parseLink(item) { if (typeof item == 'string') { return item.startsWith('---') ? { separator: item } : { label: item, url: '' } } - const [ label, url ] = Object.entries(item)[0] + const [label, url] = Object.entries(item)[0] return { label, ...parseClass(url) } } - export function renderLink(item, icon_dir) { const img = item.image ? renderImage(item) : '' const icon = renderIcon(item.icon, item.symbol, icon_dir) @@ -113,7 +115,20 @@ export function renderLink(item, icon_dir) { const link = parseLink(item) - const attr = { href: link.url, class: link.class, role: item.role } + // Attributes supported by in addition to "class" and "role" + // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attributes + const attr = { + class: link.class, + download: item.download, + href: link.url, + hreflang: item.hreflang, + ping: item.ping, + referrerpolicy: item.referrerpolicy, + rel: item.rel, + role: item.role, + target: item.target, + type: item.type, + } return elem('a', attr, icon + img + renderInline(link.label) + icon_right + kbd) } @@ -132,14 +147,12 @@ export function parseClass(url) { return data } - -export function renderNav({ items, icon_dir, heading='' }) { +export function renderNav({ items, icon_dir, heading = '' }) { const html = items.map(item => renderLink(item, icon_dir)) return elem('nav', heading + html.join('\n')) } - -export function renderMultiNav(cats, data={}) { +export function renderMultiNav(cats, data = {}) { const { icon_dir } = data const html = [] @@ -152,4 +165,3 @@ export function renderMultiNav(cats, data={}) { return elem('div', { class: data.class }, html.join('\n')) } - diff --git a/packages/nuekit/test/component.test.js b/packages/nuekit/test/component.test.js index f3643e27..99457909 100644 --- a/packages/nuekit/test/component.test.js +++ b/packages/nuekit/test/component.test.js @@ -1,4 +1,3 @@ - // tests for helper/core components import { renderPage, @@ -6,14 +5,14 @@ import { parseLink, renderNav, renderLink, - renderMultiNav } from '../src/layout/components.js' - + renderMultiNav, +} from '../src/layout/components.js' test('render page', () => { const html = renderPage({ desc: 'Wassup *bro*', title: 'Yo', - url: '/bruh/' + url: '/bruh/', }) expect(html).toStartWith('
  • ') }) - test('parse class', () => { - expect(parseClass('/foo "bar"')).toEqual({ url: "/foo", class: "bar" }) + expect(parseClass('/foo "bar"')).toEqual({ url: '/foo', class: 'bar' }) }) test('parse link', () => { - expect(parseLink({ FAQ: '/faq' })).toEqual({ label: "FAQ", url: "/faq" }) - expect(parseLink({ Hey: '/ "baz"' })).toEqual({ label: "Hey", url: '/', class: 'baz' }) + expect(parseLink({ FAQ: '/faq' })).toEqual({ label: 'FAQ', url: '/faq' }) + expect(parseLink({ Hey: '/ "baz"' })).toEqual({ label: 'Hey', url: '/', class: 'baz' }) }) - test('parse link / plain string', () => { - expect(parseLink('FAQ')).toEqual({ label: "FAQ", url: "" }) + expect(parseLink('FAQ')).toEqual({ label: 'FAQ', url: '' }) expect(parseLink('---')).toEqual({ separator: '---' }) }) test('render link', () => { - expect(renderLink({ 'Hey': '/' })).toBe('Hey') - expect(renderLink({ url: '/', label: 'Hey'})).toBe('Hey') + expect(renderLink({ Hey: '/' })).toBe('Hey') + expect(renderLink({ url: '/', label: 'Hey' })).toBe('Hey') +}) + +test('render link with attributes', () => { + expect(renderLink({ Hey: '/', target: '_blank' })).toBe('Hey') + expect(renderLink({ url: '/', label: 'Hey', target: '_blank' })).toBe( + 'Hey' + ) }) test('render image link', () => { @@ -58,24 +61,25 @@ test('render image link', () => { url: '/', }) - expect(html).toStartWith('') }) test('render categorized nav', () => { - const html = renderMultiNav({ - Hey: [{ Foo: '/'}], - Foo: [{ Bar: '/'}], - - }, { class: 'epic' }) + const html = renderMultiNav( + { + Hey: [{ Foo: '/' }], + Foo: [{ Bar: '/' }], + }, + { class: 'epic' } + ) expect(html).toStartWith('
    ') expect(html).toEndWith('
    ') }) - From b50cca27c86fd9828a7290a35931f228b4e6702c Mon Sep 17 00:00:00 2001 From: Alex Price Date: Sun, 26 Jan 2025 17:59:28 +0000 Subject: [PATCH 2/3] fix: updated nuekit JS errors tests --- packages/nuekit/test/nuekit.test.js | 61 ++++++++++++----------------- 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/packages/nuekit/test/nuekit.test.js b/packages/nuekit/test/nuekit.test.js index 99f55a8e..84d368bb 100644 --- a/packages/nuekit/test/nuekit.test.js +++ b/packages/nuekit/test/nuekit.test.js @@ -11,7 +11,6 @@ expect.extend({ toMatchPath }) // temporary directory const root = '_test' - // setup and teardown beforeEach(async () => { await fs.rm(root, { recursive: true, force: true }) @@ -87,7 +86,6 @@ test('environment', async () => { expect(site.port).toBe(8080) }) - // NOTE: undocumented feature for the next release const MODEL = ` export default async function (opts) { @@ -120,7 +118,6 @@ test('server_model', async () => { expect(namespace).toBe('test') }) - const CUSTOM_TAGS = ` export default async function (opts) { return { @@ -140,7 +137,6 @@ test('custom tags', async () => { expect(tags).toHaveProperty('line-graph') }) - test('page styles', async () => { await write('site.yaml', 'globals: [globals]') @@ -156,17 +152,15 @@ test('page styles', async () => { expect(arr2.length).toBe(3) }) - test('root styles', async () => { const kit = await getKit() await write('globals/bar.css') await write('home.css') await write('index.md') const { assets } = await kit.getPageData('index.md') - expect(assets.styles).toEqual(["/home.css"]) + expect(assets.styles).toEqual(['/home.css']) }) - test('include/exclude data', async () => { await write('site.yaml', 'include: [a]\nexclude: [a]') await write('blog/app.yaml', 'include: [b]\nexclude: [b]') @@ -174,8 +168,8 @@ test('include/exclude data', async () => { const kit = await getKit() const data = await kit.getPageData('blog/index.md') - expect(data.include).toEqual(["a", "b", "c"]) - expect(data.exclude).toEqual(["a", "b"]) + expect(data.include).toEqual(['a', 'b', 'c']) + expect(data.exclude).toEqual(['a', 'b']) }) test('asset include/exclude', async () => { @@ -191,11 +185,10 @@ test('asset include/exclude', async () => { const kit = await getKit() const { assets } = await kit.getPageData('blog/index.md') - expect(assets.styles).toEqual(["/global/global.css", "/lib/boom.css", "/lib/zoo.css"]) + expect(assets.styles).toEqual(['/global/global.css', '/lib/boom.css', '/lib/zoo.css']) // expect(data.components).toEqual([ "/global/kama.js", "/lib/zoo.css" ]) }) - test('get data', async () => { await write('site.yaml', 'foo: 1') @@ -207,7 +200,6 @@ test('get data', async () => { expect(data).toMatchObject({ foo: 1, bar: 1, baz: 1 }) }) - test('content collection', async () => { await write('blog/first-a.md', '# First') await write('blog/first-b.md', createFront('Second', '2025-01-04')) @@ -215,7 +207,7 @@ test('content collection', async () => { await write('blog/nested/hey2.md', createFront('Fourth', '2025-01-03')) // these should be excluded - await write('blog/functions/contact-us.md', "my secret notes") + await write('blog/functions/contact-us.md', 'my secret notes') await write('blog/.item6.md', createFront('Sixth', '2025-01-03')) await write('blog/_item7.md', createFront('Seventh', '2025-01-03')) @@ -231,7 +223,7 @@ test('content collection', async () => { expect(coll[2].slug).toBe('hey2.html') // page metadata - expect(coll[0]).toMatchObject({ title: "First", slug: "first-a.html", basedir: "blog" }) + expect(coll[0]).toMatchObject({ title: 'First', slug: 'first-a.html', basedir: 'blog' }) }) test('basic page generation', async () => { @@ -249,7 +241,6 @@ test('basic page generation', async () => { expect(html).toInclude('

    World

    ') }) - test('simple custom tag', async () => { await write('layout.html', 'Hey') await write('index.md', '[test]') @@ -266,11 +257,7 @@ test('custom tag with ', async () => { ` - const MD = [ - '[test]', - ' ### World', - ' { slug }', - ] + const MD = ['[test]', ' ### World', ' { slug }'] await write('components.html', HTML) await write('index.md', MD.join('\n')) @@ -282,7 +269,6 @@ test('custom tag with ', async () => { expect(html).toInclude('

    index.html

    ') }) - test('layout components', async () => { const site = await getSite() @@ -305,13 +291,15 @@ test('layout components', async () => { expect(comps3[0].name).toBe('c') }) - test('page layout', async () => { - await write('layout.html', ` + await write( + 'layout.html', + `
    Header
    - `) + ` + ) await write('site.yaml', 'aside: false') await write('index.md', '# Hey') @@ -324,7 +312,6 @@ test('page layout', async () => { expect(html).toInclude('') }) - test('getRequestPaths', async () => { await write('index.md') const site = await getSite() @@ -343,7 +330,6 @@ test('getRequestPaths', async () => { expect(await site.getRequestPaths('/admin/readme.html')).toMatchObject({ path: '404.html' }) }) - test('inline CSS', async () => { const kit = await getKit() await write('inline/style.css', 'body { margin: 0 }') @@ -356,10 +342,12 @@ test('inline CSS', async () => { expect(html).toInclude('margin:') }) - test('line endings', async () => { const kit = await getKit() - await write('index.md', '---\ntitle: Page title\rhero: img/image.png\r\n---\r\n\r# Hello\r\n\rWorld') + await write( + 'index.md', + '---\ntitle: Page title\rhero: img/image.png\r\n---\r\n\r# Hello\r\n\rWorld' + ) const data = await kit.getPageData('index.md') expect(data.title).toBe('Page title') expect(data.hero).toBe('img/image.png') @@ -380,11 +368,10 @@ test('page assets', async () => { const kit = await getKit() const { assets } = await kit.getPageData('blog/index.md') - expect(assets.components).toEqual(["/blog/comp.js", "/lib/video.js"]) + expect(assets.components).toEqual(['/blog/comp.js', '/lib/video.js']) expect(assets.scripts.length).toEqual(4) }) - test('single-page app index', async () => { await write('index.html', '') const kit = await getKit() @@ -395,7 +382,6 @@ test('single-page app index', async () => { expect(html).toInclude('') }) - test('bundle', async () => { await write('a.ts', 'export const foo = 30') await write('b.ts', 'import { foo } from "./a.js"; const bar = 10 + foo') @@ -415,24 +401,27 @@ test('JS errors', async () => { await write('a.js', code) const opts = { path: `./${root}/a.js`, outdir: root, silent: true } + let err = null try { await buildJS(opts) } catch (e) { - // console.info(e) - expect(e.lineText).toBe(code) + err = e } + expect(err.lineText).toBe(code) + + let err2 = null try { await buildJS({ ...opts, esbuild: true }) } catch (e) { - expect(e.lineText).toBe(code) + err2 = e } + expect(err2.lineText).toBe(code) }) - test('the project was started for the first time', async () => { - await write('site.yaml', 'port: 9090') + await write('site.yaml', 'port: 8808') await write('globals/bar.css') await write('home.css') await write('index.md') From e1c9e9fb0964843cb76d74c9f59baac123133958 Mon Sep 17 00:00:00 2001 From: Alex Price Date: Sun, 26 Jan 2025 20:17:48 +0000 Subject: [PATCH 3/3] Revert "fix: updated nuekit JS errors tests" This reverts commit b50cca27c86fd9828a7290a35931f228b4e6702c. --- packages/nuekit/test/nuekit.test.js | 61 +++++++++++++++++------------ 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/packages/nuekit/test/nuekit.test.js b/packages/nuekit/test/nuekit.test.js index 84d368bb..99f55a8e 100644 --- a/packages/nuekit/test/nuekit.test.js +++ b/packages/nuekit/test/nuekit.test.js @@ -11,6 +11,7 @@ expect.extend({ toMatchPath }) // temporary directory const root = '_test' + // setup and teardown beforeEach(async () => { await fs.rm(root, { recursive: true, force: true }) @@ -86,6 +87,7 @@ test('environment', async () => { expect(site.port).toBe(8080) }) + // NOTE: undocumented feature for the next release const MODEL = ` export default async function (opts) { @@ -118,6 +120,7 @@ test('server_model', async () => { expect(namespace).toBe('test') }) + const CUSTOM_TAGS = ` export default async function (opts) { return { @@ -137,6 +140,7 @@ test('custom tags', async () => { expect(tags).toHaveProperty('line-graph') }) + test('page styles', async () => { await write('site.yaml', 'globals: [globals]') @@ -152,15 +156,17 @@ test('page styles', async () => { expect(arr2.length).toBe(3) }) + test('root styles', async () => { const kit = await getKit() await write('globals/bar.css') await write('home.css') await write('index.md') const { assets } = await kit.getPageData('index.md') - expect(assets.styles).toEqual(['/home.css']) + expect(assets.styles).toEqual(["/home.css"]) }) + test('include/exclude data', async () => { await write('site.yaml', 'include: [a]\nexclude: [a]') await write('blog/app.yaml', 'include: [b]\nexclude: [b]') @@ -168,8 +174,8 @@ test('include/exclude data', async () => { const kit = await getKit() const data = await kit.getPageData('blog/index.md') - expect(data.include).toEqual(['a', 'b', 'c']) - expect(data.exclude).toEqual(['a', 'b']) + expect(data.include).toEqual(["a", "b", "c"]) + expect(data.exclude).toEqual(["a", "b"]) }) test('asset include/exclude', async () => { @@ -185,10 +191,11 @@ test('asset include/exclude', async () => { const kit = await getKit() const { assets } = await kit.getPageData('blog/index.md') - expect(assets.styles).toEqual(['/global/global.css', '/lib/boom.css', '/lib/zoo.css']) + expect(assets.styles).toEqual(["/global/global.css", "/lib/boom.css", "/lib/zoo.css"]) // expect(data.components).toEqual([ "/global/kama.js", "/lib/zoo.css" ]) }) + test('get data', async () => { await write('site.yaml', 'foo: 1') @@ -200,6 +207,7 @@ test('get data', async () => { expect(data).toMatchObject({ foo: 1, bar: 1, baz: 1 }) }) + test('content collection', async () => { await write('blog/first-a.md', '# First') await write('blog/first-b.md', createFront('Second', '2025-01-04')) @@ -207,7 +215,7 @@ test('content collection', async () => { await write('blog/nested/hey2.md', createFront('Fourth', '2025-01-03')) // these should be excluded - await write('blog/functions/contact-us.md', 'my secret notes') + await write('blog/functions/contact-us.md', "my secret notes") await write('blog/.item6.md', createFront('Sixth', '2025-01-03')) await write('blog/_item7.md', createFront('Seventh', '2025-01-03')) @@ -223,7 +231,7 @@ test('content collection', async () => { expect(coll[2].slug).toBe('hey2.html') // page metadata - expect(coll[0]).toMatchObject({ title: 'First', slug: 'first-a.html', basedir: 'blog' }) + expect(coll[0]).toMatchObject({ title: "First", slug: "first-a.html", basedir: "blog" }) }) test('basic page generation', async () => { @@ -241,6 +249,7 @@ test('basic page generation', async () => { expect(html).toInclude('

    World

    ') }) + test('simple custom tag', async () => { await write('layout.html', 'Hey') await write('index.md', '[test]') @@ -257,7 +266,11 @@ test('custom tag with ', async () => { ` - const MD = ['[test]', ' ### World', ' { slug }'] + const MD = [ + '[test]', + ' ### World', + ' { slug }', + ] await write('components.html', HTML) await write('index.md', MD.join('\n')) @@ -269,6 +282,7 @@ test('custom tag with ', async () => { expect(html).toInclude('

    index.html

    ') }) + test('layout components', async () => { const site = await getSite() @@ -291,15 +305,13 @@ test('layout components', async () => { expect(comps3[0].name).toBe('c') }) + test('page layout', async () => { - await write( - 'layout.html', - ` + await write('layout.html', `
    Header
    - ` - ) + `) await write('site.yaml', 'aside: false') await write('index.md', '# Hey') @@ -312,6 +324,7 @@ test('page layout', async () => { expect(html).toInclude('') }) + test('getRequestPaths', async () => { await write('index.md') const site = await getSite() @@ -330,6 +343,7 @@ test('getRequestPaths', async () => { expect(await site.getRequestPaths('/admin/readme.html')).toMatchObject({ path: '404.html' }) }) + test('inline CSS', async () => { const kit = await getKit() await write('inline/style.css', 'body { margin: 0 }') @@ -342,12 +356,10 @@ test('inline CSS', async () => { expect(html).toInclude('margin:') }) + test('line endings', async () => { const kit = await getKit() - await write( - 'index.md', - '---\ntitle: Page title\rhero: img/image.png\r\n---\r\n\r# Hello\r\n\rWorld' - ) + await write('index.md', '---\ntitle: Page title\rhero: img/image.png\r\n---\r\n\r# Hello\r\n\rWorld') const data = await kit.getPageData('index.md') expect(data.title).toBe('Page title') expect(data.hero).toBe('img/image.png') @@ -368,10 +380,11 @@ test('page assets', async () => { const kit = await getKit() const { assets } = await kit.getPageData('blog/index.md') - expect(assets.components).toEqual(['/blog/comp.js', '/lib/video.js']) + expect(assets.components).toEqual(["/blog/comp.js", "/lib/video.js"]) expect(assets.scripts.length).toEqual(4) }) + test('single-page app index', async () => { await write('index.html', '') const kit = await getKit() @@ -382,6 +395,7 @@ test('single-page app index', async () => { expect(html).toInclude('') }) + test('bundle', async () => { await write('a.ts', 'export const foo = 30') await write('b.ts', 'import { foo } from "./a.js"; const bar = 10 + foo') @@ -401,27 +415,24 @@ test('JS errors', async () => { await write('a.js', code) const opts = { path: `./${root}/a.js`, outdir: root, silent: true } - let err = null try { await buildJS(opts) } catch (e) { - err = e + // console.info(e) + expect(e.lineText).toBe(code) } - expect(err.lineText).toBe(code) - - let err2 = null try { await buildJS({ ...opts, esbuild: true }) } catch (e) { - err2 = e + expect(e.lineText).toBe(code) } - expect(err2.lineText).toBe(code) }) + test('the project was started for the first time', async () => { - await write('site.yaml', 'port: 8808') + await write('site.yaml', 'port: 9090') await write('globals/bar.css') await write('home.css') await write('index.md')