<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>javascript - Hard Wired</title>
	<atom:link href="https://www.hardwired.dev/tag/javascript/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.hardwired.dev</link>
	<description></description>
	<lastBuildDate>Sun, 09 Jun 2024 19:19:18 +0000</lastBuildDate>
	<language>cs</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9</generator>

<image>
	<url>https://www.hardwired.dev/wp-content/uploads/2022/10/android-chrome-256x256-1-150x150.png</url>
	<title>javascript - Hard Wired</title>
	<link>https://www.hardwired.dev</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>NestJS Chapter 01 &#8211; New Project</title>
		<link>https://www.hardwired.dev/2024/06/09/nestjs-chapter-01-new-project/</link>
		
		<dc:creator><![CDATA[John Doe]]></dc:creator>
		<pubDate>Sun, 09 Jun 2024 19:09:38 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[crud]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[endpoint]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[nestjs]]></category>
		<category><![CDATA[nodejs]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[RESTfull]]></category>
		<category><![CDATA[typescript]]></category>
		<guid isPermaLink="false">https://www.hardwired.dev/?p=2235</guid>

					<description><![CDATA[<p>When you use an app, whether it's a web app or a desktop app, that communicates with a remote server &#62;&#62;&#62;</p>
<p>The post <a href="https://www.hardwired.dev/2024/06/09/nestjs-chapter-01-new-project/">NestJS Chapter 01 – New Project</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>When you use an app, whether it's a web app or a desktop app, that communicates with a remote server over the internet, you can be 99% sure there is an API server involved. API servers are the hidden part of the application where almost all the magic happens. One option for creating APIs is <a href="https://docs.nestjs.com/">NestJS</a>, and we will explore it a little bit.</p>
<p><strong>Key Benefits of NestJS:</strong></p>
<ul>
<li><strong>Scalability</strong>: NestJS is built with scalability in mind, making it easy to manage large-scale applications. Its modular architecture allows developers to split their applications into small, reusable modules.</li>
<li><strong>TypeScript Support</strong>: As a framework built on top of TypeScript, NestJS offers all the benefits of TypeScript, including type safety, improved code readability, and maintainability.</li>
<li><strong>Extensive Ecosystem</strong>: NestJS has a rich ecosystem of libraries and tools, which simplifies the development process. It integrates seamlessly with other popular libraries and frameworks like <a href="https://expressjs.com/en/guide/routing.html">Express</a>, <a href="https://fastify.dev/docs/latest/">Fastify</a>, and more.</li>
<li><strong>Ease of Use</strong>: The framework is designed to be developer-friendly, with a well-documented API and a robust CLI that helps in generating boilerplate code, thereby reducing development time.</li>
<li><strong>Dependency Injection</strong>: NestJS uses a powerful dependency injection system, which makes it easier to manage dependencies and promotes better code organization and testability.</li>
</ul>
<blockquote>
<p><strong>Disclaimer:</strong> This article is not primarily intended for people who are new to programming. It is written with the expectation of some experience in programming. To be honest, my motivation for writing this article is to compile my NestJS developer notes, and I've chosen to present them in article form. It will not explain NestJS in detail, nor its architecture. Instead, it will focus on solving specific problems I have encountered. I hope you find it useful. </p>
</blockquote>
<p>In Chapter 1, we will install NestJS and bring the API server to life.</p>
<p>Make sure you are using the latest LTS version of <a href="https://nodejs.org/en">NodeJS</a>.</p>
<p>For project creation and management, we will use <a href="https://docs.nestjs.com/cli/overview">@nestjs/cli</a>. The easiest way is to install it globally.</p>
<pre><code class="language-shell">npm i -g @nestjs/cli</code></pre>
<p>Then, in your projects folder, simply use the <code>nest</code> command to create a new project.</p>
<pre><code class="language-shell">nest new hardwired-nestjs-api-chapter-01</code></pre>
<p>You will be asked which package manager you want to use. I use <code>npm</code>.</p>
<p>When it is done, just delete the <code>.spec.ts</code> files from the <code>src</code> folder. We don't care about tests right now. A bunch of things are already set up, like <code>prettier</code>, <code>eslint</code>, and <code>TypeScript</code> configuration. Useful scripts are prepared in <code>package.json</code>.</p>
<pre><code class="language-json">&quot;scripts&quot;: {
    &quot;build&quot;: &quot;nest build&quot;,
    &quot;format&quot;: &quot;prettier --write \&quot;src/**/*.ts\&quot; \&quot;test/**/*.ts\&quot;&quot;,
    &quot;start&quot;: &quot;nest start&quot;,
    &quot;start:dev&quot;: &quot;nest start --watch&quot;,
    &quot;start:debug&quot;: &quot;nest start --debug --watch&quot;,
    &quot;start:prod&quot;: &quot;node dist/main&quot;,
    &quot;lint&quot;: &quot;eslint \&quot;{src,apps,libs,test}/**/*.ts\&quot; --fix&quot;,
    &quot;test&quot;: &quot;jest&quot;,
    &quot;test:watch&quot;: &quot;jest --watch&quot;,
    &quot;test:cov&quot;: &quot;jest --coverage&quot;,
    &quot;test:debug&quot;: &quot;node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand&quot;,
    &quot;test:e2e&quot;: &quot;jest --config ./test/jest-e2e.json&quot;
  },</code></pre>
<p>For now, we only need <code>start:dev</code> to run the development version. In the <code>src</code> folder, you can find <code>main.ts</code>, which is the entry point to our API, along with <code>app.controller.ts</code>, <code>app.module.ts</code>, and <code>app.service.ts</code>. You can find a perfect explanation of the NestJS architecture in the chapters <a href="https://docs.nestjs.com/controllers">Controllers</a>, <a href="https://docs.nestjs.com/providers">Providers</a>, and <a href="https://docs.nestjs.com/modules">Modules</a> in the NestJS documentation.</p>
<p><code>main.ts</code> is pretty simple. Just includes <code>@netjs/core</code>, <code>app.module</code> and bootstrap our application.</p>
<pre><code class="language-typescript">import { NestFactory } from &#039;@nestjs/core&#039;;
import { AppModule } from &#039;./app.module&#039;;

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}

bootstrap();</code></pre>
<p>When you run <code>npm run start:dev</code>, the API will run on port 3000, and you will be able to access it at <code>http://localhost:3000</code>.</p>
<p>Controllers are where you define your routes. In <code>app.controller.ts</code>, there is one <code>GET</code> route.</p>
<pre><code class="language-typescript">import { Controller, Get } from &#039;@nestjs/common&#039;;
import { AppService } from &#039;./app.service&#039;;

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}</code></pre>
<p>The <code>@Get</code> decorator without parameters in <code>app.controller.ts</code> indicates that you will access this route with <code>/</code>. It's the root route, and you can access it at <code>http://localhost:3000</code>. This route calls the service method <code>getHello()</code>, which returns the string <code>Hello World!</code>. Services are where your business logic resides.</p>
<pre><code class="language-typescript">import { Injectable } from &#039;@nestjs/common&#039;;

