<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Meditator Gu</title>
    <description>The latest articles on DEV Community by Meditator Gu (@meditatorgu).</description>
    <link>https://dev.to/meditatorgu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2952586%2Fdaaa1b36-9bb2-463a-be59-e4a30302f7d5.jpeg</url>
      <title>DEV Community: Meditator Gu</title>
      <link>https://dev.to/meditatorgu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/meditatorgu"/>
    <language>en</language>
    <item>
      <title>Null&gt;=0 And Undefined&gt;=0 Have Opposite Result Values</title>
      <dc:creator>Meditator Gu</dc:creator>
      <pubDate>Wed, 19 Mar 2025 14:12:19 +0000</pubDate>
      <link>https://dev.to/meditatorgu/null0-and-undefined0-have-opposite-result-values-1543</link>
      <guid>https://dev.to/meditatorgu/null0-and-undefined0-have-opposite-result-values-1543</guid>
      <description>&lt;p&gt;Recently, I unified the use of null and undefined in the project according to a technical specification of the company. The variables in some scenarios, whose initial values ​​were undefined, are now changed to null.&lt;/p&gt;

&lt;p&gt;After the modification, I found a strange bug that I couldn't find no matter how hard I tried. The logic of the code from top to bottom was normal, but at the end it threw an exception that shouldn't have been thrown.&lt;/p&gt;

&lt;p&gt;So I cloned the code again and restored it to the state before the modification. Then I ran the code before and after the modification at the same time. I found that when the code came to an if branch, one of them entered the if branch and the other jumped over it. The if branch looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pageKidsCountCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentNode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Skip nodes where the page can't be.&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;currentPageIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;pageIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;currentPageIndex&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The value count retrieved from the Map is sometimes empty, that is, undefined. In this case, I changed it to null. Then something went wrong. When the count value was undefined, count&amp;gt;=0 was false. But after changing it to null, it became true. This caused a strange problem.&lt;/p&gt;

&lt;p&gt;I entered it twice in the Chrome console and found that JavaScript is indeed like this.&lt;br&gt;
The result value of null&amp;gt;=0 is true, while the result value of undefined&amp;gt;=0 is false.&lt;/p&gt;

&lt;p&gt;To further alleviate my confusion, I consulted some documents. The data shows that:&lt;br&gt;
When using relational operators, JavaScript converts non-numeric operands to numbers. By default, null is converted to 0, and undefined is converted to NaN. Because 0&amp;gt;=0, null&amp;gt;=0 is true, and NaN is false when compared to any number, so the value of undefined&amp;gt;=0 is false.&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>TypeScript From The Perspective Of A Java Programmer (I)</title>
      <dc:creator>Meditator Gu</dc:creator>
      <pubDate>Wed, 19 Mar 2025 13:31:12 +0000</pubDate>
      <link>https://dev.to/meditatorgu/typescript-from-the-perspective-of-a-java-programmer-i-243h</link>
      <guid>https://dev.to/meditatorgu/typescript-from-the-perspective-of-a-java-programmer-i-243h</guid>
      <description>&lt;p&gt;A while ago, I used TypeScript to refactor a JavaScript project. But before that, I was a developer specializing in Java. In the field of business system development, I mainly study SpringBoot, MyBatis, Tomcat, microservice technology, databases, etc. I have also basically learned some big data-related technologies, such as Hadoop, HBase, and Hive, and developed a big data system for a year. For other languages ​​and related technologies, whether for development or for writing scripts, I have more or less dabbled in some of them. For example, writing bash scripts in Linux, writing Powershell scripts under Windows, using Python to build a simple server that provides algorithm functions, and using jQuery to write some simple web pages. Because of different usage scenarios and different problems faced, the related development modes, code writing methods, component ecology, and even the way programmers think about problems are very different.&lt;/p&gt;

