Skip to content
Open
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
46 changes: 46 additions & 0 deletions preact-vite/.idx/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import tseslint from 'typescript-eslint';
import eslintReact from '@eslint-react/eslint-plugin';
import prettier from 'eslint-config-prettier';
import globals from 'globals';

export default [
// 1. Global ignores
{
ignores: ['dist', 'node_modules', '*.cjs', '**/*.config.js'],
},

// 2. Recommended rules from typescript-eslint
...tseslint.configs.recommended,

// 3. Modern ESLint React configuration for Preact
{
files: ['src/**/*.{js,jsx,ts,tsx}'],
...eslintReact.configs.recommended,
languageOptions: {
globals: {
...globals.browser,
},
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
rules: {
...eslintReact.configs.recommended.rules,
// Preact-specific overrides
'@eslint-react/react-in-jsx-scope': 'off', // Not needed with modern JSX transform
'@eslint-react/dom/no-unsafe-target-blank': 'warn',
},
settings: {
react: {
version: 'detect',
pragma: 'h', // Use 'h' for Preact
pragmaFrag: 'Fragment', // Use 'Fragment' for Preact
},
},
},

// 4. Prettier config must be last to override other formatting rules.
prettier,
];
59 changes: 59 additions & 0 deletions preact-vite/.idx/update-pkg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import fs from 'node:fs';
import path from 'node:path';

// --- Configuration ---
const packageJsonPath = path.join(process.cwd(), 'package.json');

const scriptsToAdd = {
lint: 'eslint .',
format: 'prettier . --write',
};

// Modern dev dependencies for Preact, ESLint v9+, TypeScript, and Prettier
const devDependenciesToAdd = {
'@eslint-react/eslint-plugin': 'latest', // Modern, flat-config compatible React plugin
eslint: '^9.5.0',
'eslint-config-prettier': '^9.1.0',
globals: '^15.4.0',
prettier: '^3.3.2',
'typescript-eslint': 'latest', // Use latest for best compatibility
};

const prettierConfig = {
arrowParens: 'always',
bracketSpacing: true,
htmlWhitespaceSensitivity: 'css',
insertPragma: false,
bracketSameLine: false,
jsxSingleQuote: false,
printWidth: 80,
proseWrap: 'preserve',
quoteProps: 'as-needed',
requirePragma: false,
semi: true,
singleQuote: true,
tabWidth: 2,
trailingComma: 'es5',
useTabs: false,
};

// --- Script Logic ---
try {
const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8');
const packageJson = JSON.parse(packageJsonContent);

packageJson.scripts = { ...packageJson.scripts, ...scriptsToAdd };
packageJson.devDependencies = {
...packageJson.devDependencies,
...devDependenciesToAdd,
};
packageJson.prettier = prettierConfig;

const updatedPackageJsonContent = JSON.stringify(packageJson, null, 2);
fs.writeFileSync(packageJsonPath, updatedPackageJsonContent);

console.log('Successfully updated package.json with modern ESLint and Prettier configs!');
} catch (error) {
console.error('Error updating package.json:', error);
process.exit(1);
}
6 changes: 5 additions & 1 deletion preact-vite/dev.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@
# Use https://search.nixos.org/packages to find packages
packages = [
pkgs.nodejs_20
pkgs.nodePackages.eslint
pkgs.nodePackages.prettier
];
# Sets environment variables in the workspace
env = {};
idx = {
# Search for the extensions you want on https://open-vsx.org/ and use "publisher.id"
extensions = [
# "vscodevim.vim"
"dbaeumer.vscode-eslint"
"esbenp.prettier-vscode"
];
workspace = {
# Runs when a workspace is first created with this `dev.nix` file
Expand All @@ -28,7 +32,7 @@
enable = true;
previews = {
web = {
command = ["npm" "run" "dev" "--" "--port" "$PORT" "--host" "0.0.0.0"];
command = ["npm" "run" "dev" "--" "--port" "$PORT"];
manager = "web";
};
};
Expand Down
68 changes: 53 additions & 15 deletions preact-vite/idx-template.nix
Original file line number Diff line number Diff line change
@@ -1,22 +1,60 @@
{ pkgs, language ? "js", ... }: {
{ pkgs, language ? "ts", ... }:

{
# Use a recent channel to get a newer Node.js version required by modern ESLint.
channel = "stable-24.05";

packages = [
pkgs.nodejs_20
];

# This bootstrap script is run once when the template is created.
bootstrap = ''
mkdir -p "$WS_NAME"
npm create -y vite@latest "$WS_NAME" -- --template ${if language == "ts" then "preact-ts" else "preact"}
mkdir -p "$WS_NAME/.idx/"
cp -rf ${./icon.png} "$WS_NAME/.idx/icon.png"
cp -rf ${./dev.nix} "$WS_NAME/.idx/dev.nix"
chmod -R +w "$WS_NAME"
mv "$WS_NAME" "$out"
# Create the Vite project. This creates a directory with the workspace name.
${pkgs.nodejs_20}/bin/npm create -y vite@latest "$WS_NAME" -- --template ${if language == "ts" then "preact-ts" else "preact"}

# Enter the newly created project directory.
cd "$WS_NAME"

# The file to patch depends on whether the user chose TypeScript or JavaScript.
APP_FILE="src/app.jsx"
if [ "${language}" = "ts" ]; then
APP_FILE="src/app.tsx"
fi

# Use `sed` to add `rel="noreferrer noopener"` to all links with `target="_blank"`.
# This fixes a security vulnerability and satisfies the ESLint rule.
# We use a temporary file for compatibility with `sed` on different platforms.
sed 's/target="_blank"/target="_blank" rel="noreferrer noopener"/g' "$APP_FILE" > "$APP_FILE.tmp" && mv "$APP_FILE.tmp" "$APP_FILE"

# Create the .idx directory and copy the Nix environment file.
mkdir -p ./.idx
cp -f ${./dev.nix} ./.idx/dev.nix

mkdir -p "$out/.idx"
chmod -R u+w "$out"
cp -rf ${./.idx/airules.md} "$out/.idx/airules.md"
cp -rf "$out/.idx/airules.md" "$out/GEMINI.md"
chmod -R u+w "$out"
# Remove the default ESLint config from Vite.
rm -f ./.eslintrc.cjs

# Copy our modern ESLint config from the template root.
cp -f ${./.idx/eslint.config.js} ./eslint.config.js

# Copy and run the script to update package.json with new dependencies and scripts.
cp -f ${./.idx/update-pkg.js} ./update-pkg.js
${pkgs.nodejs_20}/bin/node ./update-pkg.js
rm ./update-pkg.js # Clean up the script.

# Install all dependencies.
${pkgs.nodejs_20}/bin/npm install

# Go back to the parent directory.
cd ..

# Move the completed project to the $out directory, which is what Nix expects.
mv "$WS_NAME" "$out"
'';

cd "$out"; npm install --package-lock-only --ignore-scripts
# The devenv shell hook is run every time the environment is activated.
shell.hook = ''
echo "Welcome to your Preact + Vite project! ⚡️"
echo "Run 'npm run dev' to start the development server."
'';
}
}