├── template ├── .gitignore ├── src │ ├── style.css │ ├── index.ts │ ├── component.tsx │ └── template.html ├── tests │ ├── __mocks__ │ │ └── setupTests.js │ ├── declarations.d.ts │ └── index.test.tsx ├── README.md ├── package.json └── tsconfig.json ├── .gitignore └── README.md /template/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode 3 | build 4 | dist -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | *.lock 4 | *.log 5 | template/package-lock.json 6 | template/size-plugin.json 7 | -------------------------------------------------------------------------------- /template/src/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | font: 14px/1.21 'Helvetica Neue', arial, sans-serif; 3 | font-weight: 400; 4 | } 5 | 6 | h1 { 7 | text-align: center; 8 | } 9 | -------------------------------------------------------------------------------- /template/tests/__mocks__/setupTests.js: -------------------------------------------------------------------------------- 1 | import { configure } from "enzyme"; 2 | import Adapter from "enzyme-adapter-preact-pure"; 3 | 4 | configure({ 5 | adapter: new Adapter() 6 | }); -------------------------------------------------------------------------------- /template/tests/declarations.d.ts: -------------------------------------------------------------------------------- 1 | // Enable enzyme adapter's integration with TypeScript 2 | // See: https://github.com/preactjs/enzyme-adapter-preact-pure#usage-with-typescript 3 | /// -------------------------------------------------------------------------------- /template/src/index.ts: -------------------------------------------------------------------------------- 1 | import habitat from 'preact-habitat'; 2 | 3 | import Widget from './component'; 4 | 5 | const _habitat = habitat(Widget); 6 | 7 | _habitat.render({ 8 | selector: '[data-widget-host="habitat"]', 9 | clean: true 10 | }); 11 | -------------------------------------------------------------------------------- /template/src/component.tsx: -------------------------------------------------------------------------------- 1 | import { h, VNode } from 'preact'; 2 | 3 | import './style.css'; 4 | 5 | interface Props { 6 | color?: string; 7 | } 8 | 9 | export default function App(props: Props): VNode { 10 | return ( 11 |
12 |

Hello, World!