&lt;p&gt;Before I learned TypeScript systematically, I occasionally wrote some TypeScript code as an amateur front-end developer. I copied other people's code, modified it, and met some less complex requirements. Some of these copied codes were from netizens, some were official website examples, and some were already written by my colleagues. When I just graduated, I used WebStorm to write front-end code, but in recent years I have gradually changed to VSCode. Compared with the front-end, the development environment IDEA mainly used by back-end development has a higher degree of tool integration. If the project and tools are configured correctly, then developers actually do not need to open the command line, and many things can be done very well by clicking buttons. For example, developers can import dependencies, run code, compile jar packages, etc. by clicking menus and buttons. IDEA will execute related commands on behalf of developers. It is relatively convenient and fast. However, for the front-end, if you want to develop a project well or manage a project well, the understanding of the tool chain is much higher than that of the back-end. This is the first big difference between them.&lt;/p&gt;

&lt;p&gt;When I decided to use TypeScript to develop some programs systematically, I first had to choose a suitable project creation tool. The competition for project creation tools in the front-end is more intense than that in the back-end. The back-end is basically Maven. Although there are some other competitors in this regard, such as Gradle. But the developers I know will choose Maven. On the back-end, you only need to click on the interface to create a project through IDEA and Spring Initializer. The front-end requires some commands to do these things. For me, the first is npm, then pnpm, and finally vite. After doing these, I still need to spend some time on some configuration files, such as &lt;code&gt;tsconfig.json&lt;/code&gt;, &lt;code&gt;vite.config.js&lt;/code&gt;, &lt;code&gt;package.json&lt;/code&gt;, etc. Make sure that the project built by these files meets my expectations.&lt;/p&gt;

&lt;p&gt;JavaScript's flexibility allows it to run not only in the browser, but also in node. Once it runs in node, it can be an http-server or a scripting language like bash. When I first started learning TypeScript, I was quite confused about this. The same JavaScript code will be subject to different constraints due to the different running environments. In the browser, I can use window to get global variables and use document to create DOM elements, but I can't do that in the node environment. Similarly, in the node environment, I can use the path library to read and write local files, but I can't do that in the browser. Even the debugging methods are quite different. If it is node code, then the debugging method is similar to Java. Just start the code in debug mode. But if it is for the browser, it is relatively troublesome. You need to configure the browser to open it in debug mode first, and then connect to the browser's remote debugging port through socket. Finally, you must ensure that the mapping of the execution code to the source code is correct.&lt;/p&gt;

&lt;p&gt;After solving the problems of project creation and configuration, it is time to officially start writing code. Java and TypeScript are very similar in terms of code writing. They are both descendants of the C language family and are both object-oriented. However, the historical burden of TypeScript is much heavier than that of Java. TypeScript has to be as compatible with JavaScript as possible and take on the responsibility of object-oriented, which faces great challenges. The only historical burden of Java that I know is that it is a generic erasure. JavaScript itself is flexible to write, and it was quite practical in the past when the source code of several web pages on a website was independent of each other. But now I have to develop more complex code. What I developed is a library containing more than 100,000 lines of code. JavaScript is a bit overwhelmed. The lack of clear calling relationships, unclear parameter types, and lack of support for polymorphism are quite fatal. Unfortunately, as a front-end language, TypeScript will eventually be compiled into JavaScript, and it is still limited by some designs and defects of JavaScript.&lt;/p&gt;

&lt;p&gt;When I tried to write code in an object-oriented way, the first limitation I encountered was that the interface in TypeScript would be erased after compilation. The interface in TypeScript is more like an upgraded version of JSDoc than a specific type. It is deeply involved in the code development process, providing developers with important type information, while also restricting developers from writing non-standard code, but it disappears quietly after compilation. Its quiet disappearance makes it impossible for me to use instanceof to determine whether an object implements this interface during the development process. This is a pity.&lt;/p&gt;

