Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ npx makes aurelia

This will cause `npx` to download the `makes` tool, along with the `aurelia` scaffold from this repo, which it will use to guide you through creating your project.

## Presets and samples

Use the preset picker to quickly choose a profile, including **Lean Modern Frontend** (TypeScript + Vite + Tailwind + Vitest + Storybook). When picking sample code, you can select **Blank app** for a clean, empty app shell (no demo markup) or use the minimal/router samples as before.

## Plugin projects (Vite + Webpack)

Plugin templates support Vite or Webpack. The Vite plugin build uses Vite's library mode (Rollup under the hood) and injects component CSS into the JS bundle so consumers don't need to import a separate CSS file. The dev-app still runs on the selected bundler for local testing.

## Development

There are some tests for this skeleton, setup in package.json. (totally not required by makes)
Expand Down
45 changes: 45 additions & 0 deletions __test__/after-task.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
const test = require('ava');
const fs = require('fs');
const os = require('os');
const path = require('path');
const after = require('../after');

const ansiColors = (m) => m;
Expand Down Expand Up @@ -196,6 +199,48 @@ test('"after" task installs deps with pnpm, and prints summary', async t => {
);
});

test.serial('"after" task writes pnpm .npmrc when pnpm is selected', async t => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'aurelia-pnpm-'));
const cwd = process.cwd();
t.teardown(() => {
process.chdir(cwd);
fs.rmSync(tempDir, {recursive: true, force: true});
});
process.chdir(tempDir);

const prompts = {
select(opts) {
t.deepEqual(opts.choices.map(c => c.value), ['npm', 'yarn', 'pnpm', undefined]);
return 'pnpm';
}
};

function run(cmd, args) {
t.is(cmd, 'pnpm');
t.deepEqual(args, ['install']);
}

await after({
unattended: false,
here: true,
prompts,
run,
properties: {name: 'my-app'},
features: [],
notDefaultFeatures: [],
ansiColors
}, {
_isAvailable: isAvailable,
_log() {}
});

const npmrcPath = path.join(tempDir, '.npmrc');
t.true(fs.existsSync(npmrcPath));
const content = fs.readFileSync(npmrcPath, 'utf8');
t.true(content.includes('shamefully-hoist=true'));
t.true(content.includes('auto-install-peers=true'));
});