13 |
14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /template/tests/index.test.tsx: -------------------------------------------------------------------------------- 1 | import { h } from 'preact'; 2 | import { shallow } from 'enzyme'; 3 | 4 | import Hello from '../src/component'; 5 | 6 | describe('Hello logic', () => { 7 | it('should be able to run tests', () => { 8 | expect(1 + 2).toEqual(3); 9 | }); 10 | }); 11 | 12 | describe('Hello Snapshot', () => { 13 | it('should render header with content', () => { 14 | const tree = shallow(); 15 | expect(tree.find("h1").text()).toBe('Hello, World!'); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /template/README.md: -------------------------------------------------------------------------------- 1 | # {{ name }} 2 | 3 | ## CLI Commands 4 | 5 | ``` bash 6 | # install dependencies 7 | npm install 8 | 9 | # serve demo with hot reload at localhost:8080 10 | npm run dev 11 | 12 | # build npm ready bundles to be consumed by other Preact web apps 13 | npm run build:widget 14 | 15 | # build npm ready bundles to be used as a component library 16 | npm run build:lib 17 | 18 | # lint the project with eslint to find code style issues 19 | npm run lint 20 | 21 | # run tests with jest and enzyme 22 | npm run test 23 | ``` 24 | 25 | For detailed explanation on how things work, checkout the [CLI Readme](https://github.com/preactjs/preact-cli/blob/master/README.md). 26 | -------------------------------------------------------------------------------- /template/src/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <% preact.title %> 6 | 7 | 25 | <% preact.headEnd %> 26 | 27 | 28 |
29 | 32 |
33 | <% preact.bodyEnd %> 34 | 35 | -------------------------------------------------------------------------------- /template/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{ name }}", 3 | "version": "0.1.0", 4 | "description": "", 5 | "source": "src/index.ts", 6 | "main": "dist/index.js", 7 | "module": "dist/index.module.js", 8 | "umd:main": "dist/index.umd.js", 9 | "types": "dist/index.d.ts", 10 | "scripts": { 11 | "dev": "preact watch", 12 | "build:widget": "microbundle build", 13 | "build:lib": "microbundle build -i src/component.tsx", 14 | "lint": "eslint '{src,tests}/**/*.{ts,tsx}'", 15 | "test": "jest" 16 | }, 17 | "files": [ 18 | "dist" 19 | ], 20 | "eslintConfig": { 21 | "parser": "@typescript-eslint/parser", 22 | "extends": ["preact", "plugin:@typescript-eslint/recommended"], 23 | "ignorePatterns": [ 24 | "build/" 25 | ] 26 | }, 27 | "author": "Kirill Shatskiy ", 28 | "license": "MIT", 29 | "dependencies": { 30 | "preact": "10.5.7" 31 | }, 32 | "devDependencies": { 33 | "@types/enzyme": "^3.10.8", 34 | "@types/jest": "^27.0.2", 35 | "@typescript-eslint/eslint-plugin": "^4.6.1", 36 | "@typescript-eslint/parser": "^4.6.1", 37 | "enzyme": "^3.11.0", 38 | "enzyme-adapter-preact-pure": "^3.3.0", 39 | "eslint": "^7.32.0", 40 | "eslint-config-preact": "^1.1.3", 41 | "jest": "^27.3.1", 42 | "jest-preset-preact": "^4.0.2", 43 | "microbundle": "^0.14.1", 44 | "preact-cli": "^3.0.5", 45 | "preact-habitat": "^3.3.0", 46 | "preact-render-to-string": "^5.1.11", 47 | "typescript": "^4.1.3" 48 | }, 49 | "jest": { 50 | "preset": "jest-preset-preact", 51 | "setupFiles": [ 52 | "/tests/__mocks__/setupTests.js" 53 | ] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Preact Widget-Typescript Template 2 | 3 | ## Overview 4 | 5 | - This is a TypeScript-based template for creating a Preact widget or a component library 6 | - [Preact-CLI](https://github.com/preactjs/preact-cli): Used for running a local development environment to use your widget in 7 | - [Microbundle](https://github.com/developit/microbundle): Used for bundling your widget/library for use in other Preact web apps 8 | - [Preact](https://preactjs.com/): General information about how to work with Preact, not specific to this template 9 | 10 | ## Usage 11 | 12 | ```bash 13 | $ npx preact-cli create widget-typescript my-widget 14 | $ cd my-widget 15 | $ npm install 16 | $ npm run dev 17 | ``` 18 | 19 | Development server runs on port `8080`. If the default port is already in use on 20 | your machine, it will start the development server on a random port. 21 | 22 | ## Commands 23 | - `npm install`: Installs dependencies 24 | 25 | - `npm run dev`: Run a development server with Preact-CLI to test your widget 26 | 27 | - `npm run build:widget`: NPM-ready build with Microbundle, to distribute your widget to be consumed by other Preact web applications 28 | 29 | - `npm run build:lib`: NPM-ready build with Microbundle, to distribute your component as a Preact component library 30 | 31 | - `npm run lint`: Lint files use ESLint 32 | 33 | - `npm run test`: Run Jest and Enzyme with 34 | [`enzyme-adapter-preact-pure`](https://github.com/preactjs/enzyme-adapter-preact-pure) for 35 | your tests 36 | 37 | ### How to Test 38 | 39 | The `widget-typescript` template provides a basic test setup with Jest, Enzyme and 40 | [`enzyme-adapter-preact-pure`](https://github.com/preactjs/enzyme-adapter-preact-pure). 41 | You are free to change Enzyme with any other testing library 42 | (eg. [Preact Testing Library](https://testing-library.com/docs/preact-testing-library/intro)). 43 | 44 | You can run all additional Jest CLI commands with the `npm run test` command as 45 | described in the 46 | [Jest docs](https://facebook.github.io/jest/docs/en/cli.html#using-with-npm-scripts). 47 | For example, running jest in watch mode would be : 48 | 49 | - `npm run test -- --watch` instead of `jest --watch` 50 | -------------------------------------------------------------------------------- /template/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "ESNext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ 5 | "module": "ESNext", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 6 | // "lib": [], /* Specify library files to be included in the compilation: */ 7 | // "allowJs": true, /* Allow javascript files to be compiled. */ 8 | // "checkJs": true, /* Report errors in .js files. */ 9 | "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 10 | "jsxFactory": "h", /* Specify the JSX factory function to use when targeting react JSX emit, e.g. React.createElement or h. */ 11 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 12 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 13 | // "outFile": "./", /* Concatenate and emit output to single file. */ 14 | // "outDir": "./", /* Redirect output structure to the directory. */ 15 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 16 | // "removeComments": true, /* Do not emit comments to output. */ 17 | // "noEmit": true, /* Do not emit outputs. */ 18 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 19 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 20 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 21 | 22 | /* Strict Type-Checking Options */ 23 | // "strict": true, /* Enable all strict type-checking options. */ 24 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 25 | // "strictNullChecks": true, /* Enable strict null checks. */ 26 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 27 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 28 | 29 | /* Additional Checks */ 30 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 31 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 32 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 33 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 34 | 35 | /* Module Resolution Options */ 36 | "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 37 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 38 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 39 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 40 | // "typeRoots": [], /* List of folders to include type definitions from. */ 41 | // "types": [], /* Type declaration files to be included in compilation. */ 42 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 43 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 44 | 45 | /* Source Map Options */ 46 | // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 47 | // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ 48 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 49 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 50 | 51 | /* Experimental Options */ 52 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 53 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 54 | "esModuleInterop": true 55 | }, 56 | "include": ["src"] 57 | } --------------------------------------------------------------------------------