&lt;p&gt;The status of the interface in the object-oriented code development process needs no further explanation. Many specifications emphasize the importance of interfaces. For example, the Dependency Inversion Principle in the six principles of design patterns emphasizes programming for interfaces rather than specific classes. By reading the definitions of the relevant methods in the interface, we can understand the capabilities of this interface at a glance without having to go back and forth to the specific implementation code. If the type declared for the variable is an interface rather than a specific class, it will be easy to replace or rewrite the class in the future. In the interaction between components, all APIs of a component are declared in the form of interfaces, and an independent module is extracted. The caller calls the interface through this interface module, and the implementer makes a specific implementation in another module. This is a very good way to decouple. In general, the interface in TypeScript does have some shortcomings due to the problem of interface erasure. However, it also provides most of the capabilities required by the interface feature. Interfaces in TypeScript support polymorphism, which surprised me because JavaScript does not support polymorphism. However, TypeScript interfaces can declare methods with the same name but different parameters. However, in the implementation process, there can only be one function to implement all interfaces with the same name.&lt;/p&gt;

&lt;p&gt;Null and undefined in TypeScript is another confusing problem I encountered. If we consider the equality symbol "===" together, it will be even more confusing. In Java, there is only one kind of null, that is null. Although some reports claim that the problems caused by null pointers have caused a lot of loss of business value. In the actual development process, null pointers are indeed very common. But there has been no good way to deal with this problem. I have written some C# before. In C#, the type must be separately declared whether it is null or not, which surprised me at the time. But what surprised me more was that TypeScript not only has null, but also undefined. These things are mixed together, and it is indeed more difficult to deal with. Although there are some related switches in tsconfig that can turn off the detection of null or not distinguish between null and undefined, in fact, for higher code quality, I cannot turn them off. In the process of declaring a variable, both null and undefined must be reflected. This will make the code very lengthy. For example, the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a simple name declaration, null and undefined occupy half of the space, but only provide a little useful information. If they appear in large numbers in the code, the proportion of code with business meaning will be much less. Mixing them will also cause some problems. I can give two examples that I have actually encountered.&lt;/p&gt;

&lt;p&gt;The first example is when using the strict equality check, null !== undefined. That is, null and undefined are not strictly equal. If you want to clearly check that person.name is not null, you need to write more code and do more work. Write it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is actually unnecessary. Spending more time and energy on the matter of judging null will reduce the time and energy spent on specific function development. Tools serve developers, and developers need to understand tools, but they should not always deal with some special problems of tools.&lt;/p&gt;

&lt;p&gt;The second example is a bug I encountered. After a long time of locating, I found that it was caused by the different truth and falsehood of &lt;code&gt;null &amp;gt;= 0&lt;/code&gt; and &lt;code&gt;undefined &amp;gt;= 0&lt;/code&gt;. The value of &lt;code&gt;null &amp;gt;= 0&lt;/code&gt; is true, while the value of &lt;code&gt;undefined &amp;gt;= 0&lt;/code&gt; is false. If a variable x of type number can be null or undefined, then the writing of &lt;code&gt;x &amp;gt;= 0&lt;/code&gt; may cause some strange problems in some special scenarios.&lt;/p&gt;

&lt;p&gt;In the TypeScript project I'm responsible for, I choose to use null extensively and use undefined cautiously. When necessary, I need to set the variable with the value of undefined to null in time. After all, the specific semantics and functions of undefined and null are different. You can't generalize them or simply use only one of them.&lt;/p&gt;

&lt;p&gt;In addition to the two issues mentioned above, in the process of systematically learning and using TypeScript extensively, I also found that TypeScript has made a lot of efforts to make up for the shortcomings of JavaScript in object-oriented development. As a Java developer, I know the role of these syntaxes very well. For example, the return type of a function is &lt;code&gt;never&lt;/code&gt;, &lt;code&gt;assert crond&lt;/code&gt;, &lt;code&gt;arg is number&lt;/code&gt;. JavaScript is not object-oriented at all. TypeScript wants to be more thorough in object-oriented. Therefore, we have to use something like an adapter to ease the contradiction between the two languages.&lt;/p&gt;