@Injectable()
export class AppService {
  getHello(): string {
    return &#039;Hello World!&#039;;
  }
}</code></pre>
<p>You can access <code>http://localhost:3000</code> in your browser, and if the development server is running, you will see <code>Hello World!</code>. However, as an API developer, you may want a better way to call your API during development. I recommend using <a href="https://insomnia.rest/">Insomnia</a>.</p>
<p>When you call <code>http://localhost:3000</code> using Insomnia, you will get the same result as in the browser. However, as you add more routes and JSON responses, you will appreciate the usefulness of Insomnia.</p>
<pre><code>Hello World!</code></pre>
<p><code>Hello World</code> is okay, but not very useful. Let's build something more meaningful.</p>
<p>First, we should discuss how to organize our routes to avoid a mess later. A good way is to organize them into <code>resources</code>. A resource can be <code>user</code>, <code>article</code>, <code>comment</code>, etc. For resource bases, we will use plurals, for example, <code>users</code>, <code>articles</code>, and <code>comments</code>. It is a good practice to follow <a href="https://restfulapi.net/">REST</a> principles when creating an API. One of my favorite articles on this topic is <a href="https://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api">Best Practices for Designing a Pragmatic RESTful API</a>.</p>
<p>Sometimes it is easier for programmers to use just <code>GET</code> and <code>POST</code> methods for all routes, but this does not adhere to <code>RESTful</code> principles. <code>RESTful</code> principles provide strategies to handle <a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a> actions. It is better to use the full potential of <code>HTTP</code> methods. For example, when we take the resource <code>user</code>:</p>
<ul>
<li><code>GET /users</code> - retrieves a list of users</li>
<li><code>GET /users/1</code> - retrieves the user with id 1</li>
<li><code>POST /users</code> - creates a new user</li>
<li><code>PUT /users/1</code> - updates the user with id 1</li>
<li><code>PATCH /users/1</code> - partially updates the user with id 1</li>
<li><code>DELETE /users/1</code> - deletes the user with id 1</li>
</ul>
<p>You can also combine resources. For instance, to get the articles for a user, one route could be <code>GET /users/1/articles</code>.</p>
<p>If you want to like an article, the API endpoint could be <code>PUT /articles/1/like</code>. You can use aliases, filtering, sorting, limiting, and pagination constructs, but this is a complex and highly opinionated field suitable for many articles. I think the best quick dive is provided in the article I mentioned earlier, written by <a href="https://www.vinaysahni.com/">Vinay Sahni</a>.</p>
<p>Earlier in the article, I said &quot;Let's build something more meaningful,&quot; but that was a lie. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /> For a quick demonstration of how to create a resource and follow methods, we will use something completely useless.</p>
<p>We will create a route <code>GET /zodiac-signs</code>. This route will return a list of zodiac signs with date ranges. I borrowed the list from <a href="https://github.com/helmasaur/zodiac-signs/blob/main/data/zodiac.json">here</a>.</p>
<p>To create a NestJS resource, we will use the <code>nest cli</code>.</p>
<pre><code class="language-shell">nest g res zodiac-signs --no-spec</code></pre>
<ul>
<li><code>nest</code> - nest command</li>
<li><code>g</code> - generate</li>
<li><code>res</code> - resource</li>
<li><code>zodiac-sign</code> - resource-name</li>
<li><code>--no-spec</code> - do not generate tests</li>
</ul>
<p>After you enter the command, you will be asked what type of transport layer you want to use. Choose REST API. The next question will be whether you would like to create CRUD entry points. I choose no; I will create them on my own.</p>
<p>When it is done, in your <code>src</code> folder, you will see a folder named <code>zodiac-signs</code>, and it will contain <code>zodiac-signs.controller.ts</code>, <code>zodiac-signs.module.ts</code>, and <code>zodiac-signs.service.ts</code>.</p>
<p>Nest CLI automatically connects your new resource/module to the app.</p>
<p>We will start with <code>zodiac-signs.service.ts</code>.</p>
<pre><code class="language-typescript">import { Injectable } from &#039;@nestjs/common&#039;;

