initial preact project structure (copied from another assignment and cleaned up

main
Inga 🏳‍🌈 10 months ago
parent ad0940badb
commit 599dcc2a0c
  1. 175
      .eslint-config-preact-nojest.cjs
  2. 30
      .eslintrc.cjs
  3. 1
      .gitignore
  4. 5
      .prettierrc
  5. 15
      index.html
  6. 9270
      package-lock.json
  7. 38
      package.json
  8. 1
      public/vite.svg
  9. 14
      src/index.tsx
  10. 31
      src/style.css
  11. 22
      tsconfig.json
  12. 8
      vite.config.ts

@ -0,0 +1,175 @@
// Code taken from https://github.com/preactjs/eslint-config-preact/blob/v1.3.0/index.js
// and modified to remove all jest mentions, because jest plugin is incompatible with typescript-eslint plugin v6
// (see https://github.com/jest-community/eslint-plugin-jest/pull/1401 for more details)
// and to change it from JSM to CJS
module.exports = {
// TODO: this is really only required for class property initializer methods, which are seeing declining usage.
// At some point, we should un-ship the custom parser and let ESLint use esprima.
parser: require.resolve('@babel/eslint-parser'),
// Currently ignored due to the custom parser.
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
ecmaFeatures: {
modules: true,
impliedStrict: true,
jsx: true,
},
requireConfigFile: false,
babelOptions: {
plugins: [
'@babel/plugin-syntax-class-properties',
[
'@babel/plugin-syntax-decorators',
{ decoratorsBeforeExport: false },
],
'@babel/plugin-syntax-jsx',
],
},
},
// We don't use plugin:react/recommended here to avoid React-specific rules.
extends: ['eslint:recommended'],
// TODO: preact-cli ships Jest now, Mocha may be a candidate for removal.
plugins: ['compat', 'react', 'react-hooks'],
env: {
browser: true,
es6: true,
node: true,
},
globals: {
expect: true,
browser: true,
global: true,
},
settings: {
// Preact CLI provides these defaults
targets: ['last 2 versions'],
polyfills: ['fetch', 'Promise'],
react: {
// eslint-plugin-preact interprets this as "h.createElement",
// however we only care about marking h() as being a used variable.
pragma: 'h',
// We use "react 16.0" to avoid pushing folks to UNSAFE_ methods.
version: '16.0',
},
},
rules: {
/**
* Preact / JSX rules
*/
'react/no-deprecated': 2,
'react/react-in-jsx-scope': 0, // handled this automatically
'react/display-name': [1, { ignoreTranspilerName: false }],
'react/jsx-no-bind': [
1,
{
ignoreRefs: true,
allowFunctions: true,
allowArrowFunctions: true,
},
],
'react/jsx-no-comment-textnodes': 2,
'react/jsx-no-duplicate-props': 2,
'react/jsx-no-target-blank': 2,
'react/jsx-no-undef': 2,
'react/jsx-tag-spacing': [2, { beforeSelfClosing: 'always' }],
'react/jsx-uses-react': 2, // debatable
'react/jsx-uses-vars': 2,
'react/jsx-key': [2, { checkFragmentShorthand: true }],
'react/self-closing-comp': 2,
'react/prefer-es6-class': 2,
'react/prefer-stateless-function': 1,
'react/require-render-return': 2,
'react/no-danger': 1,
// Legacy APIs not supported in Preact:
'react/no-did-mount-set-state': 2,
'react/no-did-update-set-state': 2,
'react/no-find-dom-node': 2,
'react/no-is-mounted': 2,
'react/no-string-refs': 2,
/**
* Hooks
*/
'react-hooks/rules-of-hooks': 2,
'react-hooks/exhaustive-deps': 1,
/**
* General JavaScript error avoidance
*/
'constructor-super': 2,
'no-caller': 2,
'no-const-assign': 2,
'no-delete-var': 2,
'no-dupe-class-members': 2,
'no-dupe-keys': 2,
'no-duplicate-imports': 2,
'no-else-return': 1,
'no-empty-pattern': 0,
'no-empty': 0,
'no-extra-parens': 0,
'no-iterator': 2,
'no-lonely-if': 2,
'no-mixed-spaces-and-tabs': [1, 'smart-tabs'],
'no-multi-str': 1,
'no-new-wrappers': 2,
'no-proto': 2,
'no-redeclare': 2,
'no-shadow-restricted-names': 2,
'no-shadow': 0,
'no-spaced-func': 2,
'no-this-before-super': 2,
'no-undef-init': 2,
'no-unneeded-ternary': 2,
'no-unused-vars': [
2,
{
args: 'after-used',
ignoreRestSiblings: true,
},
],
'no-useless-call': 1,
'no-useless-computed-key': 1,
'no-useless-concat': 1,
'no-useless-constructor': 1,
'no-useless-escape': 1,
'no-useless-rename': 1,
'no-var': 1,
'no-with': 2,
/**
* General JavaScript stylistic rules (disabled)
*/
semi: 0,
strict: [2, 'never'], // assume type=module output (cli default)
'object-curly-spacing': [0, 'always'],
'rest-spread-spacing': 0,
'space-before-function-paren': [0, 'always'],
'space-in-parens': [0, 'never'],
'object-shorthand': 1,
'prefer-arrow-callback': 1,
'prefer-rest-params': 1,
'prefer-spread': 1,
'prefer-template': 1,
quotes: [
0,
'single',
{
avoidEscape: true,
allowTemplateLiterals: true,
},
],
'quote-props': [2, 'as-needed'],
radix: 1, // parseInt(x, 10)
'unicode-bom': 2,
'valid-jsdoc': 0,
},
};