&lt;p&gt;I will share my views on these issues in detail in subsequent blogs. Welcome to leave a message or send a private message to discuss with me.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>typescript</category>
      <category>development</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Share A Open Source Web Image Editing Library -- Based On Fabric</title>
      <dc:creator>Meditator Gu</dc:creator>
      <pubDate>Tue, 18 Mar 2025 10:36:14 +0000</pubDate>
      <link>https://dev.to/meditatorgu/share-a-open-source-web-image-editing-library-based-on-fabric-4el2</link>
      <guid>https://dev.to/meditatorgu/share-a-open-source-web-image-editing-library-based-on-fabric-4el2</guid>
      <description>&lt;p&gt;A while ago, I helped a client solve a picture editing problem that their product was facing. After taking photos, their users needed to annotate them and then upload them to the system. In order to simplify this process, I developed a picture editing library for their system and completed the integration work with the client. In this way, they can directly edit pictures and upload them directly, saving their users a lot of unnecessary operations. This library is now officially providing services to their users.&lt;/p&gt;

&lt;p&gt;The main technologies of this project are TypeScript and FabricJS (version 6.4.3).&lt;/p&gt;

&lt;p&gt;To show you this web image editing library, I have provided two online examples using Github Pages. Click to experience:&lt;/p&gt;

&lt;p&gt;Example 1: Edit An Image Directly&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmj7bhs0ww2ynfk0tr1vl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmj7bhs0ww2ynfk0tr1vl.png" alt="Editing an image directly" width="800" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://xingshen24.github.io/online-image-editor/index.html" rel="noopener noreferrer"&gt;https://xingshen24.github.io/online-image-editor/index.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Example 2: Select An Image To Edit&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fya8x2obdx8jxy8ddt0nn.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fya8x2obdx8jxy8ddt0nn.gif" alt="Select an image to edit" width="800" height="726"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://xingshen24.github.io/online-image-editor/example.html" rel="noopener noreferrer"&gt;https://xingshen24.github.io/online-image-editor/example.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The source code of this project has been hosted on Github:&lt;br&gt;
&lt;a href="https://github.com/xingshen24/online-image-editor" rel="noopener noreferrer"&gt;https://github.com/xingshen24/online-image-editor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This library already has the basic functions that an online image editor should have. These functions are mainly divided into three categories.&lt;/p&gt;

&lt;p&gt;The first category of functions is to add some annotations to the picture. This category of functions includes six basic annotation drawing operations, namely rectangle, circle, arrow, brush, text, mosaic drawing, in addition to this, there is also a base map dragging function.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2tiea4xnpn3aqbkib2d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2tiea4xnpn3aqbkib2d.png" alt="annotations" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second category of functions is the operation of the image itself, including zooming in, zooming out, extending and shrinking blank areas, rotating, flipping, and cropping.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F81rlvnaewblvcjs47hzn.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F81rlvnaewblvcjs47hzn.gif" alt="zooming in, zooming out, extending and shrinking blank areas, rotating, flipping, and cropping." width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The third category mainly includes functions that editors should have, rather than the image itself. From the operator's perspective, there are forward and backward operations, editor reset, confirmation and cancellation of the current image edit. From the developer's perspective, it is the integration of the image editor with the business code and the related APIs and callbacks.&lt;/p&gt;

&lt;p&gt;The main functions of concern from the operator's perspective are: forward, backward, and reset.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8c2ummvtshyhyadp5qaw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8c2ummvtshyhyadp5qaw.gif" alt="forward, backward, and reset" width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main functions of concern from the developer's perspective are: confirmation and cancellation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7hn1oo1phy9dhon8jwi.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7hn1oo1phy9dhon8jwi.gif" alt="confirmation and cancellation" width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The three categories of functions mentioned above have been bound to the commonly used shortcut keys "ctrl+z" and "ctrl+y" to make it easier for users to operate.&lt;/p&gt;

&lt;p&gt;This library is created for developers. Therefore, developers can use simple code to open an image editor and configure the confirmation and cancellation callback functions to complete the integration of the project. As shown in the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ImageEditorHelper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createImageEditor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageDisplay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base64Image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;imageDisplay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;base64Image&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageDisplay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hidden&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;imageDisplay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hidden&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 显示图片&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code uses &lt;code&gt;createImageEditor&lt;/code&gt; to create an image editor. It contains three parameters. The parameter 'imageDisplay.src' is the address of the image, '.' is the relative path of a series of icons to be used by the image editor, and the third parameter is the callback executed after a single image edit is confirmed. There is also a fourth parameter, which is the callback executed after a single image edit is canceled. Because no special processing is required, the default value is used.&lt;/p&gt;