@Injectable()
export class ZodiacSignsService {
    signs = {
        aries: {
            symbol: &#039;&#x2648;&#039;,
            dateMin: &#039;2000-03-21&#039;,
            dateMax: &#039;2000-04-20&#039;,
        },
        taurus: {
            symbol: &#039;&#x2649;&#039;,
            dateMin: &#039;2000-04-21&#039;,
            dateMax: &#039;2000-05-21&#039;,
        },
        gemini: {
            symbol: &#039;&#x264a;&#039;,
            dateMin: &#039;2000-05-22&#039;,
            dateMax: &#039;2000-06-21&#039;,
        },
        cancer: {
            symbol: &#039;&#x264b;&#039;,
            dateMin: &#039;2000-06-22&#039;,
            dateMax: &#039;2000-07-22&#039;,
        },
        leo: {
            symbol: &#039;&#x264c;&#039;,
            dateMin: &#039;2000-07-23&#039;,
            dateMax: &#039;2000-08-22&#039;,
        },
        virgo: {
            symbol: &#039;&#x264d;&#039;,
            dateMin: &#039;2000-08-23&#039;,
            dateMax: &#039;2000-09-23&#039;,
        },
        libra: {
            symbol: &#039;&#x264e;&#039;,
            dateMin: &#039;2000-09-24&#039;,
            dateMax: &#039;2000-10-23&#039;,
        },
        scorpio: {
            symbol: &#039;&#x264f;&#039;,
            dateMin: &#039;2000-10-24&#039;,
            dateMax: &#039;2000-11-22&#039;,
        },
        sagittarius: {
            symbol: &#039;&#x2650;&#039;,
            dateMin: &#039;2000-11-23&#039;,
            dateMax: &#039;2000-12-21&#039;,
        },
        capricorn: {
            symbol: &#039;&#x2651;&#039;,
            dateMin: &#039;2000-12-22&#039;,
            dateMax: &#039;2000-01-20&#039;,
        },
        aquarius: {
            symbol: &#039;&#x2652;&#039;,
            dateMin: &#039;2000-01-21&#039;,
            dateMax: &#039;2000-02-19&#039;,
        },
        pisces: {
            symbol: &#039;&#x2653;&#039;,
            dateMin: &#039;2000-02-20&#039;,
            dateMax: &#039;2000-03-20&#039;,
        },
    };

    findAll() {
        return this.signs;
    }
}</code></pre>
<p>In the <code>ZodiacSignsService</code> class, we have our logic. The list of signs is stored as a class property named <code>signs</code>. The method that returns this list is <code>findAll()</code>. It is a good practice for the route <code>GET /zodiac-signs</code> to use the service method <code>findAll</code>, and for <code>GET /zodiac-signs/:name</code> to use the service method <code>findOne</code>. This uniform naming system will help you orient yourself in a large code base.</p>
<p>Next will be <code>zodiac-signs.controller.ts</code>.</p>
<pre><code class="language-typescript">import { Controller, Get } from &#039;@nestjs/common&#039;;
import { ZodiacSignsService } from &#039;./zodiac-signs.service&#039;;

