diff --git a/.github/workflows/e2e-linux.yml b/.github/workflows/e2e-linux.yml
index 3f9770c..f2e6494 100644
--- a/.github/workflows/e2e-linux.yml
+++ b/.github/workflows/e2e-linux.yml
@@ -29,6 +29,8 @@ jobs:
- latest,parcel,typescript
- latest,dumber,babel
- latest,dumber,typescript
+ - latest,vite,babel
+ - latest,vite,typescript
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node_version }}
diff --git a/.github/workflows/e2e-macOS.yml b/.github/workflows/e2e-macOS.yml
index c145068..02a67c0 100644
--- a/.github/workflows/e2e-macOS.yml
+++ b/.github/workflows/e2e-macOS.yml
@@ -26,6 +26,8 @@ jobs:
- latest,parcel,typescript
- latest,dumber,babel
- latest,dumber,typescript
+ - latest,vite,babel
+ - latest,vite,typescript
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node_version }}
diff --git a/.github/workflows/e2e-windows.yml b/.github/workflows/e2e-windows.yml
index c784b7c..c5dfce4 100644
--- a/.github/workflows/e2e-windows.yml
+++ b/.github/workflows/e2e-windows.yml
@@ -26,6 +26,8 @@ jobs:
- latest,parcel,typescript
- latest,dumber,babel
- latest,dumber,typescript
+ - latest,vite,babel
+ - latest,vite,typescript
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node_version }}
diff --git a/__test__/before-task.spec.js b/__test__/before-task.spec.js
index d5af5f0..19576d2 100644
--- a/__test__/before-task.spec.js
+++ b/__test__/before-task.spec.js
@@ -23,7 +23,7 @@ test('"before" task can select default-esnext preset', async t => {
const result = await before({unattended: false, prompts});
t.deepEqual(result, {
silentQuestions: true,
- preselectedFeatures: ['app', 'webpack', 'babel', 'jest']
+ preselectedFeatures: ['app', 'vite', 'babel', 'vitest']
});
});
@@ -40,7 +40,7 @@ test('"before" task can select default-typescript preset', async t => {
const result = await before({unattended: false, prompts});
t.deepEqual(result, {
silentQuestions: true,
- preselectedFeatures: ['app', 'webpack', 'typescript', 'jest']
+ preselectedFeatures: ['app', 'vite', 'typescript', 'vitest']
});
});
diff --git a/__test__/transforms.spec.js b/__test__/transforms.spec.js
index f14f863..e03af2f 100644
--- a/__test__/transforms.spec.js
+++ b/__test__/transforms.spec.js
@@ -71,3 +71,67 @@ test.cb('ext-transform translates .ext file to .ts file when typescript is selec
contents: Buffer.from('
')
}));
});
+
+test.cb('ext-transform translates css files to .module.css files when css-module is selected', t => {
+ const jsExt = extTransform({}, ['css-module']);
+ const files = [];
+
+ jsExt.pipe(new Writable({
+ objectMode: true,
+ write(file, enc, cb) {
+ files.push(file);
+ cb();
+ }
+ }));
+
+ jsExt.on('end', () => {
+ t.is(files.length, 2);
+ t.is(files[0].path.replace(/\\/g, '/'), 'test/a.module.css');
+ t.is(files[0].contents.toString(), '.p { color: green; }');
+ t.is(files[1].path.replace(/\\/g, '/'), 'test/b.module.scss');
+ t.is(files[1].contents.toString(), '.p { color: red; }');
+ t.end();
+ })
+
+ jsExt.write(new Vinyl({
+ path: 'test/a.css',
+ contents: Buffer.from('.p { color: green; }')
+ }));
+
+ jsExt.end(new Vinyl({
+ path: 'test/b.scss',
+ contents: Buffer.from('.p { color: red; }')
+ }));
+});
+
+test.cb('ext-transform leaves css files untouched files when css-module is not selected', t => {
+ const jsExt = extTransform({}, ['']);
+ const files = [];
+
+ jsExt.pipe(new Writable({
+ objectMode: true,
+ write(file, enc, cb) {
+ files.push(file);
+ cb();
+ }
+ }));
+
+ jsExt.on('end', () => {
+ t.is(files.length, 2);
+ t.is(files[0].path.replace(/\\/g, '/'), 'test/a.css');
+ t.is(files[0].contents.toString(), '.p { color: green; }');
+ t.is(files[1].path.replace(/\\/g, '/'), 'test/b.scss');
+ t.is(files[1].contents.toString(), '.p { color: red; }');
+ t.end();
+ })
+
+ jsExt.write(new Vinyl({
+ path: 'test/a.css',
+ contents: Buffer.from('.p { color: green; }')
+ }));
+
+ jsExt.end(new Vinyl({
+ path: 'test/b.scss',
+ contents: Buffer.from('.p { color: red; }')
+ }));
+});
\ No newline at end of file
diff --git a/app-min/e2e__if_playwright/app.spec.ext__if_not_plugin b/app-min/e2e__if_playwright/app.spec.ext__if_not_plugin
index 9e747ef..ff58ddf 100644
--- a/app-min/e2e__if_playwright/app.spec.ext__if_not_plugin
+++ b/app-min/e2e__if_playwright/app.spec.ext__if_not_plugin
@@ -1,9 +1,4 @@
-// @if typescript
import { test, expect } from '@playwright/test';
-// @endif
-// @if babel
-const { test, expect } = require('@playwright/test');
-// @endif
test.beforeEach(async ({ page }) => {
await page.goto('http://localhost:9000');
diff --git a/app-min/test__if_not_no-unit-tests/my-app.spec.ext b/app-min/test__if_not_no-unit-tests/my-app.spec.ext
index 60350f5..bc8ccfc 100644
--- a/app-min/test__if_not_no-unit-tests/my-app.spec.ext
+++ b/app-min/test__if_not_no-unit-tests/my-app.spec.ext
@@ -1,6 +1,9 @@
// @if mocha
import { expect } from 'chai';
// @endif
+// @if vitest
+import { describe, it, expect } from 'vitest';
+// @endif
// @if shadow-dom
import { CustomElement } from 'aurelia';
// @endif
@@ -25,7 +28,7 @@ describe('my-app', () => {
// @if !shadow-dom
const text = node.textContent;
// @endif
- // @if jasmine || jest
+ // @if jasmine || jest || vitest
expect(text.trim()).toBe('Hello World!');
// @endif
// @if mocha
diff --git a/before.js b/before.js
index 0abeb26..47b734c 100644
--- a/before.js
+++ b/before.js
@@ -1,13 +1,18 @@
// Use "before" task to ask user to select a preset (to skip questionnaire).
const PRESETS = {
- 'default-esnext': ['app', 'webpack', 'babel', 'jest'],
- 'default-typescript': ['app', 'webpack', 'typescript', 'jest'],
+ 'default-esnext': ['app', 'vite', 'babel', 'vitest'],
+ 'default-typescript': ['app', 'vite', 'typescript', 'vitest'],
+ // TODO: move plugin to vite+vitest
+ // FIXME: vite compiles plugin with separate css dist file, and removed
+ // import('./style.css') from js code, need to:
+ // 1. hook up a css loader in runtime for normal css and css-module.
+ // 2. hook up a text loader in runtime for shadow-dom css.
'default-esnext-plugin': ['plugin', 'webpack', 'babel', 'shadow-dom', 'jest'],
'default-typescript-plugin': ['plugin', 'webpack', 'typescript', 'shadow-dom', 'jest'],
};
-const REQUIRE_NODEJS_VESION = [14, 15, 0];
+const REQUIRE_NODEJS_VESION = [18, 0, 0];
function isNodejsOutdated() {
const version = process.version.slice(1).split('.');
diff --git a/common/package.json b/common/package.json
index 7e3dca7..246a4d4 100644
--- a/common/package.json
+++ b/common/package.json
@@ -5,6 +5,8 @@
// @endif
// @if plugin
"description": "An Aurelia 2 plugin.",
+ // TODO: turn on after moved plugin to vite steup
+ // "type": "module",
"main": "dist/index.js",
"files": [
"dist"
diff --git a/common/src/resource.d.ts__if_typescript b/common/src/resource.d.ts__if_typescript
index ef44a5d..d3ef093 100644
--- a/common/src/resource.d.ts__if_typescript
+++ b/common/src/resource.d.ts__if_typescript
@@ -11,18 +11,18 @@ declare module '*.html' {
}
// @if css-module
-declare module '*.css' {
+declare module '*.module.css' {
const value: Record;
export default value;
}
// @if less
-declare module '*.less' {
+declare module '*.module.less' {
const value: Record;
export default value;
}
// @endif
// @if sass
-declare module '*.scss' {
+declare module '*.module.scss' {
const value: Record;
export default value;
}
diff --git a/dumber/gulpfile.js b/dumber/gulpfile.js
index c9f93e3..3e80400 100644
--- a/dumber/gulpfile.js
+++ b/dumber/gulpfile.js
@@ -143,10 +143,7 @@ function buildHtml(src) {
// standard DOM APIs in "closed" mode.
.pipe(au2({ defaultShadowOptions: { mode: 'open' }, hmr: false }));
// @endif
- // @if css-module
- .pipe(au2({ useCSSModule: true, hmr: false }));
- // @endif
- // @if !shadow-dom && !css-module
+ // @if !shadow-dom
.pipe(au2({ hmr: false }));
// @endif
}
@@ -177,7 +174,8 @@ function buildCss(src) {
// improve compatibility on svg.
postcssUrl({ url: 'inline', encodeType: 'base64' })
]))/* @if css-module */
- .pipe(cssModule())/* @endif */;
+ // Use .module.css naming convention
+ .pipe(gulpif(f => f.basename.endsWith('.module.css'), cssModule()))/* @endif */;
}
function build() {
diff --git a/e2e-test.js b/e2e-test.js
index 2f596e1..084ce37 100644
--- a/e2e-test.js
+++ b/e2e-test.js
@@ -5,11 +5,9 @@
// Have to run "npm run test:e2e" manually before a release.
const spawn = require('cross-spawn');
-const os = require('os');
const fs = require('fs');
const path = require('path');
const test = require('ava');
-const puppeteer = require('puppeteer');
const kill = require('tree-kill');
const {possibleFeatureSelections} = require('makes');
const questions = require('./questions');
@@ -24,7 +22,7 @@ const allSkeletons = possibleFeatureSelections(questions);
const isWin32 = process.platform === 'win32';
-const folder = path.join(os.tmpdir(), 'test-skeletons');
+const folder = path.join(__dirname, 'test-skeletons');
console.log('-- cleanup ' + folder);
fs.rmSync(folder, {recursive: true, force: true});
fs.mkdirSync(folder);
@@ -40,7 +38,7 @@ function killProc(proc) {
kill(proc.pid);
}
-function run(command, dataCB, errorCB) {
+function run(command, cwd, dataCB, errorCB) {
const [cmd, ...args] = command.split(' ');
return new Promise((resolve, reject) => {
const env = Object.create(process.env);
@@ -49,7 +47,7 @@ function run(command, dataCB, errorCB) {
// need to reset NODE_ENV back to development because this whole
// test is running in NODE_ENV=test which will affect gulp build
env.NODE_ENV = 'development';
- const proc = spawn(cmd, args, {env});
+ const proc = spawn(cmd, args, {env, cwd});
proc.on('exit', async (code, signal) => {
await delay(1);
if (code && signal !== 'SIGTERM' && !win32Killed.has(proc.pid)) {
@@ -85,15 +83,6 @@ function run(command, dataCB, errorCB) {
});
}
-async function takeScreenshot(url, filePath) {
- const browser = await puppeteer.launch();
- const page = await browser.newPage();
- await page.goto(url);
- await new Promise(r => setTimeout(r, 6000));
- await page.screenshot({path: filePath});
- await browser.close();
-}
-
const targetFeatures = (process.env.TARGET_FEATURES || '').toLowerCase().split(',').filter(p => p);
if (!targetFeatures.includes('playwright')) {
targetFeatures.push('playwright');
@@ -111,6 +100,7 @@ if (targetFeatures.length) {
function getServerRegex(features) {
if (features.includes('webpack')) return /Loopback: (\S+)/;
if (features.includes('parcel')) return /Server running at (\S+)/;
+ if (features.includes('vite')) return /(http:\/\/\S+\/)/;
return /Dev server is started at: (\S+)/;
}
@@ -126,26 +116,24 @@ skeletons.forEach((features, i) => {
test.serial(title, async t => {
console.log(title);
- process.chdir(folder);
const makeCmd = `npx makes ${__dirname} ${appName} -s ${features.join(',')}`;
console.log('-- ' + makeCmd);
- await run(makeCmd);
+ await run(makeCmd, folder);
t.pass('made skeleton');
- process.chdir(appFolder);
console.log('-- npm i');
- await run('npm i');
+ await run('npm i', appFolder);
t.pass('installed deps');
if (!features.includes('no-unit-tests')) {
console.log('-- npm test');
- await run('npm test');
+ await run('npm test', appFolder);
t.pass('finished unit tests');
}
console.log('-- npm run build');
- await run('npm run build', null,
+ await run('npm run build', appFolder, null,
(data, kill) => {
// Skip parcel warnings.
if (features.includes('parcel')) return;
@@ -164,32 +152,21 @@ skeletons.forEach((features, i) => {
if (!m) return;
const url = m[1];
t.pass(m[0]);
-
- try {
- if (!process.env.GITHUB_ACTIONS) {
- console.log('-- take screenshot');
- await takeScreenshot(url, path.join(folder, appName + '.png'));
- }
- kill();
- } catch (e) {
- t.fail(e.message);
- kill();
- }
+ kill();
};
// Webpack5 now prints Loopback: http://localhost:5000 in stderr!
- await run('npm start', runE2e, runE2e);
+ await run('npm start', appFolder, runE2e, runE2e);
if (features.includes('playwright')) {
console.log('-- npx playwright test --project chromium');
- await run('npx playwright install --with-deps');
- await run('npx playwright test --project chromium');
+ await run('npx playwright install --with-deps', appFolder);
+ await run('npx playwright test --project chromium', appFolder);
}
await delay(1);
console.log('-- remove folder ' + appName);
- process.chdir(folder);
await fs.promises.rm(appFolder, {recursive: true});
});
});
diff --git a/jest/package.json b/jest/package.json
index e98647a..26bb496 100644
--- a/jest/package.json
+++ b/jest/package.json
@@ -25,10 +25,7 @@
// @if shadow-dom
"\\.(js|html)$": [ "@aurelia/babel-jest", { defaultShadowOptions: { mode: 'open' } } ]
// @endif
- // @if css-module
- "\\.(js|html)$": [ "@aurelia/babel-jest", { useCSSModule: true } ]
- // @endif
- // @if !shadow-dom && !css-module
+ // @if !shadow-dom
"\\.(js|html)$": "@aurelia/babel-jest",
// @endif
// @endif
@@ -36,10 +33,7 @@
// @if shadow-dom
"\\.(ts|html)$": [ "@aurelia/ts-jest", { defaultShadowOptions: { mode: 'open' } } ]
// @endif
- // @if css-module
- "\\.(ts|html)$": [ "@aurelia/ts-jest", { useCSSModule: true } ]
- // @endif
- // @if !shadow-dom && !css-module
+ // @if !shadow-dom
"\\.(ts|html)$": "@aurelia/ts-jest",
// @endif
// @endif
diff --git a/package.json b/package.json
index 35640c7..abe82d4 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,6 @@
"glob": "^10.3.1",
"makes": "^3.2.0",
"npm-check-updates": "^16.10.13",
- "puppeteer": "^20.7.3",
"semver": "^7.5.3",
"standard-changelog": "^3.0.0",
"tree-kill": "^1.2.2",
diff --git a/parcel/README.md b/parcel/README.md
index a43a97c..9eb237b 100644
--- a/parcel/README.md
+++ b/parcel/README.md
@@ -4,5 +4,5 @@ By Parcel2 conventions, the `index.html` is in `src/` folder.
## Aurelia 2 config
-To control the behaviour of ShadownDOM and CSS-Module setup in Aurelia 2, create a section `"aurelia"` in the `package.json` file.
+To control the behaviour of ShadownDOM in Aurelia 2, create a section `"aurelia"` in the `package.json` file.
https://www.npmjs.com/package/@aurelia/parcel-transformer
diff --git a/parcel/package.json b/parcel/package.json
index c26d588..5486b68 100644
--- a/parcel/package.json
+++ b/parcel/package.json
@@ -45,14 +45,7 @@
"hmr": false
},
// @endif
- // @if css-module
- "aurelia": {
- "useCSSModule": true,
- "hmr": false
- },
- "@parcel/transformer-css": { "cssModules": true },
- // @endif
- // @if !shadow-dom && !css-module
+ // @if !shadow-dom
"aurelia": {
"hmr": false
},
diff --git a/playwright/playwright.config.ext b/playwright/playwright.config.mjs
similarity index 86%
rename from playwright/playwright.config.ext
rename to playwright/playwright.config.mjs
index 2edccd3..26d7224 100644
--- a/playwright/playwright.config.ext
+++ b/playwright/playwright.config.mjs
@@ -1,11 +1,4 @@
-// @if typescript
-import type { PlaywrightTestConfig } from '@playwright/test';
-import { devices } from '@playwright/test';
-// @endif
-// @if babel
-// @ts-check
-const { devices } = require('@playwright/test');
-// @endif
+import { defineConfig, devices } from '@playwright/test';
/**
* Read environment variables from file.
@@ -16,7 +9,7 @@ const { devices } = require('@playwright/test');
/**
* See https://playwright.dev/docs/test-configuration.
*/
-const config/* @if typescript */: PlaywrightTestConfig/* @endif */ = {
+export default defineConfig({
testDir: './e2e',
/* Maximum time one test can run for. */
timeout: 30 * 1000,
@@ -108,11 +101,4 @@ const config/* @if typescript */: PlaywrightTestConfig/* @endif */ = {
command: 'npm start',
port: 9000,
},
-};
-
-// @if typescript
-export default config;
-// @endif
-// @if babel
-module.exports = config;
-// @endif
+});
diff --git a/plugin-min/test__if_not_no-unit-tests/hello-world.spec.ext b/plugin-min/test__if_not_no-unit-tests/hello-world.spec.ext
index 50debb7..4740cec 100644
--- a/plugin-min/test__if_not_no-unit-tests/hello-world.spec.ext
+++ b/plugin-min/test__if_not_no-unit-tests/hello-world.spec.ext
@@ -1,6 +1,9 @@
// @if mocha
import { expect } from 'chai';
// @endif
+// @if vitest
+import { describe, it, expect } from 'vitest';
+// @endif
// @if shadow-dom
import { CustomElement } from 'aurelia';
// @endif
@@ -25,7 +28,7 @@ describe('hello-world', () => {
// @if !shadow-dom
const text = node.textContent;
// @endif
- // @if jasmine || jest
+ // @if jasmine || jest || vitest
expect(text.trim()).toBe('Hello World! foo');
// @endif
// @if mocha
diff --git a/questions.js b/questions.js
index a26882e..a470859 100644
--- a/questions.js
+++ b/questions.js
@@ -16,6 +16,7 @@ module.exports = [
{
message: 'Which bundler would you like to use?',
choices: [
+ {if: 'app', value: 'vite', title: 'Vite', hint: 'Next Generation Frontend Tooling.'},
{value: 'webpack', title: 'Webpack', hint: 'A powerful and popular bundler for modern JavaScript apps.'},
{if: 'app', value: 'dumber', title: 'Dumber', hint: 'A dumb JavasScript bundler, dumber than you and me. The successor of Aurelia CLI built-in bundler.'},
{if: 'app', value: 'parcel', title: 'Parcel', hint: 'Blazing fast, zero configuration web application bundler.'},
@@ -34,7 +35,7 @@ module.exports = [
{title: 'No'},
{if: 'app', value: 'shadow-dom', title: 'Use Shadow DOM', hint: 'Shadow DOM in open mode, shadowRoot is accessible through DOM API.'},
{if: 'plugin', value: 'shadow-dom', title: 'Use Shadow DOM (Recommended for plugin project)', hint: 'Shadow DOM in open mode, shadowRoot is accessible through DOM API.'},
- {value: 'css-module', title: 'Use CSS Module', hint: 'CSS Module is an alternative way to locally scope CSS class names.'},
+ {value: 'css-module', title: 'Use CSS Module', hint: 'CSS Module is an alternative way to locally scope CSS class names. We use .module.css/less/scss file name convention.'},
]
},
{
@@ -49,9 +50,10 @@ module.exports = [
message: 'What unit testing framework to use?',
choices: [
{value: 'no-unit-tests', title: 'None', hint: 'No unit testing'},
- {value: 'jest', title: 'Jest', hint: 'Runs in Node.js, simulates browser by default, with a focus on simplicity.'},
- {value: 'jasmine', title: 'Jasmine', hint: 'Runs in browser, a behavior-driven testing framework.'},
- {value: 'mocha', title: 'Mocha + Chai', hint: 'Runs in browser, a feature-rich JavaScript test framework for node and browsers.'}
+ {if: '!vite', value: 'jest', title: 'Jest', hint: 'Runs in Node.js, simulates browser by default, with a focus on simplicity.'},
+ {if: '!vite', value: 'jasmine', title: 'Jasmine', hint: 'Runs in browser, a behavior-driven testing framework.'},
+ {if: '!vite', value: 'mocha', title: 'Mocha + Chai', hint: 'Runs in browser, a feature-rich JavaScript test framework for node and browsers.'},
+ {if: 'vite', value: 'vitest', title:'Vitest', hint: 'A Vite-native testing framework.'}
]
},
{
diff --git a/transforms.js b/transforms.js
index 700cb36..2eff04f 100644
--- a/transforms.js
+++ b/transforms.js
@@ -8,6 +8,10 @@ exports.append = function(properties, features) {
if (file.extname === '.ext') {
// change .ext to .ts or .js file
file.extname = features.includes('typescript') ? '.ts' : '.js';
+ } else if (features.includes('css-module')) {
+ if (['.css', '.less', '.scss'].includes(file.extname)) {
+ file.extname = `.module${file.extname}`;
+ }
}
}
cb(null, file);
diff --git a/typescript/package.json b/typescript/package.json
index 95e9b5d..56c29cc 100644
--- a/typescript/package.json
+++ b/typescript/package.json
@@ -1,7 +1,8 @@
{
"devDependencies": {
"@types/node": "^20.12.3",
- "typescript": "^5.4.3",
+ // FIXME: typescript v5.5 has issue with our decorator typing
+ "typescript": "~5.4.5",
"tslib": "^2.6.2",
"@typescript-eslint/eslint-plugin": "^7.5.0",
"@typescript-eslint/parser": "^7.5.0"
diff --git a/vite/index.html b/vite/index.html
new file mode 100644
index 0000000..002212d
--- /dev/null
+++ b/vite/index.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+ Aurelia
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vite/package.json b/vite/package.json
new file mode 100644
index 0000000..bb8eca4
--- /dev/null
+++ b/vite/package.json
@@ -0,0 +1,31 @@
+{
+ "type": "module",
+ "devDependencies": {
+ "@aurelia/vite-plugin": /* @if latest */"latest"/* @endif *//* @if dev */"dev"/* @endif */,
+ "vite": "^5.2.12",
+ "vite-plugin-node-polyfills": "^0.22.0",
+ // @if babel
+ "vite-plugin-babel": "^1.2.0",
+ // @endif
+ // @if typescript && plugin
+ "vite-plugin-dts": "^3.9.1",
+ // @endif
+ // @if vitest
+ "vitest": "^1.6.0",
+ "jsdom": "^24.1.0",
+ // @endif
+ // @if less
+ "less": "^4.2.0",
+ // @endif
+ // @if sass
+ "sass": "^1.77.3",
+ // @endif
+ },
+ "scripts": {
+ "start": "vite",
+ "build": "vite build",
+ // @if vitest
+ "test": "vitest",
+ // @endif
+ }
+}
diff --git a/vite/tsconfig.vitest.json__if_vitest_and_typescript b/vite/tsconfig.vitest.json__if_vitest_and_typescript
new file mode 100644
index 0000000..e0a57fe
--- /dev/null
+++ b/vite/tsconfig.vitest.json__if_vitest_and_typescript
@@ -0,0 +1,8 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "composite": true,
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo",
+ "types": ["node", "jsdom"]
+ }
+}
\ No newline at end of file
diff --git a/vite/vite.config.ext b/vite/vite.config.ext
new file mode 100644
index 0000000..8e56609
--- /dev/null
+++ b/vite/vite.config.ext
@@ -0,0 +1,58 @@
+import { defineConfig } from 'vite';
+import { nodePolyfills } from 'vite-plugin-node-polyfills'
+import aurelia from '@aurelia/vite-plugin';
+// @if babel
+import babel from 'vite-plugin-babel';
+// @endif
+// @if plugin
+import { resolve } from 'path';
+// @if typescript
+import dts from 'vite-plugin-dts';
+// @endif
+// @endif
+
+export default defineConfig({
+ server: {
+ open: !process.env.CI,
+ port: 9000,
+ },
+ esbuild: {
+ target: 'es2022'
+ },
+ // @if plugin
+ build: {
+ lib: {
+ entry: resolve(__dirname, 'src/index./* @if babel */js/* @endif *//* @if typescript */ts/* @endif */'),
+ // Generate ESM dist file only.
+ formats: ['es'],
+ fileName: 'index',
+ },
+ rollupOptions: {
+ // Add all 3rd party dependencies here to avoid bundling.
+ external: [/@aurelia\/\w+/, 'aurelia'],
+ },
+ },
+ // @endif
+ plugins: [
+ aurelia({
+ useDev: true,
+ // @if plugin
+ include: '{src,dev-app}/**/*.{ts,js,html}',
+ // @endif
+ // @if shadow-dom
+ // The other possible Shadow DOM mode is 'closed'.
+ // If you turn on "closed" mode, there will be difficulty to perform e2e
+ // tests (such as Playwright). Because shadowRoot is not accessible through
+ // standard DOM APIs in "closed" mode.
+ defaultShadowOptions: { mode: 'open' },
+ // @endif
+ }),
+ // @if babel
+ babel(),
+ // @endif
+ nodePolyfills(),
+ // @if typescript && plugin
+ dts(),
+ // @endif
+ ],
+});
diff --git a/vite/vitest.config.ext__if_vitest b/vite/vitest.config.ext__if_vitest
new file mode 100644
index 0000000..1261649
--- /dev/null
+++ b/vite/vitest.config.ext__if_vitest
@@ -0,0 +1,17 @@
+import { fileURLToPath } from "node:url";
+import { mergeConfig, defineConfig/* @if playwright */, configDefaults/* @endif */ } from "vitest/config";
+import viteConfig from "./vite.config";
+
+export default mergeConfig(
+ viteConfig,
+ defineConfig({
+ test: {
+ environment: "jsdom",
+ watch: false,
+ // @if playwright
+ exclude: [...configDefaults.exclude, "e2e/*"],
+ // @endif
+ root: fileURLToPath(new URL("./", import.meta.url)),
+ },
+ }),
+);
\ No newline at end of file
diff --git a/webpack/webpack.config.js b/webpack/webpack.config.js
index 216027f..eac1478 100644
--- a/webpack/webpack.config.js
+++ b/webpack/webpack.config.js
@@ -13,20 +13,6 @@ const WebpackShellPluginNext = require('webpack-shell-plugin-next')
const nodeExternals = require('webpack-node-externals');
// @endif
-// @if !css-module
-const cssLoader = 'css-loader';
-// @endif
-// @if css-module
-const cssLoader = {
- loader: 'css-loader',
- options: {
- modules: true,
- // https://github.com/webpack-contrib/css-loader#importloaders
- importLoaders: /* @if css */1/* @endif *//* @if !css */2/* @endif */
- }
-};
-// @endif
-
// @if sass
const sassLoader = {
loader: 'sass-loader',
@@ -113,7 +99,7 @@ module.exports = function(env, { /* @if jasmine || mocha*/runTest, /* @endif */a
},
resolve: {
extensions: [/* @if typescript */'.ts', /* @endif */'.js'],
- modules: [path.resolve(__dirname, 'src'),/* @if !production */ path.resolve(__dirname, 'dev-app'),/* @endif */ 'node_modules'],
+ modules: [path.resolve(__dirname, 'src'),/* @if plugin */ path.resolve(__dirname, 'dev-app'),/* @endif */ 'node_modules'],
alias: production ? {
// add your production aliases here
} : {
@@ -131,12 +117,12 @@ module.exports = function(env, { /* @if jasmine || mocha*/runTest, /* @endif */a
{ test: /\.(png|svg|jpg|jpeg|gif)$/i, type: 'asset' },
{ test: /\.(woff|woff2|ttf|eot|svg|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/i, type: 'asset' },
// @if !shadow-dom
- { test: /\.css$/i, use: [ 'style-loader', cssLoader, postcssLoader ] },
+ { test: /\.css$/i, use: [ 'style-loader', 'css-loader', postcssLoader ] },
// @if less
- { test: /\.less$/i, use: [ 'style-loader', cssLoader, postcssLoader, 'less-loader' ] },
+ { test: /\.less$/i, use: [ 'style-loader', 'css-loader', postcssLoader, 'less-loader' ] },
// @endif
// @if sass
- { test: /\.scss$/i, use: [ 'style-loader', cssLoader, postcssLoader, sassLoader ] },
+ { test: /\.scss$/i, use: [ 'style-loader', 'css-loader', postcssLoader, sassLoader ] },
// @endif
// @endif
// @if shadow-dom
@@ -145,7 +131,7 @@ module.exports = function(env, { /* @if jasmine || mocha*/runTest, /* @endif */a
// For style loaded in src/main.js, it's not loaded by style-loader.
// It's for shared styles for shadow-dom only.
issuer: /[/\\]src[/\\]main\.(js|ts)$/,
- use: [ cssLoader, postcssLoader ]
+ use: [ 'css-loader', postcssLoader ]
},
// @if less
{
@@ -153,7 +139,7 @@ module.exports = function(env, { /* @if jasmine || mocha*/runTest, /* @endif */a
// For style loaded in src/main.js, it's not loaded by style-loader.
// It's for shared styles for shadow-dom only.
issuer: /[/\\]src[/\\]main\.(js|ts)$/,
- use: [ cssLoader, postcssLoader, 'less-loader' ]
+ use: [ 'css-loader', postcssLoader, 'less-loader' ]
},
// @endif
// @if sass
@@ -162,7 +148,7 @@ module.exports = function(env, { /* @if jasmine || mocha*/runTest, /* @endif */a
// For style loaded in src/main.js, it's not loaded by style-loader.
// It's for shared styles for shadow-dom only.
issuer: /[/\\]src[/\\]main\.(js|ts)$/,
- use: [ cssLoader, postcssLoader, sassLoader ]
+ use: [ 'css-loader', postcssLoader, sassLoader ]
},
// @endif
{
@@ -170,7 +156,7 @@ module.exports = function(env, { /* @if jasmine || mocha*/runTest, /* @endif */a
// For style loaded in other js/ts files, it's loaded by style-loader.
// They are directly injected to HTML head.
issuer: /(?