&lt;p&gt;I will write a series of blogs in detail later to share with readers how to use FabricJS step by step to develop such an image editor. It contains some tricky points, such as cropping screenshots. In order to overcome these problems, I also conducted an in-depth study of the source code of FabricJS.&lt;/p&gt;

</description>
      <category>fabricjs</category>
      <category>opensource</category>
      <category>typescript</category>
    </item>
    <item>
      <title>One hundred days!I Refactored The 50000 Star JavaScript Project with TypeScript！</title>
      <dc:creator>Meditator Gu</dc:creator>
      <pubDate>Tue, 18 Mar 2025 03:53:54 +0000</pubDate>
      <link>https://dev.to/meditatorgu/one-hundred-daysi-refactored-the-50000-star-javascript-project-with-typescript-537o</link>
      <guid>https://dev.to/meditatorgu/one-hundred-daysi-refactored-the-50000-star-javascript-project-with-typescript-537o</guid>
      <description>&lt;p&gt;Displaying PDF on the Web is a common requirement. However, the community has long lacked a suitable library to help developers do this. Pdf.js can meet the needs of displaying PDF, but it seems to be a bit powerless when it comes to integrating it into business systems. The latter is a fairly common requirement in China, whether it is a government-customized system or a commercial company's application system.&lt;/p&gt;

&lt;p&gt;Here are some common problems when using pdf.js in application systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is easy to integrate pdf.js into the web, but it is not very convenient to make pdf.js interact with the backend.&lt;/li&gt;
&lt;li&gt;The basic functions of the PDF reader are available, but it is difficult for developers to control these functions through code.&lt;/li&gt;
&lt;li&gt;The source code is relatively complex and difficult to read, modify and extend, and customization based on the source code is even more difficult.&lt;/li&gt;
&lt;li&gt;Lack of strong documentation support, the official documentation is not clear enough, and the community documentation is not deep and wide enough (at least in the Chinese network).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As the times continue to move forward, it is increasingly necessary to solve some of these problems. I have helped several customers solve their needs for customizing pdf.js, such as loading PDF fragments, reading and storing annotations through a database, customizing specific special annotations, and solving bugs they encountered during the integration process.&lt;/p&gt;

&lt;p&gt;Over a long period of time, I have communicated with many of my clients. I realized that most of the problems they face are common problems with certain commonalities. From a technical point of view, they can be solved through code reuse. As for the remaining small number of individual problems, they can be solved through plug-ins and custom codes.&lt;/p&gt;

&lt;p&gt;So I decided to develop an advanced version based on pdf.js. And set two basic goals. The first goal is to strengthen the API and documentation so that developers can smoothly integrate pdf.js into the system they are developing. Front-end developers can use the API to operate the PDF reader, and back-end developers can persist various information in the PDF reader and return it to them when the front-end requests this data. The second goal is to develop some functions that are needed by the market but have not yet been developed or are not perfect, such as a richer annotation system, PDF permission management, image and text extraction, customized watermarks, etc.&lt;/p&gt;

&lt;p&gt;But when I tried to do this, I found that it was not only very difficult, but also very ineffective. I used a tool to scan the source code of pdf.js and found that its code volume was actually more than I thought. If blank lines and comments are counted, its total code volume is about 200,000 lines. Even if blank lines and comments are removed, the total code volume is more than 100,000 lines. At first, I developed it for two to three weeks on this basis, and encountered many more problems than I expected at the beginning. On the basis of the existing code, even if it is just to achieve some basic goals, it is very difficult. For example, when I tried to change the PDF reader from the up and down sliding style to the page turning style, I found that not only a lot of code needs to be modified, but such changes will also affect other parts and bring potential bugs. And even if I spent a long time developing the functions I wanted, I might not be able to provide freely customized interfaces and APIs to developers, and even the information about function parameters in the source code is difficult to inform people who are willing to read the code in a convenient way.&lt;/p&gt;