@Controller(&#039;zodiac-signs&#039;)
export class ZodiacSignsController {
  constructor(private readonly zodiacSignsService: ZodiacSignsService) {}

  @Get()
  findAll() {
    return this.zodiacSignsService.findAll();
  }
}</code></pre>
<p>We create a method <code>findAll</code> decorated with <code>@Get</code> decorator, which, without parameters, instructs the app router to point to the <code>findAll</code> method in the <code>ZodiacSignsController</code> in response to a <code>GET /zodiac-signs</code> request.</p>
<p>That's all for now. Make sure the development server is running (<code>npm run start:dev</code>). Then, you can access <code>http://localhost:3000/zodiac-signs</code>. The expected result is the same JSON as we have in <code>ZodiacSignsService</code>.</p>
<p>Okay, it's not much, but it's enough to get started. In the next chapter, we'll take a look at DTOs (Data Transfer Objects).</p>
<p>You can find project on my <a href="https://github.com/eduardtomasek/hardwired-nestjs-chapter-01-new-project">GitHub</a>.</p>
<p>Happy coding!</p>

<div class="twitter-share"><a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fwww.hardwired.dev%2F2024%2F06%2F09%2Fnestjs-chapter-01-new-project%2F&#038;via=hessevalentino" class="twitter-share-button">Tweet</a></div><p>The post <a href="https://www.hardwired.dev/2024/06/09/nestjs-chapter-01-new-project/">NestJS Chapter 01 – New Project</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to create TypeScript NPM package project</title>
		<link>https://www.hardwired.dev/2024/05/26/how-to-create-typescript-npm-package-project/</link>
		
		<dc:creator><![CDATA[John Doe]]></dc:creator>
		<pubDate>Sun, 26 May 2024 13:46:32 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[nodejs]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[typescript]]></category>
		<guid isPermaLink="false">https://www.hardwired.dev/?p=2200</guid>

					<description><![CDATA[<p>Sometimes you want to create your own npm package. Here is the way to set up an npm package in &#62;&#62;&#62;</p>
<p>The post <a href="https://www.hardwired.dev/2024/05/26/how-to-create-typescript-npm-package-project/">How to create TypeScript NPM package project</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>Sometimes you want to create your own <a href="https://www.npmjs.com/"><code>npm</code></a> package. Here is the way to set up an <code>npm</code> package in <a href="https://www.typescriptlang.org/"><code>TypeScript</code></a>.</p>
<p>In your project directory, initialize the <code>npm</code> object.</p>
<pre><code class="language-bash">npm init</code></pre>
<p>Install development dependencies.</p>
<pre><code class="language-bash">npm install --save-dev typescript ts-node</code></pre>
<p><code>ts-node</code> enables you to directly execute <code>TypeScript</code> on <a href="https://nodejs.org/en"><code>Node.js</code></a>. See more on the <a href="https://www.npmjs.com/package/ts-node">package website</a>.</p>
<p>Set up the <code>TypeScript</code> project.</p>
<pre><code class="language-bash">npx tsc --init</code></pre>
<p>In the generated <code>tsconfig.json</code>, set <code>outDir</code> to <code>dist</code>.</p>
<pre><code class="language-json">...
&quot;outDir&quot;: &quot;./dist&quot;, /* Specify an output folder for all emitted files. */
...</code></pre>
<p>In the root directory, create the <code>src</code> folder and in the folder <code>index.ts</code> which will be the entry point in your package.</p>
<pre><code class="language-bash">mkdir src
touch ./src/index.ts</code></pre>
<p>Create a <code>.gitignore</code> file.</p>
<pre><code class="language-ini">/node_modules
# Ignore test-related files
/coverage.data
/coverage/
# Build files
/dist</code></pre>
<p>Install the <a href="https://www.npmjs.com/package/tsup"><code>tsup</code></a> package. It is a <code>bundler</code> and is powered by <a href="https://github.com/evanw/esbuild"><code>esbuild</code></a>.</p>
<blockquote>
<p>In the context of JavaScript, a <strong>bundler</strong> is a tool that takes multiple JavaScript files and their dependencies and combines them into a single file or a few files, which can then be included in a web application. The main purpose of a bundler is to manage and optimize the delivery of code to the browser, enhancing performance and simplifying development.</p>
</blockquote>
<pre><code class="language-bash">
npm install --save-dev tsup</code></pre>
<p>In the root directory, create the <code>tsup.config.ts</code> file.</p>
<pre><code class="language-typescript">import { defineConfig } from &quot;tsup&quot;;
export default defineConfig({
entry: [&quot;src/index.ts&quot;],
format: [&quot;cjs&quot;, &quot;esm&quot;], // Build for commonJS and ESmodules
dts: true, // Generate declaration file (.d.ts)
splitting: false,
sourcemap: true,
clean: true,
});</code></pre>
<p>Update these properties in <code>package.json</code></p>
<pre><code class="language-json">...
&quot;main&quot;: &quot;./dist/index.js&quot;,
&quot;module&quot;: &quot;./dist/index.mjs&quot;,
&quot;types&quot;: &quot;./dist/index.d.ts&quot;,
&quot;files&quot;: [
    &quot;dist&quot;
],
&quot;scripts&quot;: {
    &quot;build&quot;: &quot;tsup&quot;
},
...</code></pre>
<p>In your <code>index.ts</code>, create a trivial function you will export in this package.</p>
<pre><code class="language-typescript">export function add(a: number, b: number): number {
  return a + b;
}</code></pre>
<p>Build your package with <code>npm run build</code>. In the <code>dist</code> directory, you will see the build of your project.</p>
<p>TADA! Now you have a base project for your <code>npm</code> package.</p>

<div class="twitter-share"><a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fwww.hardwired.dev%2F2024%2F05%2F26%2Fhow-to-create-typescript-npm-package-project%2F&#038;via=hessevalentino" class="twitter-share-button">Tweet</a></div><p>The post <a href="https://www.hardwired.dev/2024/05/26/how-to-create-typescript-npm-package-project/">How to create TypeScript NPM package project</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to create a new TypeScript project</title>
		<link>https://www.hardwired.dev/2024/05/25/how-to-create-a-new-typescript-project/</link>
		
		<dc:creator><![CDATA[John Doe]]></dc:creator>
		<pubDate>Sat, 25 May 2024 06:01:43 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[gts]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[nodejs]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[typescript]]></category>
		<guid isPermaLink="false">https://www.hardwired.dev/?p=2197</guid>

					<description><![CDATA[<p>TypeScript compared to JavaScript is a little bit more complex. If you do server-side JavaScript, you just call node your-script.js &#62;&#62;&#62;</p>
<p>The post <a href="https://www.hardwired.dev/2024/05/25/how-to-create-a-new-typescript-project/">How to create a new TypeScript project</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>TypeScript compared to JavaScript is a little bit more complex. If you do server-side JavaScript, you just call <code>node your-script.js</code> and it runs. When you want to use TypeScript, you need to install a few things and do a few steps to make your code runnable.</p>
<blockquote>
<p>Make sure you have installed the latest version of <code>nodejs</code> on your system.</p>
</blockquote>
<p>Create your project folder, change the current working directory, and install <code>typescript</code> as your development dependency.</p>
<pre><code class="language-bash">npm i -D typescript</code></pre>
<p>Initialize your <code>nodejs</code> project.</p>
<pre><code class="language-bash">npm init</code></pre>
<p>Then use <code>npx</code> to initialize a new <code>typescript</code> project.</p>
<pre><code class="language-bash">npx tsc --init</code></pre>
<p>A bunch of files should be in your project:</p>
<ul>
<li>package.json</li>
<li>package-lock.json</li>
<li>tsconfig.json</li>
</ul>
<p>Edit <code>tsconfig.json</code>, find <code>outDir</code>, and change it if you do not want compiled files in your root directory. Change it to the <code>build</code> folder.</p>
<pre><code class="language-json">...
outDir&quot;: &quot;./build&quot;,   /* Specify an output folder for all emitted files. */
...</code></pre>
<p>Now it's time to create your first TypeScript code.</p>
<p>Create a file <code>index.ts</code> and just put some random code.</p>
<pre><code class="language-typescript">async function main() {
    const i: number = 1;

    console.log(&#039;Random stuff&#039;, i);
}

main()</code></pre>
<p>Save it and then you can do a manual compilation.</p>
<pre><code class="language-bash">npx tsc</code></pre>
<p>This compiles your project and the output will be stored in the <code>build</code> folder. You will find the file <code>index.js</code> there. Do a test run with <code>node ./build/index.js</code>.</p>
<p>In the console, you should see:</p>
<pre><code class="language-bash">Random stuff 1</code></pre>
<p>You can use <code>npx tsc -w</code> to activate watch mode. When you change anything in your project, it will be recompiled automatically.</p>
<p>To make it a little bit easier, you can edit the <code>scripts</code> property in <code>package.json</code> to merge compilation and run into one command.</p>
<pre><code class="language-json">...
&quot;scripts&quot;: {
        &quot;start&quot;: &quot;npx tsc &amp;&amp; node ./build/index.js&quot;
},
...</code></pre>
<p>When you call <code>npm run start</code>, your project will be compiled and run.</p>
<p>During code development, you should use a linter to check your code using certain rules to avoid code inconsistency. An easy way is to use <code>Google TypeScript Style</code>.</p>
<p>Install <code>gts</code> as a development dependency.</p>
<pre><code class="language-bash">npm i -D gts</code></pre>
<p>Then initialize <code>gts</code> with <code>npx</code>.</p>
<pre><code class="language-bash">npx gts init</code></pre>
<p>It will ask you some questions. If your <code>typescript</code> version is higher than suggested, just say no. Then you will be asked about updating <code>tsconfig.json</code>, say yes.</p>
<p>Some big changes will be made.</p>
<p>The <code>src</code> folder will be created with an <code>index.ts</code> file in it. Remove your old <code>index.ts</code> from the root folder.</p>
<p>In <code>package.json</code>, update your start script.</p>
<pre><code class="language-json">...
&quot;start&quot;: &quot;npx tsc &amp;&amp; node ./build/src/index.js&quot;,
...</code></pre>
<blockquote>
<p>Make sure you have <code>eslint</code> support activated in your editor</p>
</blockquote>
<p>You will get an <code>index.ts</code> example file in the <code>src</code> directory. It is all wrong. If you have <code>eslint</code> support activated in your editor, it should scream at you with lots of errors.</p>
<pre><code class="language-typescript">console.log(&quot;Try npm run lint/fix!&quot;);

const longString = &#039;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer ut aliquet diam.&#039;;

const trailing = &#039;Semicolon&#039;

            const why={am:&#039;I tabbed?&#039;};

const iWish = &quot;I didn&#039;t have a trailing space...&quot;; 

const sicilian = true;;

const vizzini = (!!sicilian) ? !!!sicilian : sicilian;

const re = /foo   bar/;

export function doSomeStuff(withThis: string, andThat: string, andThose: string[]) {
    //function on one line
    if(!Boolean(andThose.length)) {return false;}
    console.log(withThis);
    console.log(andThat);
    console.dir(andThose);
    console.log(longString, trailing, why, iWish, vizzini, re);
    return;
}
// TODO: more examples</code></pre>
<p>Just run <code>npm run fix</code> to let <code>gts</code> fix your code. You will get this:</p>
<pre><code class="language-typescript">console.log(&#039;Try npm run lint/fix!&#039;);

const longString =
  &#039;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer ut aliquet diam.&#039;;

const trailing = &#039;Semicolon&#039;;

const why = {am: &#039;I tabbed?&#039;};

const iWish = &quot;I didn&#039;t have a trailing space...&quot;;

const sicilian = true;

const vizzini = sicilian ? !sicilian : sicilian;

const re = /foo {3}bar/;

export function doSomeStuff(
  withThis: string,
  andThat: string,
  andThose: string[]
) {
  //function on one line
  if (!andThose.length) {
    return false;
  }
  console.log(withThis);
  console.log(andThat);
  console.dir(andThose);
  console.log(longString, trailing, why, iWish, vizzini, re);
  return;
}
// TODO: more examples</code></pre>
<p>If it is working, you have just created your <code>typescript</code> project with a linter. It is a good thing to configure your code editor to perform <code>npm run fix</code> with every save.</p>
<p>Enjoy TypeScript coding.</p>

<div class="twitter-share"><a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fwww.hardwired.dev%2F2024%2F05%2F25%2Fhow-to-create-a-new-typescript-project%2F&#038;via=hessevalentino" class="twitter-share-button">Tweet</a></div><p>The post <a href="https://www.hardwired.dev/2024/05/25/how-to-create-a-new-typescript-project/">How to create a new TypeScript project</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Puppeteer download BOT</title>
		<link>https://www.hardwired.dev/2022/10/31/puppeteer-download-bot/</link>
		
		<dc:creator><![CDATA[John Doe]]></dc:creator>
		<pubDate>Mon, 31 Oct 2022 13:35:28 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Různé]]></category>
		<category><![CDATA[bot]]></category>
		<category><![CDATA[chrome]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[headless]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[nodejs]]></category>
		<category><![CDATA[puppeteer]]></category>
		<category><![CDATA[scraping]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[web-scraping]]></category>
		<guid isPermaLink="false">http://wordpress.hardwired.dev/?p=774</guid>

					<description><![CDATA[<p>O co jde Uděláme bota co načte webovou stránku, klikne na čudlík a stáhne soubor. Použijeme k tomu knihovnu Puppeteer &#62;&#62;&#62;</p>
<p>The post <a href="https://www.hardwired.dev/2022/10/31/puppeteer-download-bot/">Puppeteer download BOT</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><h1>O co jde</h1>
<p>Uděláme bota co načte webovou stránku, klikne na čudlík a stáhne soubor.</p>
<p>Použijeme k tomu knihovnu <a href="https://pptr.dev/" title="Puppeteer">Puppeteer</a> a samotný kód budeme pouštět v <a href="https://www.docker.com/" title="Dockeru">Dockeru</a>.</p>
<blockquote>
<p>Větší podrobnosti a vysvětlení zakládání NodeJs projektu v Dockeru najde v článku <a href="http://wordpress.hardwired.dev/nodejs-develompent-v-dockeru/" title="NodeJS develompent v Dockeru">NodeJS develompent v Dockeru</a>.</p>
</blockquote>
<h1>Příprava projektu</h1>
<p>Založíme nový projekt:</p>
<pre><code class="language-shell">mkdir puppet
cd puppet
npm init -y</code></pre>
<p>Upravíme <code>package.json</code> a přidáme do něj knihovnu <code>puppeteer</code>:</p>
<pre><code class="language-json">{
  &quot;name&quot;: &quot;puppet&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;description&quot;: &quot;&quot;,
  &quot;main&quot;: &quot;index.js&quot;,
  &quot;scripts&quot;: {
    &quot;start&quot;: &quot;node index.js&quot;
  },
  &quot;keywords&quot;: [],
  &quot;author&quot;: &quot;&quot;,
  &quot;license&quot;: &quot;ISC&quot;,
  &quot;dependencies&quot;: {
    &quot;puppeteer&quot;: &quot;^19.2.0&quot;
  }
}</code></pre>
<p>Vytvoříme <code>Dockerfile</code>, který použije jako základ obraz s <code>node v16</code>, nainstaluje <code>Chrome prohlížeč</code> a nakopíruje projekt do Docker obrazu.</p>
<pre><code class="language-shell">FROM node:16

RUN apt-get update &amp;&amp; apt-get install gnupg wget -y &amp;&amp; \
  wget --quiet --output-document=- https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor &gt; /etc/apt/trusted.gpg.d/google-archive.gpg &amp;&amp; \
  sh -c &#039;echo &quot;deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main&quot; &gt;&gt; /etc/apt/sources.list.d/google.list&#039; &amp;&amp; \
  apt-get update &amp;&amp; \
  apt-get install google-chrome-stable -y --no-install-recommends &amp;&amp; \
  rm -rf /var/lib/apt/lists/*

ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
    PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome-stable

WORKDIR /app
COPY package*.json .
RUN npm install
COPY . ./</code></pre>
<p>Vytvoříme <code>index.js</code> soubor a necháme ho jen vypsat zprávu do konzole.</p>
<pre><code class="language-shell">touch index.js</code></pre>
<pre><code class="language-javascript">console.log(&#039;Hello from docker&#039;)</code></pre>
<p>Není úplně špatné vytvořit i <code>.dockerignore</code> soubor.</p>
<pre><code class="language-shell">node_modules
Dockerfile
.dockerignore
.git
.gitignore
README.md
docker-compose*</code></pre>
<p>Sestavíme obraz.</p>
<pre><code class="language-shell">docker build -t puppet-app-image .</code></pre>
<p>A spustíme Docker kontejner.</p>
<pre><code class="language-bash"># %cd% je aktuální složka ve Windows, pro jiné systémy použijte adekvátní náhradu

docker run -d --tty --name puppet-app -v %cd%:/app -v /app/node_modules puppet-app-image</code></pre>
<blockquote>
<p>--tty parametr je nutný. V opačném případě se Docker kontejner spustí a pak hned úspěšně ukončí. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Za normálních okolností předpokládá, že v něm něco poběží a až se to ukončí tak skončí taky. TTY toto chování potlačí.</p>
</blockquote>
<p>Jakmile kontejner běží, můžeme se do něj přihlásit:</p>
<pre><code class="language-shell">docker exec -it puppet-app bash</code></pre>
<p>Vevnitř se ocitneme ve složce <code>/app</code>, kde je náš projekt a můžeme zkusit spustit náš program.</p>
<pre><code class="language-shell">nodejs index.js</code></pre>
<p>Měl by nám odpovědět <code>Hello from docker</code>.</p>
<h1>Bot</h1>
<p>Pro ukázku bude bot stahovat zdrojový kód puppeteeru z githubu. Upravíme <code>index.js</code> následovně.</p>
<pre><code class="language-javascript">const puppeteer = require(&#039;puppeteer&#039;)

;(async () =&gt; {
    const browser = await puppeteer.launch({
        headless: true,
        args: [&#039;--no-sandbox&#039;],
    })

    const page = await browser.newPage()
    page.setViewport({ width: 1920, height: 1080 })

    const client = await page.target().createCDPSession()
    await client.send(&quot;Page.setDownloadBehavior&quot;, {
        behavior: &quot;allow&quot;,
        downloadPath: &#039;./&#039;
    })

    await page.goto(
        &#039;https://github.com/puppeteer/puppeteer/releases/tag/puppeteer-core-v19.2.0&#039;,
        { waitUntil: &#039;networkidle2&#039; }
    )
    await page.waitForTimeout(1000)

    await page.click(&#039;#repo-content-turbo-frame div.mb-3 &gt; details &gt; div &gt; div &gt; ul &gt; li:nth-child(1) &gt; div.d-flex.flex-justify-start.col-12.col-lg-9 &gt; a&#039;)
    await page.waitForTimeout(5000)

    await page.screenshot({ path: &#039;./screen.jpg&#039;, fullPage: true })

    await browser.close()
})()</code></pre>
<p>Naimportujeme do našeho projektu knihovnu <code>puppeteer</code>.</p>
<pre><code class="language-javascript">const puppeteer = require(&#039;puppeteer&#039;)</code></pre>
<p>Budeme volat asynchronní funkce v java scriptu a budeme používat klíčové slovo <code>await</code>, které čeká na provedení asynchronní funkce. Problém je to, že <code>await</code> se může objevit jen v asynchronní funkci. Tudíž náš kód musíme do jedné takové zabalit a rovnou spustit.</p>
<pre><code class="language-javascript">;(async () =&gt; {
    // code
})()</code></pre>
<p>Vytvoříme nový <code>headless prohlížeč</code>.</p>
<pre><code class="language-javascript">const browser = await puppeteer.launch({
    headless: true,
    args: [&#039;--no-sandbox&#039;],
})</code></pre>
<p>Vytvoříme novou <code>stránku/tab</code> a nastavíme rozlišení.</p>
<pre><code class="language-javascript">const page = await browser.newPage()
page.setViewport({ width: 1920, height: 1080 })</code></pre>
<p>Pro tuto konkrétní stránku nastavíme automatické stahovaní do určitého adresáře. V našem případě adresář s projektem. Takhle nebudeme vyvolávat dialog pro umístění stahovaného souboru.</p>
<pre><code class="language-javascript">const client = await page.target().createCDPSession()
await client.send(&quot;Page.setDownloadBehavior&quot;, {
    behavior: &quot;allow&quot;,
    downloadPath: &#039;./&#039;
})</code></pre>
<p>V naší <code>stránce/tabu</code> otevřeme požadovanou github stránku.</p>
<pre><code class="language-javascript">await page.goto(
    &#039;https://github.com/puppeteer/puppeteer/releases/tag/puppeteer-core-v19.2.0&#039;,
    { waitUntil: &#039;networkidle2&#039; }
)
await page.waitForTimeout(1000)</code></pre>
<p>Klikneme na odkaz pro stažení a chvíli počkáme, než se soubor stáhne <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<pre><code class="language-javascript">await page.click(&#039;#repo-content-turbo-frame div.mb-3 &gt; details &gt; div &gt; div &gt; ul &gt; li:nth-child(1) &gt; div.d-flex.flex-justify-start.col-12.col-lg-9 &gt; a&#039;)
await page.waitForTimeout(5000)</code></pre>
<p>K definování toho na co se má kliknout se používá <a href="https://www.w3schools.com/CSSREF/css_selectors.php" title="CSS Selector">CSS Selector</a> (<a href="https://drafts.csswg.org/selectors/" title="draft">draft</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors" title="mdn">mdn</a>). Ten pomocí html elementů, tříd, atributů a dalších dokáže sestavit unikátní cestu k prvku na stránce. Stránky generované nějakým frameworkem umí potrápit i s takhle dlouhým selektorem, jako v tomto případě.</p>
<p><img decoding="async" src="http://wordpress.hardwired.dev/wp-content/uploads/2022/10/githubsource.jpg" alt="" /></p>
<p>Pak už si jen uděláme momentku, v jakém stavu stránku opouštíme.</p>
<pre><code class="language-javascript">await page.screenshot({ path: &#039;./screen.jpg&#039;, fullPage: true })</code></pre>
<p>A prohlížeč korektně zavřeme.</p>
<pre><code class="language-javascript">await browser.close()</code></pre>
<h1>Spuštění kódu</h1>
<p>V konzoli se připojíme k našemu kontejneru.</p>
<pre><code class="language-bash">docker exec -it puppet-app bash</code></pre>
<p>A spustíme našeho bota.</p>
<pre><code class="language-bash">node index.js</code></pre>
<p>Pokud vše proběhne, jak má, tak ve složce projektu budete mít jak stažený soubor, tak fotku stránky těsně před tím než jste ji opustili.</p>
<p><img decoding="async" src="http://wordpress.hardwired.dev/wp-content/uploads/2022/10/puppeteer_screen.jpg" alt="" /></p>
<p>Toto je velice hrubý nástřel toho, co Puppeteer dokáže na konkrétním případě. Výhodou je, že se opravdu spustí prohlížeč, ve kterém můžeme ovládat i dynamicky generované <code>single page</code> aplikace. Nevýhodou je, že pokud se struktura stránky změní moc, tak musíte upravit i váš kód.</p>
<p>Happy coding!</p>

<div class="twitter-share"><a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fwww.hardwired.dev%2F2022%2F10%2F31%2Fpuppeteer-download-bot%2F&#038;via=hessevalentino" class="twitter-share-button">Tweet</a></div><p>The post <a href="https://www.hardwired.dev/2022/10/31/puppeteer-download-bot/">Puppeteer download BOT</a> first appeared on <a href="https://www.hardwired.dev">Hard Wired</a>.</p>]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
