diff --git a/lib/presets/stencil/azion.config.js b/lib/presets/stencil/azion.config.js new file mode 100644 index 00000000..e568b77e --- /dev/null +++ b/lib/presets/stencil/azion.config.js @@ -0,0 +1,50 @@ +import { defineConfig } from 'azion/config'; + +const config = defineConfig({ + build: { + preset: { + name: 'stencil', + }, + }, + origin: [ + { + name: 'origin-storage-default', + type: 'object_storage', + }, + ], + + rules: { + request: [ + { + name: 'Set Storage Origin for All Requests', + match: '^\\/', + behavior: { + setOrigin: { + name: 'origin-storage-default', + type: 'object_storage', + }, + }, + }, + { + name: 'Deliver Static Assets', + match: '.(css|js|ttf|woff|woff2|pdf|svg|jpg|jpeg|gif|bmp|png|ico|mp4|json|xml|html)$', + behavior: { + setOrigin: { + name: 'origin-storage-default', + type: 'object_storage', + }, + deliver: true, + }, + }, + { + name: 'Redirect to index.html', + match: '^\\/', + behavior: { + rewrite: `/index.html`, + }, + }, + ], + }, +}); + +export default config; \ No newline at end of file diff --git a/lib/presets/stencil/config.js b/lib/presets/stencil/config.js new file mode 100644 index 00000000..92d99b6f --- /dev/null +++ b/lib/presets/stencil/config.js @@ -0,0 +1,10 @@ +/** + * Config to be used in build context. + */ +const config = { + builder: 'webpack', + polyfills: false, + custom: {}, +}; + +export default config; diff --git a/lib/presets/stencil/handler.js b/lib/presets/stencil/handler.js new file mode 100644 index 00000000..67981ba2 --- /dev/null +++ b/lib/presets/stencil/handler.js @@ -0,0 +1,17 @@ +import { mountSPA } from 'azion/utils'; + +/** + * Handles the 'fetch' event. + * @param {import('azion/types').FetchEvent} event - The fetch event. + * @returns {Promise} The response for the request. + */ +async function handler(event) { + try { + const myApp = await mountSPA(event.request.url); + return myApp; + } catch (e) { + return new Response('Not Found', { status: 404 }); + } +} + +export default handler; diff --git a/lib/presets/stencil/prebuild.js b/lib/presets/stencil/prebuild.js new file mode 100644 index 00000000..7b9416ed --- /dev/null +++ b/lib/presets/stencil/prebuild.js @@ -0,0 +1,21 @@ +import { rm } from 'fs/promises'; +import { exec, getPackageManager, copyDirectory } from '#utils'; + +const packageManager = await getPackageManager(); + +/** + * Runs custom prebuild actions + */ +async function prebuild() { + const newOutDir = '.edge/storage'; + const outDir = 'www'; + + await exec(`${packageManager} run build`, 'Stencil', true); + + // move files to vulcan default path + copyDirectory(outDir, newOutDir); + + rm(outDir, { recursive: true, force: true }); +} + +export default prebuild; diff --git a/lib/utils/presets/presets.utils.test.js b/lib/utils/presets/presets.utils.test.js index 323af1c5..f4a4de39 100644 --- a/lib/utils/presets/presets.utils.test.js +++ b/lib/utils/presets/presets.utils.test.js @@ -24,6 +24,7 @@ describe('getPresetsList utils', () => { 'nuxt', 'react', 'rustwasm', + 'stencil', 'svelte', 'typescript', 'vitepress', diff --git a/tests/e2e/stencil-static.test.js b/tests/e2e/stencil-static.test.js new file mode 100644 index 00000000..c9bc4388 --- /dev/null +++ b/tests/e2e/stencil-static.test.js @@ -0,0 +1,54 @@ +/* eslint-disable jest/expect-expect */ +import supertest from 'supertest'; +import puppeteer from 'puppeteer'; +import projectInitializer from '../utils/project-initializer.js'; +import projectStop from '../utils/project-stop.js'; +import { getContainerPort } from '../utils/docker-env-actions.js'; + +// timeout in minutes +const TIMEOUT = 10 * 60 * 1000; + +let serverPort; +let localhostBaseUrl; +const EXAMPLE_PATH = '/examples/stencil-app-boilerplate'; + +describe('E2E - stencil project', () => { + let request; + let browser; + let page; + + beforeAll(async () => { + serverPort = getContainerPort(); + localhostBaseUrl = `http://0.0.0.0:${serverPort}`; + + request = supertest(localhostBaseUrl); + + await projectInitializer(EXAMPLE_PATH, 'stencil', serverPort); + + browser = await puppeteer.launch({ headless: 'new' }); + page = await browser.newPage(); + }, TIMEOUT); + + afterAll(async () => { + await projectStop(serverPort, EXAMPLE_PATH.replace('/examples/', '')); + + await browser.close(); + }, TIMEOUT); + + test('Should render home page in "/" route', async () => { + await page.goto(`${localhostBaseUrl}/`); + + const pageContent = await page.content(); + const pageTitle = await page.title(); + + expect(pageContent).toContain('Welcome to the Stencil App Starter'); + expect(pageTitle).toBe('Stencil Starter App'); + }); + + test('Should return correct asset', async () => { + await request + .get('/assets/icon/icon.png') + .expect(200) + .expect('Content-Type', /image\/png/); + }); +});