&lt;p&gt;After a short attempt, I found that I could not solve the seemingly simple problems mentioned above with simple methods. In fact, if minor improvements could solve all these problems, I believe this job would have been done long ago. Even if it is not the pdf.js team itself, there will be other developers active in the community to complete this task.&lt;/p&gt;

&lt;p&gt;So I prepared to make some major changes. I planned to refactor pdf.js directly with TypeScript, retaining its core logic for PDF document processing, and refactoring its code related to displaying PDF on the web. The relevant tool chain and development style should also keep up with the times. I decided to abandon npm, remove gulp, and replace them with pnpm and vite. The traditional single module style is no longer used, and the multi-module approach of monorepo is a better choice.&lt;/p&gt;

&lt;p&gt;I used to focus on the backend, and only occasionally wrote front-end, so I didn't have a deep understanding of front-end development, and I knew very little about the front-end technology ecosystem. But I still have a lot of experience in refactoring medium and large projects. I have refactored business systems such as warehouse management systems, and big data systems such as knowledge graph systems. In general, there are challenges in refactoring, and there is a period of pain, and this period of pain can even be said to be not short, nor easy. From the beginning of the reconstruction of a system to the smooth operation of this system, for a long period of time, there is almost no output of new functions, bugs may be strange, and difficulties are one after another. But when this period of pain is over, the whole project begins to see the light. Bugs that could not be located before can now be located. Functions that could not be developed before can now be developed. The low development efficiency has now been greatly improved. Various mainstream components that could not be connected before can now be easily connected. Therefore, if we want to fully tap the potential of pdf.js and allow developers to perfectly integrate it into their daily development, a thorough reconstruction is inevitable.&lt;/p&gt;

&lt;p&gt;I think pdf.js does not perform well in the aspect of accessing business systems, mainly because it is not designed for the Chinese market alone. From a product perspective, its positioning is not a library for developers to call, but a tool for users to view PDF. pdf.js does a very good job in being a PDF viewing tool. It has also been integrated into many tools, such as VSCode, IDEA, chrome, etc. This allows users of these tools to easily view PDF on these tools. For ordinary computer users, they can also use chrome to view PDF directly without installing any other viewing tools. In contrast, every tool has its own strengths and weaknesses, and pdf.js cannot perfectly take into account both developers and users. For developers, it is only a little aggrieved. It is possible to integrate pdf.js, but the effect after integration is not so good.&lt;/p&gt;

&lt;p&gt;When I refactored pdf.js, the first thing I had to do was to re-establish its positioning and goals - it does not directly serve users, but developers. Developers should be able to open a PDF with simple code as shown below, and customize their PDF reader through a series of configurations, rather than having to embed it through an iframe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;viewer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;WebSerenViewer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;viewerScale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;viewer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;compressed.tracemonkey-pldi-09.pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;verbosity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;VerbosityLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WARNINGS&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;viewer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getViewController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;bindEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;bindEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WebViewerController&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pdf-page-up&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pageUp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pdf-page-down&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pageDown&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a single function, what I want to provide is not a specific button or icon, but the API, callbacks and various events that developers can operate.&lt;/p&gt;

&lt;p&gt;For developers who want to debug, customize, and contribute source code, I should provide mainstream tool chains, clear parameters, clear calling relationships, etc. I should ensure that they can understand, debug, and modify relevant code at a low cost.&lt;/p&gt;

&lt;p&gt;After spending more than 100 days on this, I have made several key steps in these matters. The main languages ​​and tools used in the code have changed to TypeScript, pnpm, and vite. The code development style has changed to a multi-module monorepo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcvid874g7ioq85yww8vy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcvid874g7ioq85yww8vy.png" alt="monorepo-style structure" width="420" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The parameter types of all functions are clear, and hard coding has been eliminated one after another. The overall code quality has been improved to a certain extent. And the most basic demo has also run through:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx91s8avp4rvbzu4dupux.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx91s8avp4rvbzu4dupux.gif" alt="The first working example" width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example, I used the initialization method in the previous code to create a PDF reader with the 'init' method, opened a PDF file with the 'open' method, and bound the previous page and next page APIs to the relevant buttons.&lt;/p&gt;