test('"after" task installs deps, and prints summary in here mode', async t => {
const prompts = {
select(opts) {
Expand Down
49 changes: 46 additions & 3 deletions __test__/before-task.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,50 @@ test('"before" task can select default-typescript preset', async t => {
});
});

test('"before" task can select minimal-esnext preset', async t => {
const prompts = {
select(opts) {
t.truthy(opts.choices.find(c => c.value === 'minimal-esnext'));
return 'minimal-esnext';
}
};

const result = await before({unattended: false, prompts});
t.deepEqual(result, {
silentQuestions: true,
preselectedFeatures: ['app', 'vite', 'babel', 'no-unit-tests', 'app-blank', 'css']
});
});

test('"before" task can select minimal-typescript preset', async t => {
const prompts = {
select(opts) {
t.truthy(opts.choices.find(c => c.value === 'minimal-typescript'));
return 'minimal-typescript';
}
};

const result = await before({unattended: false, prompts});
t.deepEqual(result, {
silentQuestions: true,
preselectedFeatures: ['app', 'vite', 'typescript', 'no-unit-tests', 'app-blank', 'css']
});
});

test('"before" task can select lean-modern-frontend preset', async t => {
const prompts = {
select(opts) {
t.truthy(opts.choices.find(c => c.value === 'lean-modern-frontend'));
return 'lean-modern-frontend';
}
};

const result = await before({unattended: false, prompts});
t.deepEqual(result, {
silentQuestions: true,
preselectedFeatures: ['app', 'vite', 'typescript', 'vitest', 'tailwindcss', 'storybook', 'app-min']
});
});
test('"before" task can select default-esnext-plugin preset', async t => {
const prompts = {
select(opts) {
Expand All @@ -55,7 +99,7 @@ test('"before" task can select default-esnext-plugin preset', async t => {
const result = await before({ unattended: false, prompts });
t.deepEqual(result, {
silentQuestions: true,
preselectedFeatures: ['plugin', 'webpack', 'babel', 'shadow-dom', 'jest']
preselectedFeatures: ['plugin', 'vite', 'babel', 'shadow-dom', 'vitest']
});
});

Expand All @@ -72,7 +116,7 @@ test('"before" task can select default-typescript-plugin preset', async t => {
const result = await before({ unattended: false, prompts });
t.deepEqual(result, {
silentQuestions: true,
preselectedFeatures: ['plugin', 'webpack', 'typescript', 'shadow-dom', 'jest']
preselectedFeatures: ['plugin', 'vite', 'typescript', 'shadow-dom', 'vitest']
});
});
test('"before" task can select no preset', async t => {
Expand All @@ -88,4 +132,3 @@ test('"before" task can select no preset', async t => {
const result = await before({unattended: false, prompts});
t.is(result, undefined);
});

25 changes: 25 additions & 0 deletions after.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ const {execSync} = require('child_process');
const fs = require('fs');
const path = require('path');

const PNPM_NPMRC = `# for pnpm, use flat node_modules
shamefully-hoist=true
auto-install-peers=true
`;

function isAvailable(bin) {
try {
execSync(bin + ' -v', {stdio: 'ignore'});
Expand All @@ -23,6 +28,7 @@ module.exports = async function({
const c = ansiColors;
let depsInstalled = false;
let packageManager = undefined;
const projectDir = here ? '.' : properties.name;

if (!unattended) {
const choices = [ {value: 'npm', title: 'Yes, use npm'} ];
Expand All @@ -43,6 +49,9 @@ module.exports = async function({
});

if (packageManager) {
if (packageManager === 'pnpm') {
ensurePnpmrc(projectDir);
}
await run(packageManager, ['install']);

if (features.includes('playwright')) {
Expand Down Expand Up @@ -107,3 +116,19 @@ module.exports = async function({
}
_log((packageManager ?? 'npm') + ' start\n');
};

function ensurePnpmrc(projectDir) {
if (!projectDir || !fs.existsSync(projectDir)) return;

const npmrcPath = path.join(projectDir, '.npmrc');
if (!fs.existsSync(npmrcPath)) {
fs.writeFileSync(npmrcPath, PNPM_NPMRC);
return;
}

const existing = fs.readFileSync(npmrcPath, 'utf8');
if (existing.includes('shamefully-hoist=') && existing.includes('auto-install-peers=')) return;

const spacer = existing.endsWith('\n') ? '' : '\n';
fs.writeFileSync(npmrcPath, existing + spacer + PNPM_NPMRC);
}
2 changes: 2 additions & 0 deletions app-blank/src/my-app.ext
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export class MyApp {
}
1 change: 1 addition & 0 deletions app-blank/src/my-app.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div>Delete me</div>>
29 changes: 29 additions & 0 deletions app-blank/src/my-app.stories.ext__if_storybook
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* @if vite */
import { MyApp } from './my-app';

const meta = {
title: 'Example/MyApp',
component: MyApp,
render: () => ({
template: `<my-app></my-app>`,
})
};

export default meta;

export const Default = {};
/* @endif */
/* @if webpack */
import { MyApp } from './my-app';

export default {
title: 'MyApp',
component: MyApp,
};

export const Default = () => ({
Component: MyApp,
template: '<my-app></my-app>',
props: {}
});
/* @endif */
20 changes: 20 additions & 0 deletions app-blank/test__if_not_no-unit-tests/my-app.spec.ext
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @if vitest
import { describe, it } from 'vitest';
// @endif
import { MyApp } from '../src/my-app';
import { createFixture } from '@aurelia/testing';

describe('my-app', () => {
it('should render', async () => {
const { appHost } = await createFixture(
'<my-app></my-app>',
{},
[MyApp],
).started;

const element = appHost.querySelector('my-app');
if (element === null) {
throw new Error('Expected to find my-app element in host');
}
});
});
12 changes: 5 additions & 7 deletions app-min/src/my-app.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
<!-- @if tailwindcss -->
<div class="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 flex flex-col items-center justify-center p-8">
<div class="bg-white rounded-lg shadow-lg p-8 max-w-md w-full text-center">
<div class="text-3xl font-bold text-gray-800 mb-4">Welcome to Aurelia 2!</div>
<div class="text-gray-600 mb-6">You're now running <span class="font-semibold text-blue-600">${message}</span></div>
<div class="text-sm text-gray-500">Experience the power of Aurelia 2 with TailwindCSS</div>
<div class="mt-4 px-3 py-1 bg-blue-100 text-blue-800 rounded-full text-sm font-medium inline-block">Aurelia 2</div>
<div class="min-h-screen flex items-center justify-center p-6 bg-gray-50">
<div class="text-center">
<h1 class="text-3xl font-bold text-gray-900">${message}</h1>
<p class="mt-2 text-gray-600">Aurelia 2 + TailwindCSS</p>
<!-- @if shadow-dom -->
<div class="mt-6 p-4 bg-gradient-to-r from-purple-500 to-pink-500 rounded-lg text-white">
<div class="mt-6 p-3 border rounded bg-white">
<div class="shared-shadow-style">
<div class="shared-shadow-text">This content uses shared Shadow DOM styles!</div>
</div>
Expand Down
20 changes: 3 additions & 17 deletions app-with-router/src/about-page.html
Original file line number Diff line number Diff line change
@@ -1,21 +1,7 @@
<!-- @if tailwindcss -->
<div class="bg-white rounded-lg shadow p-6">
<h1 class="text-3xl font-bold text-gray-900 mb-4">About</h1>
<div class="prose prose-blue max-w-none">
<p class="text-gray-600 leading-relaxed">
This is a sample Aurelia application showcasing the integration of TailwindCSS with the Aurelia framework.
The combination provides a powerful development experience with utility-first CSS styling.
</p>
<div class="mt-6 p-4 bg-gradient-to-r from-blue-50 to-indigo-50 rounded-lg border border-blue-200">
<h3 class="text-lg font-semibold text-blue-900 mb-2">Features</h3>
<ul class="text-blue-800 space-y-1">
<li>• Aurelia 2 with modern web standards</li>
<li>• TailwindCSS for utility-first styling</li>
<li>• Responsive design out of the box</li>
<li>• Fast development workflow</li>
</ul>
</div>
</div>
<div class="bg-white rounded-md border p-4">
<h1 class="text-2xl font-semibold text-gray-900 mb-2">About</h1>
<p class="text-gray-600">This page is routed via @aurelia/router.</p>
</div>
<!-- @endif -->
<!-- @if !tailwindcss -->
Expand Down
3 changes: 0 additions & 3 deletions app-with-router/src/missing-page.ext

This file was deleted.

12 changes: 0 additions & 12 deletions app-with-router/src/missing-page.html

This file was deleted.

1 change: 0 additions & 1 deletion app-with-router/src/my-app.ext
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { route } from '@aurelia/router';
title: 'About',
},
],
fallback: import('./missing-page'),
})
export class MyApp {
}
20 changes: 6 additions & 14 deletions app-with-router/src/my-app.html
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
<!-- @if tailwindcss -->
<div class="min-h-screen bg-gray-50">
<nav class="bg-white shadow">
<div class="max-w-7xl mx-auto px-4">
<div class="flex justify-between h-16">
<div class="flex space-x-8">
<a href="welcome" class="flex items-center px-3 py-2 text-sm font-medium text-gray-900 border-b-2 hover:border-indigo-500 hover:text-indigo-600 transition-colors">
Welcome
</a>
<a href="about" class="flex items-center px-3 py-2 text-sm font-medium text-gray-500 border-b-2 border-transparent hover:border-indigo-500 hover:text-indigo-600 transition-colors">
About
</a>
</div>
</div>
<nav class="bg-white border-b">
<div class="max-w-5xl mx-auto px-4 py-3 flex gap-4">
<a href="welcome" class="text-sm font-medium text-gray-900 hover:text-indigo-600">Welcome</a>
<a href="about" class="text-sm font-medium text-gray-600 hover:text-indigo-600">About</a>
</div>
</nav>

<main class="max-w-7xl mx-auto py-6 px-4">
<au-viewport class="min-h-[calc(100vh-8rem)]"></au-viewport>
<main class="max-w-5xl mx-auto p-4">
<au-viewport></au-viewport>
</main>
</div>
<!-- @endif -->
Expand Down
16 changes: 3 additions & 13 deletions app-with-router/src/welcome-page.html
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
<!-- @if tailwindcss -->
<div class="bg-white rounded-lg shadow p-6">
<h1 class="text-3xl font-bold text-gray-900 mb-4">${message}</h1>
<p class="text-gray-600 mb-6">Welcome to your Aurelia app with TailwindCSS and routing!</p>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="p-4 bg-blue-50 rounded-lg">
<h3 class="font-semibold text-blue-900 mb-2">Aurelia 2</h3>
<p class="text-blue-700 text-sm">Modern, powerful, and developer-friendly framework</p>
</div>
<div class="p-4 bg-indigo-50 rounded-lg">
<h3 class="font-semibold text-indigo-900 mb-2">TailwindCSS</h3>
<p class="text-indigo-700 text-sm">Utility-first CSS framework for rapid UI development</p>
</div>
</div>
<div class="bg-white rounded-md border p-4">
<h1 class="text-2xl font-semibold text-gray-900 mb-2">${message}</h1>
<p class="text-gray-600">Routing is configured and working.</p>
</div>
<!-- @endif -->
<!-- @if !tailwindcss -->
Expand Down
Loading