{"id":1318,"date":"2023-04-08T22:45:30","date_gmt":"2023-04-08T22:45:30","guid":{"rendered":"http:\/\/www.codedread.com\/blog\/?p=1318"},"modified":"2023-04-10T19:36:26","modified_gmt":"2023-04-10T19:36:26","slug":"dead-simple-react-es-modules-tsx","status":"publish","type":"post","link":"https:\/\/www.codedread.com\/blog\/archives\/2023\/04\/08\/dead-simple-react-es-modules-tsx\/","title":{"rendered":"Dead Simple: TSX, ES Modules, Preact"},"content":{"rendered":"\n<a href=\"https:\/\/www.json.org\/\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/codedread.com\/clipart\/react.svg\" style=\"float:right\" alt=\"Logo for JSON\" width=\"100\" height=\"100\"><\/a>\n\n\n\n<p class=\"wp-block-paragraph\">I decided to learn a bit of React again for some toy projects (my day job JS framework is Angular). Most of the tutorials for setting up a React project \"from scratch\" ultimately result in using the <a href=\"https:\/\/create-react-app.dev\/\">create-react-app<\/a> library to hide a lot of the complexity (transpilers, bundlers), but I'm not interested in Webpack or Babel - primarily because I know browsers don't need them anymore. Also, I like to learn about how the bits and bobs work together for small projects like this. Here are the 3 things I want: Typescript, JSX, and compile\/deploy to ES modules. Can this actually be done? Yes, and it's not that difficult.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p class=\"wp-block-paragraph\">The React ecosystem is huge and there are giant frameworks that then build on top of it. For now, I want to learn a stripped down version of React core called <a href=\"https:\/\/preactjs.com\/\">Preact<\/a>. Most examples out there use <a href=\"https:\/\/react.dev\/learn\/writing-markup-with-jsx\">JSX<\/a> not <a href=\"https:\/\/github.com\/developit\/htm\">HTM<\/a> and since I'm using Typescript, I already know I need a build step so fine, let's just bite the JSX bullet!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here are the minimal HTML, TSX, and JSON files that do something semi-interesting and have zero red squiggles in VS Code and all that other developer goodness.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">index.html:<\/p>\n\n\n\n<pre class=\"wp-block-code has-vivid-green-cyan-color has-black-background-color has-text-color has-background\"><code>&#60;!DOCTYPE html&#62;\n&#60;html&#62;\n&#60;body&#62;\n  &#60;div id=\"app\"&#62;&#60;\/div&#62;\n  &#60;script type=\"importmap\"&#62;\n    {\n      \"imports\": {\n        \"preact\": \"https:\/\/esm.sh\/preact@10.13.2\"\n      }\n    }\n  &#60;\/script&#62;\n  &#60;script src=\".\/dist\/index.js\" type=\"module\"&#62;&#60;\/script&#62;\n&#60;\/body&#62;\n&#60;\/html&#62;<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">src\/index.tsx:<\/p>\n\n\n\n<pre class=\"wp-block-code has-vivid-green-cyan-color has-black-background-color has-text-color has-background\"><code>import { Component, RenderableProps, h, render } from 'preact';\n\ninterface AppProps {\n  name: string;\n}\n\ninterface AppState {\n  count: number;\n}\n\nexport class App extends Component&#60;AppProps, AppState&#62; {\n  state: AppState = { count: 0 };\n\n  clicky(name: string) {\n    const newCount = this.state.count + 1;\n    alert(`Hello, ${name}! You clicked ${newCount} times.`);\n    this.setState({count: newCount});\n  }\n\n  render(props: AppProps) {\n    return (\n      &#60;div&#62;\n        &#60;button onClick={() =&#62; this.clicky(props.name)}&#62;\n          Clicky\n        &#60;\/button&#62;\n        &#60;div&#62;(clicked {this.state.count} times)&#60;\/div&#62;\n      &#60;\/div&#62;\n    );\n  }\n}\n\nrender(&#60;App name=\"Jeff\"\/&#62;, document.getElementById(\"app\"));\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">package.json:<\/p>\n\n\n\n<pre class=\"wp-block-code has-vivid-green-cyan-color has-black-background-color has-text-color has-background\"><code>{\n  \"main\": \"dist\/index.js\",\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"preact\": \"^10.13.2\",\n    \"typescript\": \"^5.0.3\"\n  }\n}\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">tsconfig.json:<\/p>\n\n\n\n<pre class=\"wp-block-code has-vivid-green-cyan-color has-black-background-color has-text-color has-background\"><code>{\n  \"compilerOptions\": {\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"lib\": &#91;\n      \"es2022\",\n      \"dom\"\n    ],\n    \"module\": \"es2022\",\n    \"moduleResolution\": \"nodenext\",\n    \"outDir\": \"dist\",\n    \"rootDirs\": &#91;\n      \"src\"\n    ],\n    \"target\": \"es2022\"\n  },\n  \"exclude\": &#91;\n    \"node_modules\"\n  ],\n  \"include\": &#91;\n    \"src\/**\/*\",\n  ]\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run <code>npm install<\/code> to get your (minimal) dependencies installed. Then simply <code>tsc<\/code> to build (<code>tsc -w<\/code> if you want it to auto-build every time you save a file). Host a web server in the project directory to play with the thing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Note the use of an <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTML\/Element\/script\/type\/importmap\">Import Map<\/a> in the HTML so that you can alias \"preact\" in your source. This is so that VS Code gets a clue during development, but your deployed source references a minimalized, standalone library that the Preact folks have conveniently provided (for the cost of a tiny 5kb download).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For lack of some acronym to describe this setup, I'll go with TEMP:  TSX, Ecmascript Modules, Preact.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I decided to learn a bit of React again for some toy projects (my day job JS framework is Angular). Most of the tutorials for setting up a React project &#8220;from scratch&#8221; ultimately result in using the create-react-app library to hide a lot of the complexity (transpilers, bundlers), but I&#8217;m not interested in Webpack or [&#8230;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[38,204,25,11,28],"tags":[],"class_list":["post-1318","post","type-post","status-publish","format-standard","hentry","category-javascript","category-react","category-software","category-technology","category-web"],"_links":{"self":[{"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/posts\/1318","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/comments?post=1318"}],"version-history":[{"count":17,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/posts\/1318\/revisions"}],"predecessor-version":[{"id":1340,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/posts\/1318\/revisions\/1340"}],"wp:attachment":[{"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/media?parent=1318"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/categories?post=1318"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/tags?post=1318"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}