&lt;p&gt;The whole process was full of challenges. When I wrote a bash script to simply and roughly change the suffix of all files ending with js to ts, there were more than 20,000 direct errors. For nearly two months, I kept fixing these errors one by one like Yugong moving mountains. After I fixed an error, several new errors might pop up. For example, after I clarified the parameters of a function, the previously hidden errors such as "The object has no xx attribute" and "The object may be null" also appeared. Therefore, the actual number of errors fixed is more than 20,000.&lt;/p&gt;

&lt;p&gt;In the process of fixing the error, I also found many problems such as irregular writing and coupling. For example, a certain section of code arbitrarily passed parameter types that did not conform to the JSDoc description just for convenience; the reflection was used arbitrarily, resulting in a broken reference chain between codes; hard coding; confusing call relationships, etc. I changed them all. For the process-oriented writing, I also changed it to object-oriented. The following is a comparison of the code before and after the rewrite, before the rewrite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GetPage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pdfManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageIndex&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="nx"&gt;pdfManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ensure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rotate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;pdfManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ensure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ref&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;pdfManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ensure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userUnit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;pdfManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ensure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;view&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userUnit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;refStr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;userUnit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code listens to the "GetPage" event, but the parameter type of this event is unknown (the type of the parameter data in function(data)), and it takes a long time to analyze. After listening to this code, pdfManager calls the get method of rotate in page, and directly uses such a hard-coded + reflection method to do it. Such code is not easy to modify and is prone to problems. For example, when someone accidentally changes the name of rotate in page, the code at this place may become a missed point and cause errors.&lt;/p&gt;

&lt;p&gt;After the adjustment of TypeScript, all parameters are clear, the call is obvious, and the association between page and rotate has become a strong association:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onGetPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pdfManager&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageIndex&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="nx"&gt;pdfManager&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ensure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;pdfManager&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ensure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;pdfManager&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ensure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userUnit&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;pdfManager&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ensure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userUnit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;refStr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userUnit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are many more changes like this, and I will discuss these issues in detail and share my experiences in subsequent blogs.&lt;/p&gt;

&lt;p&gt;After I completed the basic refactoring, the code could not be run directly. Once it was run, many runtime errors would be reported. At this time, the code base had been compiled. My previous work included refactoring some large files and methods, modifying Record to Map in large quantities, and unifying null and undefined in the project. These works brought a lot of bugs. It took more than a day to locate and solve several of the bugs. After fixing these bugs, my refactored code finally ran through. But this is not enough. In order to show readers a most basic case, which is the page turning case mentioned earlier. I did a lot of work to extract the parameters and APIs to ensure that if a developer wants to use this library, it can directly control the created PDF reader through configuration and API.&lt;/p&gt;

&lt;p&gt;Although the code has been run, it is still a long way from being truly usable in production. I will continue to spend some time to conduct a rich test on the new code to ensure that all PDFs in pdf.js perform consistently on the old and new codes. The rewrite of APIs and callback events is not yet complete, which is also very important for developers to control the readers created with this library. Maybe I won't develop all the points at once. But it is still necessary to develop those key points well. After all this work is completed, I will release the first version with supporting cases, codes, and documents. Make sure this library is efficient and easy to use.&lt;/p&gt;

&lt;p&gt;I have hosted the code for this project on Github:&lt;br&gt;
&lt;a href="https://github.com/xingshen24/seren-pdf" rel="noopener noreferrer"&gt;https://github.com/xingshen24/seren-pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Debugging this library is relatively simple. Just use &lt;code&gt;pnpm recursive install&lt;/code&gt; to install the dependencies, then go to the &lt;strong&gt;packages-private/seren-viewer-develop/&lt;/strong&gt; directory and run it with &lt;code&gt;pnpm run dev&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>pdfjs</category>
      <category>refactoring</category>
    </item>
  </channel>
</rss>