@ -0,0 +1,30 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
tsconfigRootDir: __dirname,
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'./.eslint-config-preact-nojest.cjs',
'plugin:@typescript-eslint/strict-type-checked',
'plugin:prettier/recommended',
],
root: true,
env: {
/*node: true,
jest: true,*/
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'@typescript-eslint/no-confusing-void-expression': [
'error',
{ ignoreArrowShorthand: true },
],
'@typescript-eslint/restrict-template-expressions': [
'error',
{ allowNever: true },
],
},
};

1
.gitignore vendored

@ -130,3 +130,4 @@ dist
.yarn/install-state.gz .yarn/install-state.gz
.pnp.* .pnp.*
.tap

@ -0,0 +1,5 @@
{
"tabWidth": 4,
"singleQuote": true,
"trailingComma": "all"
}

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link href='https://fonts.cdnfonts.com/css/atkinson-hyperlegible' rel='stylesheet'>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="color-scheme" content="light dark" />
<title>Spell checker</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>

9270
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,38 @@
{
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"start-release": "npm run build && serve dist",
"lint": "eslint \"{src,test}/**/*.{ts,tsx}\"",
"typecheck": "tsc --noEmit",
"test": "tap run",
"prebuild": "npm run lint && npm run typecheck && npm run test",
"preview": "vite preview"
},
"dependencies": {
"preact": "^10.13.1"
},
"devDependencies": {
"@babel/core": "^7.23.3",
"@babel/eslint-parser": "^7.23.3",
"@babel/plugin-syntax-class-properties": "^7.12.13",
"@babel/plugin-syntax-decorators": "^7.23.3",
"@babel/plugin-syntax-jsx": "^7.23.3",
"@preact/preset-vite": "^2.5.0",
"@tsconfig/strictest": "^2.0.2",
"@typescript-eslint/eslint-plugin": "^6.11.0",
"@typescript-eslint/parser": "^6.11.0",
"eslint": "^8.53.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-compat": "^4.2.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"serve": "^14.2.1",
"tap": "^18.6.1",
"typescript": "^5.2.2",
"vite": "^4.3.2"
}
}

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@ -0,0 +1,14 @@
import { render } from 'preact';
import './style.css';
export function App() {
return <h1>Hello world</h1>;
}
const app = document.getElementById('app');
if (app) {
render(<App />, app);
} else {
console.error('Cannot find app container');
}

@ -0,0 +1,31 @@
:root {
font-family: system-ui, 'Atkinson Hyperlegible', sans-serif;
line-height: 1.5;
font-weight: 400;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
body {
padding: 1rem;
display: flex;
align-items: center;
}
#app {
max-width: 1280px;
margin: 0 auto;
text-align: center;
}
img {
margin-bottom: 1.5rem;
}
img:hover {
filter: drop-shadow(0 0 2em #673ab8aa);
}

@ -0,0 +1,22 @@
{
"extends": "@tsconfig/strictest/tsconfig.json",
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"noEmit": true,
"allowJs": true,
"checkJs": true,
/* Preact Config */
"jsx": "react-jsx",
"jsxImportSource": "preact",
"skipLibCheck": true,
"paths": {
"react": ["./node_modules/preact/compat/"],
"react-dom": ["./node_modules/preact/compat/"]
}
},
"include": ["node_modules/vite/client.d.ts", "**/*"],
"exclude": ["dist"],
}

@ -0,0 +1,8 @@
import { defineConfig } from 'vite';
import preact from '@preact/preset-vite';
// https://vitejs.dev/config/
export default defineConfig({
base: './',
plugins: [preact()],
});
Loading…
Cancel
Save