diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 064f3df7..d48a1f5a 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -14,21 +14,21 @@ appearance, race, religion, or sexual identity and orientation. Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or +- The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities @@ -69,10 +69,9 @@ members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +available at [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq - + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6b799017..22d85e20 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,7 +28,7 @@ as a new JSON object in the array. This information includes: - A username for your profile (used in your profile URL). - [IE, our founder's username is `crutchcorn`, and [their page can be found here](https://unicorn-utterances.com/unicorns/crutchcorn)] + \[IE, our founder's username is `crutchcorn`, and [their page can be found here](https://unicorn-utterances.com/unicorns/crutchcorn)] - Full name @@ -74,7 +74,7 @@ Now that we have your user attribution data, we can move onto the post data itse #### Save Location Once you have your `.md` file, we'll need a place to put it. We place a subdirectory in our [`content/blog` folder](./content/blog) for each of the blog posts on the site. The naming of these subdirectories is integral to keep in mind, as they reflect the URL path of the article once finished. For example, the folder [`what-is-ssr-and-ssg`](./content/blog/what-is-ssr-and-ssg) will turn into the URL for the article: -[https://unicorn-utterances.com/posts/what-is-ssr-and-ssg/](https://unicorn-utterances.com/posts/what-is-ssr-and-ssg/) + Once you've created a subfolder with the URI you'd like your article to have, move the `.md` file into the folder with the name `index.md`. If you have linked images or videos, you'll need to save those files in the same folder and change your markdown file to reference them locally: @@ -121,16 +121,20 @@ The following data **must** be present: - Title for the article - We ask that your titles are less than 80 characters. + - A description of the article - We ask that your descriptions are less than 190 characters. - A published date - Please follow the format as seen above + - An array of authors - This array must have every value match [one of the `id`s of the `unicorns.json` file](./content/data/unicorns.json) + - An array of related tags - Please try to use existing tags if possible. If you don't find any, that's alright - We ask that you keep it to 4 tags maximum + - A `license` to be associated with the post - This must match the `id` field for one of the values [in our `license.json` file](./content/data/licenses.json) - If you're not familiar with what these licenses mean, view the `explainLink` for each of them in the `license.json` file. It'll help you understand what permissions the public has to the post diff --git a/LICENSE.md b/LICENSE.md index 21eff128..21ab8f0a 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -2,198 +2,208 @@ Mozilla Public License, version 2.0 1. Definitions - 1.1. “Contributor” - means each individual or legal entity that creates, contributes to the - creation of, or owns Covered Software. + 1.1. “Contributor” + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. - 1.2. “Contributor Version” - means the combination of the Contributions of others (if any) used by a - Contributor and that particular Contributor’s Contribution. + 1.2. “Contributor Version” + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor’s Contribution. - 1.3. “Contribution” - means Covered Software of a particular Contributor. + 1.3. “Contribution” + means Covered Software of a particular Contributor. - 1.4. “Covered Software” - means Source Code Form to which the initial Contributor has attached the - notice in Exhibit A, the Executable Form of such Source Code Form, - and Modifications of such Source Code Form, in each case - including portions thereof. + 1.4. “Covered Software” + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, + and Modifications of such Source Code Form, in each case + including portions thereof. - 1.5. “Incompatible With Secondary Licenses” - means + 1.5. “Incompatible With Secondary Licenses” + means - a. that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or + ``` + a. that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or - b. that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the terms - of a Secondary License. + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms + of a Secondary License. + ``` - 1.6. “Executable Form” - means any form of the work other than Source Code Form. + 1.6. “Executable Form” + means any form of the work other than Source Code Form. - 1.7. “Larger Work” - means a work that combines Covered Software with other material, - in a separate file or files, that is not Covered Software. + 1.7. “Larger Work” + means a work that combines Covered Software with other material, + in a separate file or files, that is not Covered Software. - 1.8. “License” - means this document. + 1.8. “License” + means this document. - 1.9. “Licensable” - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, - any and all of the rights conveyed by this License. + 1.9. “Licensable” + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, + any and all of the rights conveyed by this License. - 1.10. “Modifications” - means any of the following: + 1.10. “Modifications” + means any of the following: - a. any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered Software; or + ``` + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or - b. any new file in Source Code Form that contains any Covered Software. + b. any new file in Source Code Form that contains any Covered Software. + ``` - 1.11. “Patent Claims” of a Contributor - means any patent claim(s), including without limitation, method, process, - and apparatus claims, in any patent Licensable by such Contributor that - would be infringed, but for the grant of the License, by the making, - using, selling, offering for sale, having made, import, or transfer of - either its Contributions or its Contributor Version. + 1.11. “Patent Claims” of a Contributor + means any patent claim(s), including without limitation, method, process, + and apparatus claims, in any patent Licensable by such Contributor that + would be infringed, but for the grant of the License, by the making, + using, selling, offering for sale, having made, import, or transfer of + either its Contributions or its Contributor Version. - 1.12. “Secondary License” - means either the GNU General Public License, Version 2.0, the - GNU Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those licenses. + 1.12. “Secondary License” + means either the GNU General Public License, Version 2.0, the + GNU Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those licenses. - 1.13. “Source Code Form” - means the form of the work preferred for making modifications. + 1.13. “Source Code Form” + means the form of the work preferred for making modifications. - 1.14. “You” (or “Your”) - means an individual or a legal entity exercising rights under this License. - For legal entities, “You” includes any entity that controls, - is controlled by, or is under common control with You. For purposes of - this definition, “control” means (a) the power, direct or indirect, - to cause the direction or management of such entity, whether by contract - or otherwise, or (b) ownership of more than fifty percent (50%) of the - outstanding shares or beneficial ownership of such entity. + 1.14. “You” (or “Your”) + means an individual or a legal entity exercising rights under this License. + For legal entities, “You” includes any entity that controls, + is controlled by, or is under common control with You. For purposes of + this definition, “control” means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by contract + or otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions - 2.1. Grants - Each Contributor hereby grants You a world-wide, royalty-free, - non-exclusive license: + 2.1. Grants + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: - a. under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, - or as part of a Larger Work; and + ``` + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, + or as part of a Larger Work; and - b. under Patent Claims of such Contributor to make, use, sell, - offer for sale, have made, import, and otherwise transfer either - its Contributions or its Contributor Version. + b. under Patent Claims of such Contributor to make, use, sell, + offer for sale, have made, import, and otherwise transfer either + its Contributions or its Contributor Version. + ``` - 2.2. Effective Date - The licenses granted in Section 2.1 with respect to any Contribution - become effective for each Contribution on the date the Contributor - first distributes such Contribution. + 2.2. Effective Date + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor + first distributes such Contribution. - 2.3. Limitations on Grant Scope - The licenses granted in this Section 2 are the only rights granted - under this License. No additional rights or licenses will be implied - from the distribution or licensing of Covered Software under this License. - Notwithstanding Section 2.1(b) above, no patent license is granted - by a Contributor: + 2.3. Limitations on Grant Scope + The licenses granted in this Section 2 are the only rights granted + under this License. No additional rights or licenses will be implied + from the distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted + by a Contributor: - a. for any code that a Contributor has removed from - Covered Software; or + ``` + a. for any code that a Contributor has removed from + Covered Software; or - b. for infringements caused by: (i) Your and any other third party’s - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its - Contributor Version); or + b. for infringements caused by: (i) Your and any other third party’s + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its + Contributor Version); or - c. under Patent Claims infringed by Covered Software in the - absence of its Contributions. + c. under Patent Claims infringed by Covered Software in the + absence of its Contributions. + ``` - This License does not grant any rights in the trademarks, service marks, - or logos of any Contributor (except as may be necessary to comply with - the notice requirements in Section 3.4). + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). - 2.4. Subsequent Licenses - No Contributor makes additional grants as a result of Your choice to - distribute the Covered Software under a subsequent version of this - License (see Section 10.2) or under the terms of a Secondary License - (if permitted under the terms of Section 3.3). + 2.4. Subsequent Licenses + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License + (if permitted under the terms of Section 3.3). - 2.5. Representation - Each Contributor represents that the Contributor believes its - Contributions are its original creation(s) or it has sufficient rights - to grant the rights to its Contributions conveyed by this License. + 2.5. Representation + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights + to grant the rights to its Contributions conveyed by this License. - 2.6. Fair Use - This License is not intended to limit any rights You have under - applicable copyright doctrines of fair use, fair dealing, - or other equivalents. + 2.6. Fair Use + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, + or other equivalents. - 2.7. Conditions - Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the - licenses granted in Section 2.1. + 2.7. Conditions + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the + licenses granted in Section 2.1. 3. Responsibilities - 3.1. Distribution of Source Form - All distribution of Covered Software in Source Code Form, including - any Modifications that You create or to which You contribute, must be - under the terms of this License. You must inform recipients that the - Source Code Form of the Covered Software is governed by the terms - of this License, and how they can obtain a copy of this License. - You may not attempt to alter or restrict the recipients’ rights - in the Source Code Form. + 3.1. Distribution of Source Form + All distribution of Covered Software in Source Code Form, including + any Modifications that You create or to which You contribute, must be + under the terms of this License. You must inform recipients that the + Source Code Form of the Covered Software is governed by the terms + of this License, and how they can obtain a copy of this License. + You may not attempt to alter or restrict the recipients’ rights + in the Source Code Form. - 3.2. Distribution of Executable Form - If You distribute Covered Software in Executable Form then: + 3.2. Distribution of Executable Form + If You distribute Covered Software in Executable Form then: - a. such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more than - the cost of distribution to the recipient; and + ``` + a. such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more than + the cost of distribution to the recipient; and - b. You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients’ rights in the Source Code Form under this License. + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients’ rights in the Source Code Form under this License. + ``` - 3.3. Distribution of a Larger Work - You may create and distribute a Larger Work under terms of Your choice, - provided that You also comply with the requirements of this License for - the Covered Software. If the Larger Work is a combination of - Covered Software with a work governed by one or more Secondary Licenses, - and the Covered Software is not Incompatible With Secondary Licenses, - this License permits You to additionally distribute such Covered Software - under the terms of such Secondary License(s), so that the recipient of - the Larger Work may, at their option, further distribute the - Covered Software under the terms of either this License or such - Secondary License(s). + 3.3. Distribution of a Larger Work + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of + Covered Software with a work governed by one or more Secondary Licenses, + and the Covered Software is not Incompatible With Secondary Licenses, + this License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the + Covered Software under the terms of either this License or such + Secondary License(s). - 3.4. Notices - You may not remove or alter the substance of any license notices - (including copyright notices, patent notices, disclaimers of warranty, - or limitations of liability) contained within the Source Code Form of - the Covered Software, except that You may alter any license notices to - the extent required to remedy known factual inaccuracies. + 3.4. Notices + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, + or limitations of liability) contained within the Source Code Form of + the Covered Software, except that You may alter any license notices to + the extent required to remedy known factual inaccuracies. - 3.5. Application of Additional Terms - You may choose to offer, and to charge a fee for, warranty, support, - indemnity or liability obligations to one or more recipients of - Covered Software. However, You may do so only on Your own behalf, - and not on behalf of any Contributor. You must make it absolutely clear - that any such warranty, support, indemnity, or liability obligation is - offered by You alone, and You hereby agree to indemnify every Contributor - for any liability incurred by such Contributor as a result of warranty, - support, indemnity or liability terms You offer. You may include - additional disclaimers of warranty and limitations of liability - specific to any jurisdiction. + 3.5. Application of Additional Terms + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of + Covered Software. However, You may do so only on Your own behalf, + and not on behalf of any Contributor. You must make it absolutely clear + that any such warranty, support, indemnity, or liability obligation is + offered by You alone, and You hereby agree to indemnify every Contributor + for any liability incurred by such Contributor as a result of warranty, + support, indemnity or liability terms You offer. You may include + additional disclaimers of warranty and limitations of liability + specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation @@ -209,31 +219,31 @@ to be able to understand it. 5. Termination - 5.1. The rights granted under this License will terminate automatically - if You fail to comply with any of its terms. However, if You become - compliant, then the rights granted under this License from a particular - Contributor are reinstated (a) provisionally, unless and until such - Contributor explicitly and finally terminates Your grants, and (b) on an - ongoing basis, if such Contributor fails to notify You of the - non-compliance by some reasonable means prior to 60 days after You have - come back into compliance. Moreover, Your grants from a particular - Contributor are reinstated on an ongoing basis if such Contributor - notifies You of the non-compliance by some reasonable means, - this is the first time You have received notice of non-compliance with - this License from such Contributor, and You become compliant prior to - 30 days after Your receipt of the notice. + 5.1. The rights granted under this License will terminate automatically + if You fail to comply with any of its terms. However, if You become + compliant, then the rights granted under this License from a particular + Contributor are reinstated (a) provisionally, unless and until such + Contributor explicitly and finally terminates Your grants, and (b) on an + ongoing basis, if such Contributor fails to notify You of the + non-compliance by some reasonable means prior to 60 days after You have + come back into compliance. Moreover, Your grants from a particular + Contributor are reinstated on an ongoing basis if such Contributor + notifies You of the non-compliance by some reasonable means, + this is the first time You have received notice of non-compliance with + this License from such Contributor, and You become compliant prior to + 30 days after Your receipt of the notice. - 5.2. If You initiate litigation against any entity by asserting a patent - infringement claim (excluding declaratory judgment actions, - counter-claims, and cross-claims) alleging that a Contributor Version - directly or indirectly infringes any patent, then the rights granted - to You by any and all Contributors for the Covered Software under - Section 2.1 of this License shall terminate. + 5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted + to You by any and all Contributors for the Covered Software under + Section 2.1 of this License shall terminate. - 5.3. In the event of termination under Sections 5.1 or 5.2 above, all - end user license agreements (excluding distributors and resellers) which - have been validly granted by You or Your distributors under this License - prior to termination shall survive termination. + 5.3. In the event of termination under Sections 5.1 or 5.2 above, all + end user license agreements (excluding distributors and resellers) which + have been validly granted by You or Your distributors under this License + prior to termination shall survive termination. 6. Disclaimer of Warranty @@ -311,9 +321,11 @@ this License against a Contributor. Exhibit A - Source Code Form License Notice - This Source Code Form is subject to the terms of the - Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed - with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +``` +This Source Code Form is subject to the terms of the +Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed +with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +``` If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a @@ -324,6 +336,7 @@ You may add additional accurate notices of copyright ownership. Exhibit B - “Incompatible With Secondary Licenses” Notice - This Source Code Form is “Incompatible With Secondary Licenses”, - as defined by the Mozilla Public License, v. 2.0. - +``` +This Source Code Form is “Incompatible With Secondary Licenses”, +as defined by the Mozilla Public License, v. 2.0. +``` diff --git a/README.es.md b/README.es.md index 2e80fa4f..831cb3f2 100644 --- a/README.es.md +++ b/README.es.md @@ -16,9 +16,7 @@ Este repository actúa como la ubicación del código fuente para el [blog de Un ## Patrocinadores -The Polyglot Developer -OceanBit -CoderPad +The Polyglot Developer OceanBit CoderPad [Reconocemos todos los patrocinios que compartimos abiertamente en GitHub](https://github.com/unicorn-utterances/unicorn-utterances/issues?q=is%3Aissue+label%3Adisclosure+is%3Aclosed) diff --git a/README.md b/README.md index dfd14747..5ccf700a 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,7 @@ This repository acts as the source code location for [the Unicorn Utterances blo ## Sponsors -The Polyglot Developer -OceanBit -CoderPad +The Polyglot Developer OceanBit CoderPad [We disclose every sponsorship we share openly on GitHub](https://github.com/unicorn-utterances/unicorn-utterances/issues?q=is%3Aissue+label%3Adisclosure+is%3Aclosed) @@ -42,4 +40,3 @@ We highly encourage and celebrate others contributing to our site and our commun Keep in mind that we request developers reach out [via our Discord](https://discord.gg/FMcvc6T) or [via GitHub issue](https://github.com/unicorn-utterances/unicorn-utterances/issues/new) before extensive development is pursued. If you have a feature you'd like to add to the site, let us know! We'd love to do some brainstorming before coding begins! We extend this invitation to those who may be unfamiliar with our processes. Be sure to check out [our CONTRIBUTING.md](./CONTRIBUTING.md) file first, but don't be afraid to join in and ask questions if you're uncertain of anything - diff --git a/content/blog/android-studio-setup-for-ryzen-cpus/index.md b/content/blog/android-studio-setup-for-ryzen-cpus/index.md index 930339b2..a65ec6c5 100644 --- a/content/blog/android-studio-setup-for-ryzen-cpus/index.md +++ b/content/blog/android-studio-setup-for-ryzen-cpus/index.md @@ -12,7 +12,7 @@ In the past, Android Studio did not support AMD's CPUs for hardware emulation of an Android device. [That all changed in 2018 when Google added Hyper-V support to the Android Emulator](https://android-developers.googleblog.com/2018/07/android-emulator-amd-processor-hyper-v.html). -However, while working on my Ryzen CPU powered desktop, I had difficulties getting the program working on my machine. +However, while working on my Ryzen CPU powered desktop, I had difficulties getting the program working on my machine. # BIOS Setup {#bios} @@ -47,15 +47,13 @@ Enabling IOMMU on a Gigabyte AMD motherboard is much easier than enabling SVM mo ![The chipset tab](./iommu.jpg) - - Once changed, tab over to "Save & Exit" and select "Exit and save changes". # Windows Features Setup {#windows-features} Now that we have our BIOS (UEFI, really) configured correctly, we can enable the Windows features we need for the Android Emulator. -To start, press Win + R, which should bring up the **"Run"** dialog. Once open, _type `OptionalFeatures` and press **"OK"**_. +To start, press Win + R, which should bring up the **"Run"** dialog. Once open, _type `OptionalFeatures` and press **"OK"**_. ![The "run dialog" box with the typed suggestion](./run_dialog.png) @@ -73,7 +71,7 @@ After these three settings are selected, press **"OK"** and allow the features t # Setup Android Studio {#android-studio} -You have a few different methods for installing Android Studio. You can choose to use [Google's installer directly](https://developer.android.com/studio/install), you can [utilize the Chocolatey CLI installer](https://chocolatey.org/packages/AndroidStudio), or even use [JetBrain's Toolbox utility to install and manage an instance of Android Studio](https://www.jetbrains.com/toolbox-app/). _Any of these methods work perfectly well_, it's down to preference, really. +You have a few different methods for installing Android Studio. You can choose to use [Google's installer directly](https://developer.android.com/studio/install), you can [utilize the Chocolatey CLI installer](https://chocolatey.org/packages/AndroidStudio), or even use [JetBrain's Toolbox utility to install and manage an instance of Android Studio](https://www.jetbrains.com/toolbox-app/). _Any of these methods work perfectly well_, it's down to preference, really. Once you get Android Studio installed, go ahead and _open the SDK Manager settings screen_ from the **"Configure"** dropdown. @@ -83,15 +81,11 @@ Once you see the popup dialog, you'll want to _select the "SDK Tools" tab_. Ther ![The mentioned screen with the AMD hypervisor selected](./select_amd_hypervisor.png) - - - - -Once you've selected it, press **"Apply"** to download the installer. _Because the "Apply" button only downloads the installer, we'll need to run it manually._ +Once you've selected it, press **"Apply"** to download the installer. _Because the "Apply" button only downloads the installer, we'll need to run it manually._ ## Run the Installer {#amd-hypervisor-installer} -To find the location of the installer, you'll want to go to the install location for your Android SDK. For me (who used the Jetbrains Toolbox to install Android Studio), that path was: `%AppData%/../Local/Android/Sdk`. +To find the location of the installer, you'll want to go to the install location for your Android SDK. For me (who used the Jetbrains Toolbox to install Android Studio), that path was: `%AppData%/../Local/Android/Sdk`. The hypervisor installer is located under the following subpath of that path: @@ -125,13 +119,13 @@ You'll then see a list of the devices that you currently have setup. I, for exam You can create a new one by _pressing **"Create Virtual Device"**_. -Upon the dialog creation, you'll see a list of devices that you can use as a baseline for your emulator. This sets the hardware information (screen size and such). Even if you pick a device, it does not restrict the versions of Android you can use with it. I picked Pixel 2 and KitKat for my KK testing device, despite the Pixel 2 being released well after that OS release. +Upon the dialog creation, you'll see a list of devices that you can use as a baseline for your emulator. This sets the hardware information (screen size and such). Even if you pick a device, it does not restrict the versions of Android you can use with it. I picked Pixel 2 and KitKat for my KK testing device, despite the Pixel 2 being released well after that OS release. ![The "select hardware" screen as mentioned](./select_virtual_device.png) Once you've selected a device, you can pick the version of Android to run. You'll want to select an `x86` or `x86_64` build of Android you're looking for. I've noticed better performance from `x86_64` emulators myself, so I went with an `x86_64` build of Android Pie. -![The selected image for x86_64 Pie](./pie_device.png) +![The selected image for x86\_64 Pie](./pie_device.png) Afterward, you'll want to name your emulator. I try to keep them without strings and not too long, so if I need to run the emulator manually in the CLI, I can do so with the name of the emulator easily. @@ -139,13 +133,12 @@ Afterward, you'll want to name your emulator. I try to keep them without strings Finally, once you've selected **"Finish"**, it should save the emulator's settings and start the emulator itself. - > You may get an error such as `HAXM is not installed` when trying to set up an emulator. If you get this error, it's most likely that you have not [enabled the settings in BIOS](#bios). I know in my case, I had recently performed a BIOS upgrade, and it had reset my BIOS settings, making me go back and re-enable them. ![The emulator once ran](./device_running.png) # Conclusion -I've had incredible success with my Ryzen powered desktop during my Android development. Not only is it cost-efficient for my usage compared to the Intel option, but it's able to run the emulator quickly. Hopefully, this article has been able to help you set up your machine as well. +I've had incredible success with my Ryzen powered desktop during my Android development. Not only is it cost-efficient for my usage compared to the Intel option, but it's able to run the emulator quickly. Hopefully, this article has been able to help you set up your machine as well. Let us know what your thoughts on this article were! We not only have our comments down below, but we have [a Discord community](https://discord.gg/FMcvc6T) as well that we invite you to join! We chat about all kinds of programming and CS related topics there! diff --git a/content/blog/angular-components-control-value-accessor/index.md b/content/blog/angular-components-control-value-accessor/index.md index d8a9fcb3..eb73dace 100644 --- a/content/blog/angular-components-control-value-accessor/index.md +++ b/content/blog/angular-components-control-value-accessor/index.md @@ -130,7 +130,6 @@ With this, we'll finally be able to use these methods to control our component. > If you're wondering why you don't need to do something like this with `ngOnInit`, it's because that functionality is baked right into Angular. Angular _always_ looks for an `onInit` function and tries to call it when the respective lifecycle method is run. `implements` is just a type-safe way to ensure that you're explicitly wanting to call that method. - ## `writeValue` {#write-value} `writeValue` is a method that acts exactly as you'd expect it to: It simply writes a value to your component's value. As your value has more than a single write method (from your component and from the parent), it's suggested to have a setter, getter, and private internal value for your property. @@ -302,7 +301,6 @@ Finally, you can pass these options to `ngModel` and `formControl` (or even `for If done properly, you should see something like this: - # Form Control Classes @@ -311,7 +309,6 @@ Angular CSS masters might point to [classes that's applied to inputs when variou These classes include: - - `ng-pristine` - `ng-dirty` - `ng-untouched` @@ -409,7 +406,6 @@ export class AppComponent { - Not only do you have [a wide range of Angular-built validators at your disposal](https://angular.io/api/forms/Validators), but you're even able to [make your own validator](https://angular.io/api/forms/Validator)! # Conclusion {#conclusion} diff --git a/content/blog/angular-extend-class/index.md b/content/blog/angular-extend-class/index.md index b5947aaa..9fdd91a7 100644 --- a/content/blog/angular-extend-class/index.md +++ b/content/blog/angular-extend-class/index.md @@ -160,7 +160,7 @@ In this article we'll learn: - [How to use a base class in Angular](#base-class-angular) - [How to simplify Angular base class usage using an abstract class](#abstract-class) - [Overwriting lifecycle methods in Angular extended classes](#lifecycle-methods) -- [Using dependency injection with your extended class](#dependency injection) +- \[Using dependency injection with your extended class]\(#dependency injection) - [Why you don't want to use base classes with Angular](#dont-extend-base-classes) # What is an extension class, anyway? {#base-class} @@ -195,8 +195,6 @@ This class has a few things going on: When we create an "instance" of this class, it will in turn call the `constructor` and give us an object with all of the properties and methods associated with `HelloMessage` as an "instance" of that class. - - Now, let's say that we want to reuse the `sayHi` logic in multiple classes at a time. > Sounds like a familiar problem, doesn't it? @@ -584,8 +582,6 @@ class AppComponent extends BaseComponent implements OnInit, OnDestroy { } ``` - - ## Overwriting `constructor` behavior {#overwriting-constructors} When working with class extension, regardless of being used in Angular or in JavaScript itself, you need to call `super()` when trying to overwrite a constructor: @@ -837,8 +833,6 @@ class AppComponent extends BaseComponent { } ``` - - # Why you don't want to extend Angular base classes {#dont-extend-base-classes} Now that we've learned how to extend base classes in Angular to share lifecycle methods, allow me to flip the script: @@ -995,8 +989,6 @@ class AppComponent implements OnDestroy { } ``` - - # Conclusion And that's it! I hope this has been an insightful look into how you can extend component logic. diff --git a/content/blog/angular-npm-font-usage/index.md b/content/blog/angular-npm-font-usage/index.md index d0d4254a..bf511734 100644 --- a/content/blog/angular-npm-font-usage/index.md +++ b/content/blog/angular-npm-font-usage/index.md @@ -113,7 +113,7 @@ Because we're planning on using Angular CLI, we'll want to set the `src` propert > font-weight: 800; > src: url("#{$base_path}/foundry_sterling_extra_bold.otf") format('opentype') > } -> +> > // ... Other @font-face declarations > } > ``` @@ -152,7 +152,7 @@ npm i ecp-private-assets ## `angular.json` modification {#angular-json} -Once this is done, two steps are required. First, add the following to `angular.json`'s `assets` property. This will copy the files from `ecp-private-assets` to `/assets` once you setup a build. +Once this is done, two steps are required. First, add the following to `angular.json`'s `assets` property. This will copy the files from `ecp-private-assets` to `/assets` once you setup a build. ```json { @@ -201,14 +201,13 @@ This way, when we use the CSS `url('/assets/')`, it will point to our newly appo Now that we have our assets in place, we need to import the CSS file into our app. - If your app utilizes `postcss`'s `import` plugin or if you're using vanilla CSS, add the following line to your `main.scss` file: ```css @import "ecp-private-assets/fonts/foundry_sterling.css"; ``` -> Remember to keep the `@import`s at the top of your file, as you will receive an error otherwise. +> Remember to keep the `@import`s at the top of your file, as you will receive an error otherwise. However, if you're not using `postcss` and have SCSS installed, you can use the following: diff --git a/content/blog/angular-templates-start-to-source/index.md b/content/blog/angular-templates-start-to-source/index.md index 876301ca..6f82bc18 100644 --- a/content/blog/angular-templates-start-to-source/index.md +++ b/content/blog/angular-templates-start-to-source/index.md @@ -62,7 +62,7 @@ We are then adding the [`ngIf`](https://angular.io/api/common/NgIf) structural d - If `bool` is true, it renders `

True

`, and the template containing `

False

` does not - If `bool` is false, it then checks if the [`else` condition built into `ngIf`](https://angular.io/api/common/NgIf#showing-an-alternative-template-using-else) has a value assigned to it. If there is a value assigned to the `else` condition, it renders that template. - - In this example, it does; the template we've assigned to `templHere`. Because of this, `

False

` is rendered + - In this example, it does; the template we've assigned to `templHere`. Because of this, `

False

` is rendered If you had forgotten to include the `ngIf`, it would never render the `False` element because **a template is not rendered to the view unless explicitly told to — this includes templates created with `ng-template`** @@ -209,7 +209,6 @@ Fancy that. When we want to overwrite the type of data we expect `ViewChild` to return, we can use a second property passed to the `ViewChild` decorator with the type we want to be returned. With the use-case mentioned above, we can tell Angular that we want a reference to the element of the component itself by using the `ElementRef`. - ```typescript /* This would replace the previous @ViewChild */ @ViewChild('myComponent', {read: ElementRef, static: false}) myComponent: ElementRef; @@ -314,7 +313,7 @@ action-card { } ``` -But this is often not the case. _[Angular's `ViewEncapsulation`](https://angular.io/api/core/ViewEncapsulation) prevents styles from one component from affecting the styling of another_. This is especially true if you're using a configuration that allows the native browser to handle the components under the browser's shadow DOM APIs, which restricts stylesheet sharing on a browser-level. This is why the [Angular-specific CSS selector `::ng-deep`](https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep) has been marked for depreciation (sorry old-school Angular developers [including myself, so much to migrate 😭]). +But this is often not the case. _[Angular's `ViewEncapsulation`](https://angular.io/api/core/ViewEncapsulation) prevents styles from one component from affecting the styling of another_. This is especially true if you're using a configuration that allows the native browser to handle the components under the browser's shadow DOM APIs, which restricts stylesheet sharing on a browser-level. This is why the [Angular-specific CSS selector `::ng-deep`](https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep) has been marked for depreciation (sorry old-school Angular developers \[including myself, so much to migrate 😭]). It's no matter, though. We have the power of `ViewChildren` on our side! Corbin already showed us how to get a reference to an element of a rendered component! Let's spin up an example: @@ -407,7 +406,6 @@ export class AppComponent { This is a perfect example of where you might want `@ContentChild` — not only are you unable to use `ng-content` to render this template without a template reference being passed to an outlet, but you're able to create a context that can pass information to the template being passed as a child. - # How Does Angular Track the UI {#understand-the-tree} Awesome! We've been blowing through some of the real-world uses of templates like a bullet-train through a tunnel. 🚆 But I have something to admit: I feel like I've been doing a pretty bad job at explaining the "nitty-gritty" of how this stuff works. While that can often be a bit more dry of a read, I think it's very important to be able to use these APIs to their fullest. As such, let's take a step back and read through some of the more abstract concepts behind them. @@ -516,11 +514,8 @@ Little has changed, yet there's something new! A _view container_ is just what i

``` - ![A chart showing an element as the root with two children, a template and a view. The view points towards the template](./hierarchy_view_container_on_element.svg "Diagram showing the above code as a graph") - - _It is because Angular's view containers being able to be attached to views, templates, and elements that enable the dependency injection system to get a `ViewContainerRef` regardless of what you're requested the `ViewContainerRef` on_. ## Host Views {#components-are-directives} @@ -566,11 +561,8 @@ export class ChildComponent {} export class AppComponent {} ``` - ![A chart showing the heirarchy of the above code. It shows "my-app" having a host view, which has a view container. This view container is the parent to an element and "child-component", which has its own host view, view container, and children](./hierarchy_tree_example.svg "Diagram showing the above code as a graph") - - ## Template Input Variable Scope Template input variables are the variables you bind to a template when using context. ``. _These variables are defined from the context that is applied to the template_. As a result **these templates are able to be accessed by the children views of the templates, but not from a higher level** — as the context is not defined above the template: @@ -628,8 +620,6 @@ If you look at the output of this example, you'll notice that `testingMessage` i ![Chart showing the above code sample to match the prior visualization aids](./template_reference_scope.svg "Visualization of the hierarchy tree for the prior cod example") - - When the view that is trying to render `testMessage` looks for that template reference variable, it is unable to, as it is bound to the `helloThereMsg` template view. Because it cannot find a template reference variable with the id `testMessage`, it treats it like any other unfound variable: an `undefined` value. The default behavior of `undefined` being passed to `ngTemplateOutlet` is to not render anything. In order to fix this behavior, we'd need to move the second `ng-template` into the `helloThereMsg` template view so that the `ngTemplateOutlet` is able to find the matching template reference variable within its view scope. @@ -709,7 +699,6 @@ One of the default checks that is ran when Angular is starting the initial rende These checks trigger the lifecycle method `DoCheck`, which you can manually handle. The `DoCheck` lifecycle method will trigger every time Angular detects data changes, regardless of if the check of that data does not decide to update the item on-screen or not. - So let's look at the example we had previously, but let's add some lifecycle methods to evaluate when `ViewChild` is able to give us our value. ```typescript @@ -743,7 +732,7 @@ ngAfterViewInit | The template is present? true ngDoCheck | The template is present? true ``` -You can see that the `testingMessageCompVar` property is not defined until the `ngAfterViewInit`. _The reason we're hitting the error is that the template is not defined in the component logic until `ngAfterViewInit`._ It is not defined until them due to timing issues:* **the template is being declared in an embedded view, which takes a portion of time to render to screen**. As a result, the `helloThereMsg` template must render first, then the `ViewChild` can get a reference to the child after the initial update. +You can see that the `testingMessageCompVar` property is not defined until the `ngAfterViewInit`. _The reason we're hitting the error is that the template is not defined in the component logic until `ngAfterViewInit`._ It is not defined until them due to timing issues:\* **the template is being declared in an embedded view, which takes a portion of time to render to screen**. As a result, the `helloThereMsg` template must render first, then the `ViewChild` can get a reference to the child after the initial update. When using `ViewChild` by itself, it updates the value of the `testingMessageCompVar` at the same time that the `AfterViewInit` lifecycle method is ran. This value update is then in turn reflected in the template itself. @@ -803,9 +792,9 @@ When taking the example with the `testingMessageCompVar` prop and changing the v Having covered views in the last section, it's important to mention an important limitation regarding them: ->Properties of elements in a view can change dynamically, in response to user actions; the structure (number and order) of elements in a view can't. You can change the structure of elements by inserting, moving, or removing nested views within their view containers. +> Properties of elements in a view can change dynamically, in response to user actions; the structure (number and order) of elements in a view can't. You can change the structure of elements by inserting, moving, or removing nested views within their view containers. > ->\- Angular Docs +> \- Angular Docs ## Embed Views {#embed-views} @@ -846,12 +835,12 @@ Starting with some small recap: - We're creating a template with the `ng-template` tag and assigning it to a template reference variable `templ` - We're also creating a `div` tag, assigning it to the template reference variable `viewContainerRef` - Lastly, `ViewChild` is giving us a reference to the template on the `templ` component class property. - - We're able to mark both of these as `static: true` as neither of them are obfuscated by non-host-view views as parents + - We're able to mark both of these as `static: true` as neither of them are obfuscated by non-host-view views as parents Now the new stuff: - We're also using `ViewChild` to assign the template reference variable `viewContainerRef` to a component class property. - - We're using the `read` prop to give it the [`ViewContainerRef`](https://angular.io/api/core/ViewContainerRef) class, which includes some methods to help us create an embedded view. + - We're using the `read` prop to give it the [`ViewContainerRef`](https://angular.io/api/core/ViewContainerRef) class, which includes some methods to help us create an embedded view. - Then, in the `ngOnInit` lifecycle, we're running the `createEmbeddedView` method present on the `ViewContainerRef` property to create an embedded view based on the template. If you take a look at your element debugger, you'll notice that the template is injected as a sibling to the `.testing` div: @@ -897,7 +886,6 @@ console.log(embeddIndex); // This would print `0`. The view container keeps track of all of the embedded views in its control, and when you `createEmbeddedView`, it searches for the index to insert the view into. - You're also able to lookup an embedded view based on the index you're looking for using `get`. So, if you wanted to get all of the indexes being tracked by `viewContainerRef`, you'd do: ```typescript @@ -950,7 +938,6 @@ To get around this, we can use the `ng-container` tag, which allows us to get a ``` - #### Move/Insert Template @@ -959,7 +946,6 @@ But oh no! You'll see that the ordering is off. The simplest (and probably most But this is a blog post, and I needed a contrived example to showcase how we can move views programmatically: - ```typescript const newViewIndex = 0; this.viewContainerRef.move(embeddRef1, newViewIndex); // This will move this view to index 1, and shift every index greater than or equal to 0 up by 1 @@ -1034,7 +1020,6 @@ You'll notice this code is almost exactly the same from some of our previous com However, the lack of a template associated with the directive enables some fun stuff, for example, _we can use the same dependency injection trick we've been using to get the view container reference_ to get a reference to the template element that the directive is attached to and render it in the `ngOnInit` method like so: - ```typescript @Directive({ selector: '[renderTheTemplate]' @@ -1162,7 +1147,6 @@ The main idea behind structural directives is that **they're directives that wil Let's look at a basic sample to start: - ```typescript @Directive({ selector: '[renderThis]' @@ -1194,7 +1178,7 @@ export class AppComponent {} Too much CS (computer science) speak? Me too, let's rephrase that. When you add the `*` to the start of the directive that's being attached to the element, you're essentially telling Angular to wrap that element in an `ng-template` and pass the directive to the newly created template. -From there, the directive can get a reference to that template from the constructor (as Angular is nice enough to pass the template to our directive when we ask for it [this is what the DI system does]). +From there, the directive can get a reference to that template from the constructor (as Angular is nice enough to pass the template to our directive when we ask for it \[this is what the DI system does]). The cool part about structural directives, though? Because they're simply directives, **you can remove the `*` and use it with an `ng-template` directly**. Want to use the `renderThis` without a structural directive? No problem! Replace the template with the following code block and you've got yourself a rendered template: @@ -1216,7 +1200,6 @@ But rendering a template without changing it in any way isn't a very useful stru So if we added an input with the same name as the directive ([as we did previously](#directive-same-name-input)) to accept a value to check the truthiness of, added an `if` statement to render only if the value is true, we have ourselves the start of an `ngIf` replacement that we've built ourselves! - ```typescript @Directive({ selector: '[renderThisIf]' @@ -1344,16 +1327,16 @@ export class NgIfContext { Just to recap, let's run through this line-by-line: 1. `_context` is creating a default of `{$implicit: null, ngIf: null}` - - The object shape is defined by the `NgIfContext` class below - - This is to be able to pass as a context to the template. While this is not required to understand how Angular implemented this directive in basic terms, it was left in to avoid editing code elsewhere + - The object shape is defined by the `NgIfContext` class below + - This is to be able to pass as a context to the template. While this is not required to understand how Angular implemented this directive in basic terms, it was left in to avoid editing code elsewhere 2. We're then defining a variable to keep track of the template reference and the view reference ([what `createEmbeddedView` returns](https://angular.io/api/core/EmbeddedViewRef)) for usage later 3. The constructor is then assigning the template reference to the variable, and getting a reference to the view container 4. We're then defining an input with the same name as a setter, as we did with our implementation - - This setter is also calling an update function, just as were with our implementation + - This setter is also calling an update function, just as were with our implementation 5. The update view is then seeing if the `$implicit` value in the context is truthy (as we're assigning the value of the `ngIf` input to the `$implicit` key on the context) 6. Further checks are made to see if there is a view reference already. - - If there is not, it will proceed to make one (checking first that there is a template to create off of) - - If there is, it will not recreate a view, in order to avoid performance issues by recreating views over-and-over again + - If there is not, it will proceed to make one (checking first that there is a template to create off of) + - If there is, it will not recreate a view, in order to avoid performance issues by recreating views over-and-over again ## Microsyntax @@ -1428,12 +1411,10 @@ export class MakePigLatinDirective { export class AppComponent {} ``` - Just as before, we would use semicolons to split the definitions, then bind the external (as in: from the directive) context value of `original` to the local (this template) variable of `ogMsg`. - ### Additional Attribute Inputs With a typical — non-structural — directive, you'd have inputs that you could add to your directive. For example, you could have a directive with the following inputs: @@ -1513,7 +1494,6 @@ The magic in the syntax comes from that input name. I know in previous examples **This is why we usually call the directive selector the structural directive prefix — it should prefix the names of any of your microsyntax inputs**. Outside of the prefix rule, there's little else that you'll need to keep in mind with these input names. Want to make it `makePiglatinCasingThingHere`? No problem, just change that part of the input syntax to read `casingThingHere: 'upper'` - #### Why not bind like a typical input? Now, I remember when I was learning a lot of the structural directive stuff, I thought "well this syntax is cool, but it might be a bit ambiguous". I decided I was going to change that a bit: @@ -1687,7 +1667,6 @@ A key expression is simply an expression that you’re able to bind to an input - You’ll then want to **place an expression that will be passed as the input value** for the `key` you started the key expression with - Finally, _if you’d like to save the input value_, you’re able to **use the `as` keyword**, followed by the name you’d like to save the input value to (as a template input variable) - ```html

@@ -1702,8 +1681,8 @@ The `let` binding: - Starts with a `let` preserved keyword - Then lists the template input variable to save the value to - You’ll then want to put the key of the context you want to save a value of after a `=` operator - - It’s worth mentioning that this is optional. This is because of the `$implicit` key in context. - EG: a context of `{$implicit: 1, namedKey: 900}` and `let smallNum; let largerNum = namedKey` would assign `1` to `smallNum` and `900` to `largerNum` + - It’s worth mentioning that this is optional. This is because of the `$implicit` key in context. + EG: a context of `{$implicit: 1, namedKey: 900}` and `let smallNum; let largerNum = namedKey` would assign `1` to `smallNum` and `900` to `largerNum` ### Combining Them Together @@ -1821,14 +1800,16 @@ export class AppComponent { - We're starting with enabling `uniFor` as the structural directive name + - Then we're defining an input to accept `of` as a key in the syntax (to match the `ngFor` structural directive syntax). - We can then reference this value later with `this.uniForOf` just as we are in the `ngAfterViewInit`. - In that lifecycle method, we're then creating an embedded view for each item in the array - - This view is passed a context with an implicit value (so that `_var` in`let _var of list` will have the value of this item) - - We also pass the index to the context to give a boolean if an item is the first in a list - - Then we pass a `uniForOf` so that we can use `as` to capture the value passed to the `of` portion of the syntax + - This view is passed a context with an implicit value (so that `_var` in`let _var of list` will have the value of this item) + - We also pass the index to the context to give a boolean if an item is the first in a list + - Then we pass a `uniForOf` so that we can use `as` to capture the value passed to the `of` portion of the syntax + - Finally, we use the [async pipe](https://angular.io/api/common/AsyncPipe) to get the value of the array that's inside of an observable # Conclusion diff --git a/content/blog/basic-overview-of-packets-and-osi/index.md b/content/blog/basic-overview-of-packets-and-osi/index.md index 898ee01c..b589df36 100644 --- a/content/blog/basic-overview-of-packets-and-osi/index.md +++ b/content/blog/basic-overview-of-packets-and-osi/index.md @@ -22,7 +22,8 @@ It's important to note that _"networking" is a broad, catch-all term that infers > That said, you need the right binary data to be input into the CPU for it to process, just like our brains need the right input to find the answer of what to do. Because of this, communication with the CPU is integral # Architecture {#network-architectures} -There are a lot of ways that information can be connected and transferred. We use various types of architecture to connect them. + +There are a lot of ways that information can be connected and transferred. We use various types of architecture to connect them. _Computers speak in `1`s and `0`s, known as binary_. These binary values come in incredibly long strings of combinations of one of the two symbols to _construct all of the data used in communication_. @@ -44,7 +45,7 @@ Furthermore, because error-handled bi-directional cancelable subscriptions (like ## Packet Architecture {#packet-architecture} -The weaknesses of the bus architecture led to the creation of the packet architecture. The packet architecture requires a bit more of a higher-level understanding of how data is sent and received. To explain this concept, we'll use an analogy that fits really well. +The weaknesses of the bus architecture led to the creation of the packet architecture. The packet architecture requires a bit more of a higher-level understanding of how data is sent and received. To explain this concept, we'll use an analogy that fits really well. Let's say you want to send a note to your friend that's hours away from you. You don't have the internet so you decide to send a letter. In a typical correspondence, you'd send off a letter, include a return address, and wait for a response back. That said, _there's nothing stopping someone from sending more than a single letter before receiving a response_. This chart is a good example of that: @@ -56,7 +57,7 @@ Similarly, a packet is _sent from a single sender, received by a single recipien Letters may not give you the same kind of continuous stream of consciousness as in-person communications, but they do provide something in return: structure. -The way you might structure your thoughts when speaking is significantly different from how you might organize your thoughts on paper. For example, in this article, there is a clear beginning, end, and structured headings to each of the items in this article. Such verbose metadata (such as overall length) cannot be communicated via in-person talking. _The way you may structure data in a packet may also differ from how you might communicate data via a bus_. +The way you might structure your thoughts when speaking is significantly different from how you might organize your thoughts on paper. For example, in this article, there is a clear beginning, end, and structured headings to each of the items in this article. Such verbose metadata (such as overall length) cannot be communicated via in-person talking. _The way you may structure data in a packet may also differ from how you might communicate data via a bus_. That said, simply because there's a defined start and an end does not mean that you cannot _send large sequences of data through multiple packets and stitch them together_. Neither is true for the written word. This article does not contain the full set of information the series we hope to share, but rather provides a baseline and structure for how the rest of the information is to be consumed. So too can packets provide addendums to other packets, if you so wish. diff --git a/content/blog/change-host-file-android-emulator/index.md b/content/blog/change-host-file-android-emulator/index.md index 9ecaa8f8..3d84a269 100644 --- a/content/blog/change-host-file-android-emulator/index.md +++ b/content/blog/change-host-file-android-emulator/index.md @@ -23,13 +23,13 @@ In order to do this, you’ll need to install a few things first: During installation, it will ask you if you want to setup an emulator. You’ll want to install all of the related Intel Virtualization packages, as it will greatly increase your speed of the emulator. -- Download and install the android-platform-tools. This will include +- Download and install the android-platform-tools. This will include ``` adb ``` - command directly on your path for you to utilize + command directly on your path for you to utilize - For macOS, I suggest using [the Homebrew package manager](https://brew.sh/) and running `brew cask install android-platform-tools` - For Windows, I suggest using [the Chocolatey package manager](https://chocolatey.org/) and running `choco install adb` @@ -45,19 +45,19 @@ Then, press “Configure” in the bottom right corner. Then press the “AVD Ma ![The sub-menu for configure in the Android Studio startup screen](./2.png) -You’ll see a popup window that will show you the list of virtual devices. *These are devices that will be used in order to run an emulator*. You may already have a virtual device setup from the initial setup of Android Studio. They include the version of the operating system you use when you boot up the device. While the virtual device that was setup out-of-the-box is fine for most operations, we’ll want to setup an older version of the emulator. This will allow us to change the host file in Android, which requires root (something the default images won’t allow). +You’ll see a popup window that will show you the list of virtual devices. _These are devices that will be used in order to run an emulator_. You may already have a virtual device setup from the initial setup of Android Studio. They include the version of the operating system you use when you boot up the device. While the virtual device that was setup out-of-the-box is fine for most operations, we’ll want to setup an older version of the emulator. This will allow us to change the host file in Android, which requires root (something the default images won’t allow). Select **Create Virtual Device**, then select a device type. In my example, I selected **Nexus 5**, but any device definition of a relatively modern phone should work. ![A popup dialog for creating a new virtual device setup](./3.png) -As mentioned before, the default images that are provided will not allow us to replace the host files. In order to do so, *we have to download an older Android image* (and one that does not include Google Play Store). To do this, I selected the **x86_64 Android 7.1.1** (non Google API version) image to download and then selected **Next**. +As mentioned before, the default images that are provided will not allow us to replace the host files. In order to do so, _we have to download an older Android image_ (and one that does not include Google Play Store). To do this, I selected the **x86\_64 Android 7.1.1** (non Google API version) image to download and then selected **Next**. ![The selection of the aforementioned Nougat image](./4.png) It’s worth noting that we specifically must select a non-Google version, otherwise our future commands will not work (per Google’s restrictions on Google API images). -After this step, proceed to name the Android Device. *I’d suggest you name it something without any spaces in order to run a command later that you’ll need to run*. In this case, I called the image **Nexus5**. +After this step, proceed to name the Android Device. _I’d suggest you name it something without any spaces in order to run a command later that you’ll need to run_. In this case, I called the image **Nexus5**. ![My naming of the AVD](./5.png) @@ -65,8 +65,8 @@ After this step, proceed to name the Android Device. *I’d suggest you name it Once the AVD is initially setup, open your terminal, and find your installation path of Android Studio. -- For MacOS, this should be under **~/Library/Android/sdk** -- For Windows, this *should* be **C:\Users\AppData\Local\Android\sdk** +- For MacOS, this should be under **\~/Library/Android/sdk** +- For Windows, this _should_ be **C:\Users\AppData\Local\Android\sdk** Once in that path, you want to run a specific emulator command: @@ -92,9 +92,9 @@ Once you’re done with running the emulator, open a new tab and run the follow ![A screenshot of the above commands running](./7.png) -Upon running these commands, you’ll find a **hosts** file. *This file is the file that tells your OS what path a given domain has.* You can, for example, map `example.com` to go to a specific IP address, similar to how DNS works for most domains. +Upon running these commands, you’ll find a **hosts** file. _This file is the file that tells your OS what path a given domain has._ You can, for example, map `example.com` to go to a specific IP address, similar to how DNS works for most domains. -Inside the emulator, the IP address `10.0.2.2` refers to the *host* OS. For example, if you’re running a local server on your Windows/MacOS/Linux machine on `localhost:3000`, you can access it using `10.0.2.2:3000` from the Android emulator. +Inside the emulator, the IP address `10.0.2.2` refers to the _host_ OS. For example, if you’re running a local server on your Windows/MacOS/Linux machine on `localhost:3000`, you can access it using `10.0.2.2:3000` from the Android emulator. Knowing these two things, you can change the host file to make `example.com` refer to the host by adding the following to the host file: diff --git a/content/blog/chess-knight-problem/index.md b/content/blog/chess-knight-problem/index.md index c6d359a8..c9b7afd1 100644 --- a/content/blog/chess-knight-problem/index.md +++ b/content/blog/chess-knight-problem/index.md @@ -118,7 +118,7 @@ console.log(findPath(3, 3, 2, 1)); I correctly got 1. -One of the spots that we can reach in 2 moves is \[4,6\]. +One of the spots that we can reach in 2 moves is \[4,6]. ```javascript console.log(findPath(3, 3, 4, 6)); diff --git a/content/blog/corbin-advice-to-technical-interviewers/index.md b/content/blog/corbin-advice-to-technical-interviewers/index.md index 6faab4a7..ea116efa 100644 --- a/content/blog/corbin-advice-to-technical-interviewers/index.md +++ b/content/blog/corbin-advice-to-technical-interviewers/index.md @@ -13,36 +13,33 @@ Tech recruiting is difficult. Interviews are tricky for candidates - and for interviewers. One of the untold challenges of interviewing is knowing how to set up good candidates for success. After all, you want a process that tests the right skills, and filters out the noise that is not helpful to evaluating candidates. - This can be done in many ways, but let’s talk about a few today. # Don’t Be Afraid To Help -Something to keep in mind while interviewing candidates is that they’re just like you and me: people. People that make mistakes from time-to-time or might get stuck on a certain phrasing of a question. +Something to keep in mind while interviewing candidates is that they’re just like you and me: people. People that make mistakes from time-to-time or might get stuck on a certain phrasing of a question. Oftentimes, lending a gentle helping hand can be the ticket to a successful interview. It can be as simple as rephrasing the question in a way that points towards the solution, or providing a structural bit of code that needs tweaking in order to be solved. This is particularly beneficial for junior engineers, who’s interviews should focus more on “thought process” and “ability to learn and communicate” than existing skill sets. However, even senior engineers can have the solution escape them until it finally clicks with some small assistance. - While this all might seem counterintuitive to assist a candidate (even in small ways) during an interview, you have to remember that they need support. In their future role with your company, they won’t (and shouldn’t) be working in isolation. Instead, they will have a team to lean on. By giving a small hint here and there, you’re able to understand how they receive feedback and when they need help. # Allow for Resources -As mentioned earlier, candidates are just people. Because of that, you will never find an all-knowing candidate who only ever relies solely on their existing knowledge to fix an issue (no matter what big-ego Jim says). Time-and-time again I’ve heard from seasoned developers that research and cheat-sheets are part of their daily engineering work. +As mentioned earlier, candidates are just people. Because of that, you will never find an all-knowing candidate who only ever relies solely on their existing knowledge to fix an issue (no matter what big-ego Jim says). Time-and-time again I’ve heard from seasoned developers that research and cheat-sheets are part of their daily engineering work. While it might not be immediately obvious, knowing how to search for and find the relevant content is incredibly important. Not only that, it’s something that’s developed gradually alongside a developer’s journey - just like any other skill. - After all, the point of coding interviews is to see how capable a developer is at the job they’re applying for. You want to test in real-world situations, not in an isolated environment that doesn’t represent the daily aspects of the job. # Less Algorithms, More Demos Speaking of representing a job in a more realistic light: think about the last time you had a ticket in your backlog that required discussion of tree reversal (or similar algorithm). Now think of the last time you asked a question like that in your interviews. See where I’m going here? I’m not implying that algorithm questions are inherently bad for every position, but in this industry they’ve been used as a stop-gap for more relevant questions. -Many engineers can attest to being asked algorithmic questions in an interview - only to be working with styling and application state management in their day jobs. The usage of complex algorithms are far-and-few between - especially in front-end engineering. +Many engineers can attest to being asked algorithmic questions in an interview - only to be working with styling and application state management in their day jobs. The usage of complex algorithms are far-and-few between - especially in front-end engineering. -Even when algorithms ***are\*** relevant, there’s usually a team to discuss with, research to be done, and benchmarking to verify the usage of a given algorithm for key application logic. These discussions can take significantly longer than an hour long interview. +Even when algorithms \***are\*** relevant, there’s usually a team to discuss with, research to be done, and benchmarking to verify the usage of a given algorithm for key application logic. These discussions can take significantly longer than an hour long interview. Not only are these questions rarely representative of the actual job, they’re also easy to cheat with someone with enough free-time to dedicate towards algorithm memorization. Googling “interview algorithm questions” provides over 17 million results. Even the first page of results promises to teach you how to instantly solve dozens of common algorithm questions. @@ -62,7 +59,7 @@ While real-world code samples provide many upsides, setting up a real-world exam # Take-Homes -We at CoderPad are ***strong\*** advocates of take-home interviews for technical assessments. While [we’ve written about many of the benefits of take-homes before](https://coderpad.io/blog/hire-better-faster-and-in-a-more-human-way-with-take-homes/), we’ll touch on some of the advantages here: +We at CoderPad are \***strong\*** advocates of take-home interviews for technical assessments. While [we’ve written about many of the benefits of take-homes before](https://coderpad.io/blog/hire-better-faster-and-in-a-more-human-way-with-take-homes/), we’ll touch on some of the advantages here: - Lower stress environment for candidate - We’ve heard a lot from the autistic community and those with anxiety that this helps a lot diff --git a/content/blog/css-fundamentals/index.md b/content/blog/css-fundamentals/index.md index 0eb801f0..7b7d3487 100644 --- a/content/blog/css-fundamentals/index.md +++ b/content/blog/css-fundamentals/index.md @@ -55,7 +55,7 @@ Every element on the browser has a box model. You can inspect them using browser Nearly every HTML element has some default browser styles. These styles are called HTML defaults. These defaults may change depending on the browsers rendering engine. -> 🤓 Not every browser supports every CSS property! For up-to-date browser support I suggest checking out [Can I Use?](https://www.google.com/search?q=caniuse&rlz=1C1CHBF_enCA963CA963&oq=caniuse&aqs=chrome.0.69i59j69i60l3.1776j0j4&sourceid=chrome&ie=UTF-8) +> 🤓 Not every browser supports every CSS property! For up-to-date browser support I suggest checking out [Can I Use?](https://www.google.com/search?q=caniuse\&rlz=1C1CHBF_enCA963CA963\&oq=caniuse\&aqs=chrome.0.69i59j69i60l3.1776j0j4\&sourceid=chrome\&ie=UTF-8) Every HTML element has a place and a purpose. Some HTML elements are strictly used for grouping content and are generally referred to as containers, while other HTML elements are used for text, images and more. @@ -203,7 +203,7 @@ justify-content: space-evenly; > 🤓 Space your content out with justify-content -Here is a list of CSS properties used to control flexbox properties: +Here is a list of CSS properties used to control flexbox properties: - [`flex-direction`](https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction) - controls flexbox direction - [`flex-grow`](https://developer.mozilla.org/en-US/docs/Web/CSS/flex-grow) - controls a flex items grow factor @@ -337,9 +337,9 @@ There are five types of element positions: #### Flexbox: - - Used in headers, lists, tags, or any other block or inline content with the correct flex-direction - - Primary method to align and justify content in small components - - Easy to use +- Used in headers, lists, tags, or any other block or inline content with the correct flex-direction +- Primary method to align and justify content in small components +- Easy to use For example, YouTube uses a flexbox to space out their headers children elements: @@ -347,20 +347,20 @@ For example, YouTube uses a flexbox to space out their headers children elements > 🤓 Mastering the flexbox will take you very far in CSS as it is used everywhere -#### Gridbox: +#### Gridbox: - - Used in creating complex layouts that require both columns and rows - - Provides the easiest and shortest way to center elements - - Verbose and powerful +- Used in creating complex layouts that require both columns and rows +- Provides the easiest and shortest way to center elements +- Verbose and powerful For example, Spotify uses a gridbox to achieve their playlist player layout: ![spotify.png](./spotify.png) -#### Positioning: +#### Positioning: - - Used in lightboxes, mobile menus, modal windows, and similar overlaying elements - - Primarily used to remove elements from document flow +- Used in lightboxes, mobile menus, modal windows, and similar overlaying elements +- Primarily used to remove elements from document flow For example, the cookies modal on stackoverflow uses a fixed position to stay on your screen while hovering above other document elements: @@ -422,7 +422,7 @@ There are five basic CSS selectors: - **Type (`h1`)** - Targets all with the given type - **Attribute (`[type="submit"]`)** Targets all with the given attribute -> 🤓 I recommend using the `.class` selector over the `#id` selector as ID attributes are unique +> 🤓 I recommend using the `.class` selector over the `#id` selector as ID attributes are unique You can group selectors under one CSS rule using commas to share properties among multiple selectors: @@ -532,4 +532,4 @@ CSS variables allow us to define arbitrary values for reuse across a stylesheet. It is common to use CSS variables for repeated values such as colors, font-size, padding, etc. -> ⚡ [Live Code Example: CSS Variables](https://codesandbox.io/s/css-variables-tx14z?file=/styles.css) \ No newline at end of file +> ⚡ [Live Code Example: CSS Variables](https://codesandbox.io/s/css-variables-tx14z?file=/styles.css) diff --git a/content/blog/data-storage-options-in-react-native/index.md b/content/blog/data-storage-options-in-react-native/index.md index 17ff9044..fbd8dd6c 100644 --- a/content/blog/data-storage-options-in-react-native/index.md +++ b/content/blog/data-storage-options-in-react-native/index.md @@ -62,14 +62,14 @@ While you're more than able to cache database calls manually, sometimes it's con # Pros and Cons {#pros-and-cons} -| Option | Pros | Cons | -| --------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| [Key-Value Pair Storage](#default-preference) |
  • Extremely fast
  • Useful for simple data storing
|
  • Can only store serializable data
  • Not very cleanly separated
  • Not very secure
| -| [Secure Key-Value Storage](#secure-key-store) |
  • Fast
  • A secure method of data storing
|
  • Can only store serializable data
  • Not very cleanly separated
| -| [SQLite without ORM](#sqlite-storage) |
  • Cleanly separated data
|
  • Difficult to maintain code and table migrations manually
  • Not very fast compared to key-value pairs
| -| [SQLite with ORM](#orms) |
  • Cleanly separated data
  • Much more easy to maintain than writing SQL itself
|
  • Often slower than writing SQL by hand
  • More work to get setup
| -| [Serverless](#serverless) |
  • Simple setup
  • No need to schema or migrate a database when data requirements change
|
  • Potentially difficult to cache
  • Not on-device
| -| [RealmDB](#realm) |
  • An easy-to-sync on-device and cloud storage
|
  • A heavier requirement of investment than something more standard
  • Large migrations on the horizon
| +| Option | Pros | Cons | +| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | +| [Key-Value Pair Storage](#default-preference) |
  • Extremely fast
  • Useful for simple data storing
|
  • Can only store serializable data
  • Not very cleanly separated
  • Not very secure
| +| [Secure Key-Value Storage](#secure-key-store) |
  • Fast
  • A secure method of data storing
|
  • Can only store serializable data
  • Not very cleanly separated
| +| [SQLite without ORM](#sqlite-storage) |
  • Cleanly separated data
|
  • Difficult to maintain code and table migrations manually
  • Not very fast compared to key-value pairs
| +| [SQLite with ORM](#orms) |
  • Cleanly separated data
  • Much more easy to maintain than writing SQL itself
|
  • Often slower than writing SQL by hand
  • More work to get setup
| +| [Serverless](#serverless) |
  • Simple setup
  • No need to schema or migrate a database when data requirements change
|
  • Potentially difficult to cache
  • Not on-device
| +| [RealmDB](#realm) |
  • An easy-to-sync on-device and cloud storage
|
  • A heavier requirement of investment than something more standard
  • Large migrations on the horizon
| # Conclusion diff --git a/content/blog/debugging-nodejs-programs-using-chrome/index.md b/content/blog/debugging-nodejs-programs-using-chrome/index.md index efdeb059..e02baeff 100644 --- a/content/blog/debugging-nodejs-programs-using-chrome/index.md +++ b/content/blog/debugging-nodejs-programs-using-chrome/index.md @@ -42,7 +42,7 @@ app.get('/', (req, res) => { app.listen(3000); ``` -You'll notice that we're using the dummy endpoint http://www.mocky.io/v2/5e1a9abe3100004e004f316b. This endpoint returns an array of values with a shape much like this: +You'll notice that we're using the dummy endpoint . This endpoint returns an array of values with a shape much like this: ```json [ @@ -145,7 +145,7 @@ In order to access the debugger, you'll need to open up Chrome and go to the URL Then you'll want to select `inspect` on the node instance. -Doing so will bring up a screen of your entrypoint file with the source code in a window with line numbers. +Doing so will bring up a screen of your entrypoint file with the source code in a window with line numbers. ![The aforementioned code screen](./initial_debugger.png) @@ -155,7 +155,7 @@ Think about running your code like driving an experimental race-car. This car ha It's similar to a debug mode of your program. You can evaluate data using `console.log`, but _to gain greater insight, you may want to pause your application_, inspect the small details in the code during a specific state, and to do so you must pause your code. This is where breakpoints come into play: they allow you to place "pause" points into your code so that when you reach the part of code that a breakpoint is present on, your code will pause and you'll be given much better insight to what your code is doing. -To set a breakpoint from within the debugging screen, you'll want to select a code line number off to the left side of the screen. This will create a blue arrow on the line number. +To set a breakpoint from within the debugging screen, you'll want to select a code line number off to the left side of the screen. This will create a blue arrow on the line number. > If you accidentally select a line you didn't mean to, that's okay. Pressing this line again will disable the breakpoint you just created @@ -163,7 +163,7 @@ To set a breakpoint from within the debugging screen, you'll want to select a co A race-car needs to drive around the track until the point where the pit-stop is in order to be inspected; _your code needs to run through a breakpoint in order to pause and give you the expected debugging experience_. This means that, with only the above breakpoint enabled, the code will not enter into debug mode until you access `localhost:3000` in your browser to run the `app.get('/')` route. -> Some applications may be a bit [quick-on-the-draw](https://en.wiktionary.org/wiki/quick_on_the_draw) in regards to finding an acceptable place to put a breakpoint. If you're having difficulties beating your code running, feel free to replace the `--inspect` flag with `--inspect-brk` which will automatically add in a breakpoint to the first line of code in your running file. +> Some applications may be a bit [quick-on-the-draw](https://en.wiktionary.org/wiki/quick_on_the_draw) in regards to finding an acceptable place to put a breakpoint. If you're having difficulties beating your code running, feel free to replace the `--inspect` flag with `--inspect-brk` which will automatically add in a breakpoint to the first line of code in your running file. > > This way, you should have the margins to add in a breakpoint where you'd like one beforehand. @@ -179,7 +179,7 @@ Once you do so, you're in full control of your code and its state. You can: - _Inspect the values of variables_ (either by highlighting the variable you're interested in, looking under the "scope" tab on the right sidebar, or using the `Console` tab to run inspection commands à la [`console.table`](https://developer.mozilla.org/en-US/docs/Web/API/Console/table) or [`console.log`](https://developer.mozilla.org/en-US/docs/Web/API/Console/log)): - ![A screenshot of all three of the mentioned methods to inspect a variable's value](./inspect_variable_value.png) + ![A screenshot of all three of the mentioned methods to inspect a variable's value](./inspect_variable_value.png) - _Change the value of a variable:_ ![A screenshot of using the Console tab in order to change the value of a variable as you would any other JavaScript variable](./change_variable_value.png) - _Run arbitrary JavaScript commands_, similar to how a code playground might allow you to: @@ -199,7 +199,7 @@ So, if we want to see what happens after the `body` JSON variable is parsed into Knowing this, let's move through the next few lines manually by pressing each item. The ran values of the variables as they're assigned should show up to the right of the code itself in a little yellow box; This should help you understand what each line of code is running and returning without `console.log`ging or otherwise manually. -![A screenshot showing ran lines until line 12 of the "console.log". It shows that "employeeAges" is "[undefined]"](./next_few_lines.png) +![A screenshot showing ran lines until line 12 of the "console.log". It shows that "employeeAges" is "\[undefined\]"](./next_few_lines.png) But oh no! You can see, `employeeAges` on line `9` is the one that results in the unintended `[undefined]`. It seems to be occurring during the `map` phase, so let's add in a breakpoint to line `10` and reload the `localhost:3000` page (to re-run the function in question). @@ -209,7 +209,7 @@ Once you hit the first breakpoint on line `7`, you can press "play" once again t This will allow us to see the value of `employee` to see what's going wrong in our application to cause an `undefined` value. -![A show of the "employee" object that has a property "employee_age"](./inspect_employee.png) +![A show of the "employee" object that has a property "employee\_age"](./inspect_employee.png) Oh! As we can see, the name of the field we're trying to query is `employee_age`, not the mistakenly typo'd `employeeAge` property name we're currently using in our code. Let's stop our server, make the required changes, and then restart the application. @@ -217,8 +217,6 @@ We will have to run through the breakpoints we've set by pressing the "play" but ![Showing that the console log works out the way expected once the map is changed](./working_ran_debugger_code.png) - - There we go! We're able to get the expected "23"! That said, it was annoying to have to press "play" twice. Maybe there's something else we can do in similar scenarios like this? ## Disabling Breakpoints {#disabling-breakpoints} @@ -253,7 +251,7 @@ Once inside the `map` function, there's even a button _to get you outside of tha > } > return ageArray; > }; -> +> > app.get('/', (req, res) => { > request('http://www.mocky.io/v2/5e1a9abe3100004e004f316b', (error, response, body) => { > const responseList = JSON.parse(body); diff --git a/content/blog/documentation-driven-development/index.md b/content/blog/documentation-driven-development/index.md index edabb10a..097161ef 100644 --- a/content/blog/documentation-driven-development/index.md +++ b/content/blog/documentation-driven-development/index.md @@ -66,7 +66,7 @@ function calculateUserScore({killsArr, deaths, assists}) { } ``` -While we've seen the function change, remember that your game may be making this calculation in multiple parts of the codebase. On top of this, maybe your API *still* isn't perfect for this function. What if you want to display the special kills with additional points after a match? +While we've seen the function change, remember that your game may be making this calculation in multiple parts of the codebase. On top of this, maybe your API _still_ isn't perfect for this function. What if you want to display the special kills with additional points after a match? These drastic refactors mean that each iteration requires additional refactor work, likely delaying the time to ticket completion. This can impact releases dates or other scheduled launches. @@ -148,19 +148,19 @@ In fact, this _includes_ tests. 😱 Tests are a good way of conveying API examp In particular, if you're good about [writing primarily integration tests](https://kentcdodds.com/blog/write-tests), you're actually writing out usage API docs while writing testing code. -This is particularly true when writing developer tooling or libraries. Seeing a usage example of how to do something is extremely helpful, especially with a test to validate its behavior alongside it. +This is particularly true when writing developer tooling or libraries. Seeing a usage example of how to do something is extremely helpful, especially with a test to validate its behavior alongside it. -------- +--- Another thing "documentation-driven development" does not prescribe is "write once and done." This idea is a myth and may be harmful to your scope and budgets - time or otherwise. As we showed with the `calculateUserScore` example, you may need to modify your designs before moving forward for the final release: that's okay. Docs influence code influence docs. The same is true for TDD. --------- +--- DDD isn't just useful for developing code for production, either. In interviews, some good advice to communicate your development workflow is to write code comments and **then** write the solution. This allows you to make mistakes in the documentation phase (of writing comments) that will be less time-costly than if you'd made a mistake in implementation. -By doing this, you can communicate with your interviewer that you know how to work in a team and find well-defined goals. These will allow you to work towards an edgecase-free* implementation with those understandings. +By doing this, you can communicate with your interviewer that you know how to work in a team and find well-defined goals. These will allow you to work towards an edgecase-free\* implementation with those understandings. # Bring it back now y'all @@ -173,10 +173,10 @@ Each of these refers to a form of validating the functionality of code behind us # Conclusion -I've been using documentation-driven development as a concept to drive my coding on some projects. Among them was my project [`CLI Testing Library`](https://github.com/crutchcorn/cli-testing-library), which allowed me to write a [myriad of documentation pages](https://github.com/crutchcorn/cli-testing-library/tree/main/docs) as well as [verbose GitHub issues](https://github.com/crutchcorn/cli-testing-library/issues/2). +I've been using documentation-driven development as a concept to drive my coding on some projects. Among them was my project [`CLI Testing Library`](https://github.com/crutchcorn/cli-testing-library), which allowed me to write a [myriad of documentation pages](https://github.com/crutchcorn/cli-testing-library/tree/main/docs) as well as [verbose GitHub issues](https://github.com/crutchcorn/cli-testing-library/issues/2). Both of these forced me to better refine my goals and what I was looking for. The end-product, I believe, is better as a result. What do you think? Is "DDD" a good idea? Will you be using it for your next project? -Let us know what you think, and [join our Discord](https://discord.gg/FMcvc6T) to talk to us more about it! +Let us know what you think, and [join our Discord](https://discord.gg/FMcvc6T) to talk to us more about it! diff --git a/content/blog/dom-pollution-why-i-prefer-vue-over-angular/index.md b/content/blog/dom-pollution-why-i-prefer-vue-over-angular/index.md index 235ff906..33355967 100644 --- a/content/blog/dom-pollution-why-i-prefer-vue-over-angular/index.md +++ b/content/blog/dom-pollution-why-i-prefer-vue-over-angular/index.md @@ -41,6 +41,7 @@ Then if you tried the same in Angular: What happened? Lets compare the custom components. `MyTextCell.vue` + `text-cell.component.ts` + - -## Conclusion - -As promised, the update to React 18 is fairly straightforward! Most applications should be able to upgrade without too many problems. - -If you run into issues during your migration and you’re using `StrictMode`, try temporarily removing it to see if you run into any issues. [React 18 introduced some changes that may impact some apps.](https://github.com/reactwg/react-18/discussions/19) - -We hope you enjoy the new [React concurrent features](https://github.com/reactwg/react-18/discussions/4) and happy hacking! +); +``` + +When finished, you should be able to verify the version of React you’re using with `{React.version}` + + + +## Conclusion + +As promised, the update to React 18 is fairly straightforward! Most applications should be able to upgrade without too many problems. + +If you run into issues during your migration and you’re using `StrictMode`, try temporarily removing it to see if you run into any issues. [React 18 introduced some changes that may impact some apps.](https://github.com/reactwg/react-18/discussions/19) + +We hope you enjoy the new [React concurrent features](https://github.com/reactwg/react-18/discussions/4) and happy hacking! diff --git a/content/blog/how-to-use-npm/index.md b/content/blog/how-to-use-npm/index.md index 64212c93..bd14fe02 100644 --- a/content/blog/how-to-use-npm/index.md +++ b/content/blog/how-to-use-npm/index.md @@ -34,8 +34,8 @@ Any sufficiently useful programming language needs an ecosystem to rely on. One `npm` is a combination of two things: -1) The registry - the servers and databases that host the packages with their specific named packages. -2) The client-side CLI utility - the program that runs on your computer in order to install and manage the packages on your local disk +1. The registry - the servers and databases that host the packages with their specific named packages. +2. The client-side CLI utility - the program that runs on your computer in order to install and manage the packages on your local disk When, say, Facebook wants to publish a new version of `react`, someone from the React team (with publishing credentials) will setup and build the production version of the React source code, open the client-side utility in order to run the command `npm publish`, which will send the production code to the registry. From there, when you install `react` using the `npm` command on your device, it will pull the relevant files from the registry onto your local machine for you to use. @@ -43,13 +43,13 @@ While the registry is vital for the usage of the CLI utility, most of the time w # Setting Up Node {#setup-node} -Before we explain how to install Node, let's explain something about the release process of the software. +Before we explain how to install Node, let's explain something about the release process of the software. -When it comes to install options there are two: +When it comes to install options there are two: -1) LTS +1. LTS -2) Current +2. Current The "LTS" release stands for "long-term support" and is considered the most "stable" release that is recommended for production usage. This is because LTS releases will receive critical bug fixes and improvements even after a new version comes along. LTS releases often see years of support. @@ -59,7 +59,7 @@ NodeJS switches back and forth between LTS and non-LTS stable releases. For exam ## Installing Node {#installing-node} -You can find pre-built binaries ready-to-install from [NodeJS' website](https://nodejs.org/en/download/). Simply download the package you want and install it. +You can find pre-built binaries ready-to-install from [NodeJS' website](https://nodejs.org/en/download/). Simply download the package you want and install it. > If you're unsure which version of Node to go with, stick to the LTS release @@ -177,10 +177,8 @@ Just as there's a method for installing `yarn` natively on macOS, you can do the choco install yarn ``` - > There are other methods to install Yarn on Windows if you'd rather. [Look through `yarn`'s official docs for more](https://classic.yarnpkg.com/en/docs/install/#windows-stable) - # Using Node {#using-node} Now that you have it setup, let's walk through how to use Node. First, start by opening your terminal. @@ -237,7 +235,7 @@ Then, in your terminal, `cd` into the directory the `index.js` file is and run ` ![Windows Terminal showing the program output](./output-js.png) -This particular program will automatically exits Node once it's completed running, but not all do. Some programs, like the following, may run until manually halted: +This particular program will automatically exits Node once it's completed running, but not all do. Some programs, like the following, may run until manually halted: ```javascript // index.js @@ -388,9 +386,9 @@ While you can use these numbers arbitrarily, most projects follow [a standard ca The basics of semantic versioning can be broken down into three parts: -1) The major version -2) The minor version -3) The patch version +1. The major version +2. The minor version +3. The patch version In SemVer, a package version might look something like `MAJOR.MINOR.PATCH`. A package with `2.1.3` has a "**major** version" of `2`, a "**minor** version" of `1`, and a "**patch** version" of `3`. @@ -528,13 +526,13 @@ Worried that your dependencies might not resolve the same version on systems lik ## Lock Files {#package-lock} -Once you run `npm i` on a project with dependencies, you'll notice a new file in your root folder: `package-lock.json`. This file is called your **"lockfile"**. **This file is auto-generated by `npm` and should not be manually modified.** +Once you run `npm i` on a project with dependencies, you'll notice a new file in your root folder: `package-lock.json`. This file is called your **"lockfile"**. **This file is auto-generated by `npm` and should not be manually modified.** > If you're using `yarn`, you'll notice instead this file is called `yarn.lock`. It serves the same purpose as `package-lock.json` and should be treated similarly While your `package.json` describes which versions you'd _prefer_ to be installed, your lockfile nails down exactly which version of the dependency (and sub dependencies) were resolved and installed when it came time to install your packages. This allows you to use commands like `npm ci` to install directly from this lockfile and install the exact same version of packages you had installed previously. -This can be incredibly helpful for debugging package resolution issues as well as making sure your CI/CD pipeline installs the correct versions of deps. +This can be incredibly helpful for debugging package resolution issues as well as making sure your CI/CD pipeline installs the correct versions of deps. While it's imperative not to track your `node_modules` folder, you **want to commit your `package-lock` file in your git repo**. This ensures that things like CI pipelines are able to run the same versions of dependencies you're utilizing on your local machine. diff --git a/content/blog/integrating-android-code-in-unity/index.md b/content/blog/integrating-android-code-in-unity/index.md index d60445b4..241bc5b3 100644 --- a/content/blog/integrating-android-code-in-unity/index.md +++ b/content/blog/integrating-android-code-in-unity/index.md @@ -41,7 +41,6 @@ Once the copying of the files from the Android Studio environment to `Assets` ha This will naturally incur a question for developers who have tried to maintain a system of duplication of any size: **How do you manage dependencies between these two folders?** - ## Managing Android Dependencies {#android-dependencies} Luckily for us, managing Android code dependencies in Unity has a thought-out solution from a large company: Google. [Because Google writes a Firebase SDK for Unity](https://firebase.google.com/docs/unity/setup), they needed a solid way to manage native dependencies within Unity. @@ -111,17 +110,13 @@ dependencies { This will take all of the AAR files and JAR files and treat them as if they were synced by Android Studio's Gradle sync. - - For more information on how to manage your app's dependencies from within Unity, you may want to check out [this article created by the Firebase developers](https://medium.com/firebase-developers/how-to-manage-your-native-ios-and-android-dependencies-in-unity-like-firebase-921659843aef), who coincidentally made the plugin for managing Android dependencies in Unity. - - # Call Android code from C# {#call-android-from-c-sharp} It's great that we're able to manage those dependencies, but they don't mean much if you're not able to utilize the code from them! -For example, take the following library: https://github.com/jaredrummler/AndroidDeviceNames +For example, take the following library: That library allows you to grab metadata about a user's device. This might be useful for analytics or bug reporters you may be developing yourself. Let's see how we're able to integrate this Java library in our C# code when building for the Android platform. @@ -162,11 +157,11 @@ withInstance.request(handleOnFinished); You can see that we have a few steps here: -1) Make a new `Callback` instance - - Provide an implementation of `onFinished` for said instance -2) Call `DeviceName.with` to create a request we can use later - - This means that we have to gain access to the currently running context to gain device access. When calling the code from Unity, it means we have to get access to the `UnityPlayer` context that Unity engine runs on -3) Call that request's `request` method with the `Callback` instance +1. Make a new `Callback` instance + - Provide an implementation of `onFinished` for said instance +2. Call `DeviceName.with` to create a request we can use later + - This means that we have to gain access to the currently running context to gain device access. When calling the code from Unity, it means we have to get access to the `UnityPlayer` context that Unity engine runs on +3. Call that request's `request` method with the `Callback` instance For each of these steps, we need to have a mapping from the Java code to C# code. Let's walk through these steps one-by-one diff --git a/content/blog/intro-to-web-accessability/index.md b/content/blog/intro-to-web-accessability/index.md index e2230a4b..31171759 100644 --- a/content/blog/intro-to-web-accessability/index.md +++ b/content/blog/intro-to-web-accessability/index.md @@ -58,7 +58,7 @@ Something to keep in mind is that these disabilities may not be permanent. For i > Microsoft originally created this chart as part of their [Inclusive Toolkit](https://download.microsoft.com/download/b/0/d/b0d4bf87-09ce-4417-8f28-d60703d672ed/inclusive_toolkit_manual_final.pdf) manual -Creating an application that's accessible means that you're making a better experience for *all* of your users. +Creating an application that's accessible means that you're making a better experience for _all_ of your users. By making your services accessible to more people, you are most importantly making them more equitable, but there is often a business case for accessibility. Opening your doors to more users may create an additional financial incentive, and many organizations have a legal requirement to meet accessibility guidelines. For instance, the U.S. Federal Government is subject to [Section 508](https://www.section508.gov/manage/laws-and-policies), which requires compliance with [Web Content Accessibility Guidelines (also known as WCAG, which we'll touch on later)](#wcag). Likewise, private US companies may be subject to compliance due to the "Americans with Disabilities Act" (shortened to "ADA"). The U.S. isn't the only country with these requirements, either. According to [WCAG's reference page for various legal laws](https://www.w3.org/WAI/policies/), there are at least 40 such laws in place around the world. @@ -76,7 +76,7 @@ There are different scales of accessibility as well. [WCAG includes three differ > - Level AA includes all Level A and AA requirements. Many organizations strive to meet Level AA. > - Level AAA includes all Level A, AA, and AAA requirements. -Meeting AA requirements is typically seen as a good commitment to accessibility, but AAA will open more doors to your users and is the gold standard for accessible user experience. +Meeting AA requirements is typically seen as a good commitment to accessibility, but AAA will open more doors to your users and is the gold standard for accessible user experience. Far from a comprehensive list, A requires: @@ -102,7 +102,7 @@ Interested in reading the full list? [Read the quick reference to WCAG 2.1](http # Smartly using Semantic HTML Tags {#html-semantic-tags} -One of the easiest things you can do for your application's accessibility is to use semantic HTML tags. +One of the easiest things you can do for your application's accessibility is to use semantic HTML tags. Let's say we have HTML to display fruits in a list: @@ -147,7 +147,7 @@ In our previous example, we used an HTML attribute [`aria-label`](https://develo A super small small subsection of `aria-` attributes includes: -- [`aria-labelledby`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-labelledby_attribute) — Associate the element with another element's text as the label +- [`aria-labelledby`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-labelledby_attribute) — Associate the element with another element's text as the label - `aria-expanded` — A Boolean value meant to communicate when a dropdown is expanded - `aria-valuemin` — The minimum allowed value in a numerical input - `aria-valuemax` — The maximum allowed value of a numerical input @@ -156,7 +156,7 @@ Additional to `aria` props, [the `role` property](https://developer.mozilla.org/ # Classy CSS {#css} -While HTML relays a significant amount of information to assistive technologies like screen readers, it's not the only thing used to inform those tools. Certain CSS rules can change the functionality as well. After all, screen readers (and other tools) don't look through the source code of a website. Instead, they're looking at [the accessibility tree](https://developers.google.com/web/fundamentals/accessibility/semantics-builtin/the-accessibility-tree): a modified version of the DOM. The accessibility tree and the DOM are both constructed by the browser from the website's source code. +While HTML relays a significant amount of information to assistive technologies like screen readers, it's not the only thing used to inform those tools. Certain CSS rules can change the functionality as well. After all, screen readers (and other tools) don't look through the source code of a website. Instead, they're looking at [the accessibility tree](https://developers.google.com/web/fundamentals/accessibility/semantics-builtin/the-accessibility-tree): a modified version of the DOM. The accessibility tree and the DOM are both constructed by the browser from the website's source code. > Want to learn more about the DOM, how the browser constructs it, and what it's used for internally? [This article helps explain this in detail](https://unicorn-utterances.com/posts/understanding-the-dom/). @@ -178,7 +178,7 @@ For this reason, there's a frequently used CSS class used to hide elements visua } ``` - There are many ways which CSS can influence assistive technologies. [Ben Myers covers this more in his blog post](https://benmyers.dev/blog/css-can-influence-screenreaders/). +There are many ways which CSS can influence assistive technologies. [Ben Myers covers this more in his blog post](https://benmyers.dev/blog/css-can-influence-screenreaders/). # Contrast is Cool {#contrast} @@ -188,7 +188,7 @@ While there are various reasons a user might not be able to see weakly contraste Dark gray text on a black background -Now, compare that to highly contrasting colors: +Now, compare that to highly contrasting colors: White text on a black background @@ -221,7 +221,7 @@ Many phones using iOS and Android allow users to change the font size on their m -Not only do you have these settings on mobile devices, but they're available on desktop as well. +Not only do you have these settings on mobile devices, but they're available on desktop as well. Using Chrome, go to [your settings page](chrome://settings/?search=font+size), and you should be able to set your font size. @@ -231,22 +231,21 @@ You can do the same in Firefox in [your preferences](about:preferences#general). ![Font settings in Firefox](./firefox_font_size.png) - ## Implementation {#font-rem} While browsers have the ability to set the font size, if you're using `px`, `vw`, `vh`, or other unit values for your fonts, the browser will not update these font sizes for you. In order to have your application rescale the font size to match the browser settings, you'll need to use the `rem` unit. You can think of `rem` as a multiplier to apply to the default font size. When the browser's font size is set to `16px`: -- `1rem` will be `16px` (1 * 16px) -- `1.5rem` will be `24px` (1.5 * 16px) -- `3rem` will be `48px` (3 * 16px) +- `1rem` will be `16px` (1 \* 16px) +- `1.5rem` will be `24px` (1.5 \* 16px) +- `3rem` will be `48px` (3 \* 16px) Likewise, when the browser's font size is set to `20px`: -- `1rem` will be `20px` (1 * 20px) -- `1.5rem` will be `30px` (1.5 * 20px) -- `3rem` will be `60px` (3 * 20px) +- `1rem` will be `20px` (1 \* 20px) +- `1.5rem` will be `30px` (1.5 \* 20px) +- `3rem` will be `60px` (3 \* 20px) > Something to keep in mind is that `rem` is a _relative_ font size. It's relative to the root element's font size. _This means that you cannot set a default `px` value font size in CSS to the `` tag or to the `:root` selector, as it will disable font scaling, even if the rest of your page is using `rem` values._ @@ -302,7 +301,7 @@ If anyone is ever advertising to you that your inaccessible project can be made ## Assistance is Amicable {#eslint} -While full automation will never be possible for improving a project's accessibility, not everyone proposing assistance in the process is trying to sell snake oil. +While full automation will never be possible for improving a project's accessibility, not everyone proposing assistance in the process is trying to sell snake oil. For example, [Deque's open-source Axe project](https://github.com/dequelabs/axe-core) can help identify issues such as common HTML semantic errors, contrast problems, and more. There are even libraries that help integrate Axe into your project's linters, such as one for React called [`eslint-plugin-jsx-a11y`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y). @@ -322,7 +321,7 @@ As mentioned in [a previous section](#no-automation), the process to make your a While there is plenty you can do to make existing functionality accessibility friendly, it's often forgotten that a strongly accessible app may opt to add specific functionality for its users with disabilities. -Some great examples of things like this are sites with lots of user-generated content. For example, Twitter allows its users to [add alternative (alt) text to their uploaded images and GIFs](https://help.twitter.com/en/using-twitter/picture-descriptions). Likewise, YouTube has the ability to [add subtitles and captions](https://support.google.com/youtube/answer/2734796?hl=en) to uploaded videos on their platform. +Some great examples of things like this are sites with lots of user-generated content. For example, Twitter allows its users to [add alternative (alt) text to their uploaded images and GIFs](https://help.twitter.com/en/using-twitter/picture-descriptions). Likewise, YouTube has the ability to [add subtitles and captions](https://support.google.com/youtube/answer/2734796?hl=en) to uploaded videos on their platform. Oftentimes, you'll find that these features benefit everyone, not just assistive technology users. You may want to watch a video in a crowded area; with closed captions, that's a much easier sell than trying to hear over others and interrupting everyone around you. @@ -382,4 +381,4 @@ We hope you've enjoyed learning from our accolade-worthy alliterative headlines. There are so many things that we wanted to include in this article but couldn't. Like most parts of engineering, the field of accessible design and the nuances within can be incredibly complex in fringe scenarios. Getting accessibility in a great place for your users takes active effort - just like any other part of building your app. Because of this, we encourage you to do [further research](#further-reading) on the topic. Don't be afraid to ask questions of community members, either! Many in the community are incredibly helpful and friendly. -Speaking of community, we'd love to hear your thoughts on this article. Did you learn something from it? Have questions about something accessibility-related? Think we missed something? [Join our Slack community](https://bit.ly/coderpad-slack) and chat with us or [send us a Tweet](https://twitter.com/coderpad)! +Speaking of community, we'd love to hear your thoughts on this article. Did you learn something from it? Have questions about something accessibility-related? Think we missed something? [Join our Slack community](https://bit.ly/coderpad-slack) and chat with us or [send us a Tweet](https://twitter.com/coderpad)! diff --git a/content/blog/intro-to-web-components-vanilla-js/index.md b/content/blog/intro-to-web-components-vanilla-js/index.md index 26e2f568..107db3af 100644 --- a/content/blog/intro-to-web-components-vanilla-js/index.md +++ b/content/blog/intro-to-web-components-vanilla-js/index.md @@ -35,7 +35,7 @@ While the Shadow DOM and HTML templates are undoubtedly useful in applications, ## What are Custom Elements? -At their core, custom elements essentially allow you to create new HTML tags. These tags are then used to implement custom UI and logic that can be used throughout your application. +At their core, custom elements essentially allow you to create new HTML tags. These tags are then used to implement custom UI and logic that can be used throughout your application. ``` @@ -52,7 +52,7 @@ While we tend to think of HTML tags as directly mapping to a single DOM element, ![Chrome DevTools showing the page header element expand into multiple tags](./chrome.png) -Because of this, we’re able to improve an app’s organization by reducing the amount of tags visible in a single file to read with better flow. +Because of this, we’re able to improve an app’s organization by reducing the amount of tags visible in a single file to read with better flow. But custom elements aren’t just made up of HTML - you’re able to associate JavaScript logic with these tags as well! This enables you to keep your logic alongside it’s associated UI. Say your header is a dropdown that’s powered by JavaScript. Now you can keep that JavaScript inside of your “page-header” component, keeping your logic consolidated. @@ -62,16 +62,15 @@ Finally, a significant improvement that components provide is composability. You While many implementations of components have differences, one concept that is fairly universal is “lifecycle methods”. At their core, lifecycle methods enable you to run code when events occur on an element. Even frameworks like React, which haved moved away from classes, still have similar concepts of doing actions when a component is changed in some way. - Let’s take a look at some of the lifecycle methods that are baked into the browser’s implementation. Custom elements have 4 lifecycle methods that can be attached to a component. -| connectedCallback | Ran when attached to the DOM | -| ------------------------ | ------------------------------------------------------------ | -| disconnectedCallback | Ran when unattached to the DOM | +| connectedCallback | Ran when attached to the DOM | +| ------------------------ | -------------------------------------------------------------------------------- | +| disconnectedCallback | Ran when unattached to the DOM | | attributeChangedCallback | Ran when one of the web component’s attributes is changed. Must explicitly track | -| adoptedCallback | Ran when moved from one HTML document to another | +| adoptedCallback | Ran when moved from one HTML document to another | > While each of them has their uses, we’ll primarily be focusing on the first 3. `adoptedCallback` is primarily useful in niche circumstances and is therefore difficult to make a straightforward demo of. @@ -158,7 +157,6 @@ Because this JavaScript object is simple and only utilizes [primitive data types ### Serializing Limitations - While simple objects and arrays can be serialized relatively trivially, there are limitations. For example, take the following code: ```javascript @@ -175,8 +173,7 @@ If we wanted to send this object to a server from a client remotely with the met `window`, while available in the browser, is not available in NodeJS, which the server may likely be written in. Should we attempt to serialize the `window` object and pass it along with the method? What about methods on the `window` object? Should we do the same with those methods? -On the other end of the scale, while `console.log` ***is\*** implemented in both NodeJS and browsers alike, it’s implemented using native code in both runtimes. How would we even begin to serialize native methods, even if we wanted to? *Maybe* we could pass machine code? Even ignoring the security concerns, how would we handle the differences in machine code between a user’s ARM device and a server’s x86_64 architecture? - +On the other end of the scale, while `console.log` \***is\*** implemented in both NodeJS and browsers alike, it’s implemented using native code in both runtimes. How would we even begin to serialize native methods, even if we wanted to? _Maybe_ we could pass machine code? Even ignoring the security concerns, how would we handle the differences in machine code between a user’s ARM device and a server’s x86\_64 architecture? All of this becomes a problem before you even consider that your server may well not be running NodeJS. How would you even begin to represent the concept of `this` in a language like Java? How would you handle the differences between a dynamically typed language like JavaScript and C++? @@ -198,7 +195,6 @@ It simply omits the key from the JSON string. This is important to keep in mind ### HTML Attribute Strings - Why are we talking about serialization in this article? To answer that, I want to mention two truths about HTML elements. - HTML attributes are case insensitive @@ -210,14 +206,12 @@ The first of these truths is simply that for any attribute, you can change the k ``` - And: ```html ``` - The second truth is much more relevant to us in this discussion. While it might seem like you can assign non-string values to an attribute, they’re always parsed as strings under-the-hood. You might think about being tricky and using JavaScript to assign non-string values to an attribute: @@ -282,7 +276,7 @@ While this tends to be the extent of HTML element’s deserializing of attribute As we touched on shortly, if we simply try to pass an array to an attribute using JavaScript’s `setAttribute`, it will not include the brackets. This is due to `Array.toString()`’s output. -If we attempted to pass the array ``["test", "another", "hello"]`` from JS to an attribute, the output would look like this: +If we attempted to pass the array `["test", "another", "hello"]` from JS to an attribute, the output would look like this: ```javascript - -``` - -Here, we’re writing our own `clear` logic, handling dynamic value updates, and more. - -The obvious problem is that we’d then have to copy and paste most of this logic in many components in our app. But let’s say that we were dedicated to this choice, and broke it out into a class that we could then extend. - -Heck, let’s even add in some getters and setters to make managing state easier: - -```html + +``` + +Here, we’re writing our own `clear` logic, handling dynamic value updates, and more. + +The obvious problem is that we’d then have to copy and paste most of this logic in many components in our app. But let’s say that we were dedicated to this choice, and broke it out into a class that we could then extend. + +Heck, let’s even add in some getters and setters to make managing state easier: + +```html - -``` - -Now our usage should look fairly simple! - -```html + +``` + +Now our usage should look fairly simple! + +```html - -``` - -That’s only 13 lines to declare a UI component! - -Only now you have a bug with namespace collision of state with underscores, your `doRender` doesn’t handle async functions, and you still have many of the downsides listed below! - -You could work on fixing these, but ultimately, you’ve created a basis of what Lit looks like today, but now you’re starting at square one. No ecosystem on your side, no upstream maintainers to lean on. - -# Pros and Cons of Lit Framework - -With the downsides (and upsides) of vanilla web components in mind, let’s compare the pros and cons of what building components using Lit looks like: - -
Pros Cons
  • Faster re-renders* that are automatically handled
  • More consolidated UI/logic
  • More advanced tools after mastery
  • Smaller footprint than other frameworks
  • Framework knowledge required
  • Future breaking changes
  • Not as widely known/used as other frameworks (Vue, React, Angular)

- -While there is some overlap between this list of pros and cons and the one for avoiding Lit in favor of home-growing, there’s a few other items here. - -Namely, this table highlights the fact that Lit isn’t the only framework for building web components. There’s huge alternatives like React, Vue, and Angular. These ecosystems have wider adoption and knowledge than Lit, which may make training a team to use Lit more difficult. - -However, Lit has a key advantage over them, ignoring being able to output to web components for a moment - we’ll come back to that. - - -Even compared to other frameworks, Lit is uniquely lightweight. - -Compare the bundle sizes of Vue - a lightweight framework in it’s own right - compared to Lit. - -![Lit weighs in at 16.3 kilobytes while Vue weighs in at 91.9 kilobytes](./bundlephobia.png) - -While tree shaking will drastically reduce the bundle size of Vue for smaller applications, Lit will still likely win out for a simple component system. - -# Other Frameworks - -Lit framework isn’t alone in being able to output to web components, however. In recent years, other frameworks have explored and implemented various methods of writing code for a framework that outputs to web components. - - -For example, the following frameworks have official support for creating web components without changing implementation code: - -- [Vue](https://v3.vuejs.org/guide/web-components.html#definecustomelement) -- [Angular](https://angular.io/guide/elements) -- [Preact](https://github.com/preactjs/preact-custom-element) - -Vue 3, in particular, has made massive strides in improving the web component development experience for their users. - -What’s more is that these tools tend to have significantly larger ecosystems. Take Vue for example. - -Want the ability to change pages easily? [Vue Router](https://router.vuejs.org/) - + +``` + +That’s only 13 lines to declare a UI component! + +Only now you have a bug with namespace collision of state with underscores, your `doRender` doesn’t handle async functions, and you still have many of the downsides listed below! + +You could work on fixing these, but ultimately, you’ve created a basis of what Lit looks like today, but now you’re starting at square one. No ecosystem on your side, no upstream maintainers to lean on. + +# Pros and Cons of Lit Framework + +With the downsides (and upsides) of vanilla web components in mind, let’s compare the pros and cons of what building components using Lit looks like: + +
Pros Cons
  • Faster re-renders* that are automatically handled
  • More consolidated UI/logic
  • More advanced tools after mastery
  • Smaller footprint than other frameworks
  • Framework knowledge required
  • Future breaking changes
  • Not as widely known/used as other frameworks (Vue, React, Angular)

+ +While there is some overlap between this list of pros and cons and the one for avoiding Lit in favor of home-growing, there’s a few other items here. + +Namely, this table highlights the fact that Lit isn’t the only framework for building web components. There’s huge alternatives like React, Vue, and Angular. These ecosystems have wider adoption and knowledge than Lit, which may make training a team to use Lit more difficult. + +However, Lit has a key advantage over them, ignoring being able to output to web components for a moment - we’ll come back to that. + +Even compared to other frameworks, Lit is uniquely lightweight. + +Compare the bundle sizes of Vue - a lightweight framework in it’s own right - compared to Lit. + +![Lit weighs in at 16.3 kilobytes while Vue weighs in at 91.9 kilobytes](./bundlephobia.png) + +While tree shaking will drastically reduce the bundle size of Vue for smaller applications, Lit will still likely win out for a simple component system. + +# Other Frameworks + +Lit framework isn’t alone in being able to output to web components, however. In recent years, other frameworks have explored and implemented various methods of writing code for a framework that outputs to web components. + +For example, the following frameworks have official support for creating web components without changing implementation code: + +- [Vue](https://v3.vuejs.org/guide/web-components.html#definecustomelement) +- [Angular](https://angular.io/guide/elements) +- [Preact](https://github.com/preactjs/preact-custom-element) + +Vue 3, in particular, has made massive strides in improving the web component development experience for their users. + +What’s more is that these tools tend to have significantly larger ecosystems. Take Vue for example. + +Want the ability to change pages easily? [Vue Router](https://router.vuejs.org/) + Want a global store solution? [Vuex -](https://vuex.vuejs.org/)Prefer similar class based components? [Vue Class Component Library](https://class-component.vuejs.org/) - -Prebuilt UI components? [Ant Design](https://www.antdv.com/docs/vue/introduce/) - -While some ecosystem tools might exist in Lit, they certainly don’t have the same breadth. - -That’s not to say it’s all good in the general web component ecosystem. Some frameworks, like React, [have issues with Web Component interop](https://custom-elements-everywhere.com/), that may impact your ability to merge those tools together. - -# Why Web Components? - -You may be asking - if you’re going to use a framework like Vue or React anyway, why even bother with web components? Couldn’t you instead write an app in one of those frameworks, without utilizing web components? - -You absolutely can, and to be honest - this is how most apps that use these frameworks are built. - -But web components play a special role in companies that have multiple different projects: Consolidation. - -Let’s say that you work for BigCorp - the biggest corporation in Corpville. - -BigCorp has dozens and dozens of full-scale applications, and not all of them are using the same frontend framework. This might sound irresponsible of BigCorp’s system architects, but in reality, sometimes a framework is better geared towards specific applications. Additionally, maybe some of the apps were part of an acquisition or merger that brought them into the company. - -After all, the user doesn’t care (or often, know) about what framework a tool is built with. You know what a user does care about? The fact that each app in a collection all have vastly different UIs and buttons. - -![Two different apps, each with different text cutoff points in their button's text](./two_apps.png) - -While this is clearly a bug, if both codebases implement the buttons on their own, you’ll inevitably end up with these types of problems; this being on top of the work-hours your teams have to spend redoing one-another’s work for their respective frameworks. - -And that’s all ignoring how difficult it can be to get designers to have consistency between different project’s design components - like buttons. - -Web Components solve this problem. - -If you build a shared component system that exports web components, you can then use the same codebase across multiple frameworks. - -Once the code is written and exported into web components, it’s trivial to utilize these new web components in your application. Like, it can be a [single line of code trivial.](https://v3.vuejs.org/guide/web-components.html#tips-for-a-vue-custom-elements-library) - -From this point, you’re able to make sure the logic and styling of these components are made consistent between applications - even if different frameworks. - -# Conclusion - -While web components have had a long time in the oven, they came out swinging! And while Lit isn’t the only one at the table, they’ve certainly found a strong foothold in capabilities. - -Lit’s lightweightness, paired with web component’s abilities to integrate between multiple frameworks is an incredible one-two punch that makes it a strong candidate for any shared component system. - -What’s more, the ability to transfer knowledge from other frameworks makes it an easy tool to place in your toolbox for usage either now or in the future. - -Regardless; whether you’re using Vue, React, Angular, Lit, Vanilla Web Components, or anything else, we wish you happy engineering! +](https://vuex.vuejs.org/)Prefer similar class based components? [Vue Class Component Library](https://class-component.vuejs.org/) + +Prebuilt UI components? [Ant Design](https://www.antdv.com/docs/vue/introduce/) + +While some ecosystem tools might exist in Lit, they certainly don’t have the same breadth. + +That’s not to say it’s all good in the general web component ecosystem. Some frameworks, like React, [have issues with Web Component interop](https://custom-elements-everywhere.com/), that may impact your ability to merge those tools together. + +# Why Web Components? + +You may be asking - if you’re going to use a framework like Vue or React anyway, why even bother with web components? Couldn’t you instead write an app in one of those frameworks, without utilizing web components? + +You absolutely can, and to be honest - this is how most apps that use these frameworks are built. + +But web components play a special role in companies that have multiple different projects: Consolidation. + +Let’s say that you work for BigCorp - the biggest corporation in Corpville. + +BigCorp has dozens and dozens of full-scale applications, and not all of them are using the same frontend framework. This might sound irresponsible of BigCorp’s system architects, but in reality, sometimes a framework is better geared towards specific applications. Additionally, maybe some of the apps were part of an acquisition or merger that brought them into the company. + +After all, the user doesn’t care (or often, know) about what framework a tool is built with. You know what a user does care about? The fact that each app in a collection all have vastly different UIs and buttons. + +![Two different apps, each with different text cutoff points in their button's text](./two_apps.png) + +While this is clearly a bug, if both codebases implement the buttons on their own, you’ll inevitably end up with these types of problems; this being on top of the work-hours your teams have to spend redoing one-another’s work for their respective frameworks. + +And that’s all ignoring how difficult it can be to get designers to have consistency between different project’s design components - like buttons. + +Web Components solve this problem. + +If you build a shared component system that exports web components, you can then use the same codebase across multiple frameworks. + +Once the code is written and exported into web components, it’s trivial to utilize these new web components in your application. Like, it can be a [single line of code trivial.](https://v3.vuejs.org/guide/web-components.html#tips-for-a-vue-custom-elements-library) + +From this point, you’re able to make sure the logic and styling of these components are made consistent between applications - even if different frameworks. + +# Conclusion + +While web components have had a long time in the oven, they came out swinging! And while Lit isn’t the only one at the table, they’ve certainly found a strong foothold in capabilities. + +Lit’s lightweightness, paired with web component’s abilities to integrate between multiple frameworks is an incredible one-two punch that makes it a strong candidate for any shared component system. + +What’s more, the ability to transfer knowledge from other frameworks makes it an easy tool to place in your toolbox for usage either now or in the future. + +Regardless; whether you’re using Vue, React, Angular, Lit, Vanilla Web Components, or anything else, we wish you happy engineering! diff --git a/content/blog/web-components-101-history/index.md b/content/blog/web-components-101-history/index.md index 8b4b5c0e..431c5174 100644 --- a/content/blog/web-components-101-history/index.md +++ b/content/blog/web-components-101-history/index.md @@ -1,4 +1,4 @@ ---- +--- { title: "Web Components 101: History", description: "Web components have had a long history to get where they are today. Let's look back to see where they came from & their immense growth!", @@ -10,26 +10,26 @@ originalLink: 'https://coderpad.io/blog/web-components-101-history/', series: "Web Components 101", order: 1 -} ---- - -Web components enjoy large-scale usage today. From YouTube to GitHub and many other major organizations, it’s safe to say they’ve made their way into commonplace frontend development practices. - -That wasn’t always the case. After all, web components had to start somewhere. And web development can be particularly picky with what succeeds and what doesn’t. - -So then, how did web components succeed? What was their path to broad adoption? And what are the origins behind the APIs used for modern web components? - -Let’s walk through a short history of web components and the related ecosystem to answer these questions. - -# 2010: The Early Days of MVC in JS - -While the concept of [“Model View Controller”, also commonly called MVC](https://en.wikipedia.org/wiki/Model–view–controller), has been around for some time, in JavaScript itself it failed to take hold early on. - -However, in 2010, there was an explosion around MVC and it’s related cousin: Model View View-Controller (MVVC) ). This explosion came courtesy of a slew of new frameworks that launched only a few months apart from one-another. - -[Knockout was one of the first to introduce strict MVC patterns inside of JavaScript in July 2010](https://github.com/knockout/knockout/releases/tag/v1.0.0). Knockout supported observable-based UI binding. Here, you could declare a Model, and bind data from said model directly to your HTML. - -```html +} +--- + +Web components enjoy large-scale usage today. From YouTube to GitHub and many other major organizations, it’s safe to say they’ve made their way into commonplace frontend development practices. + +That wasn’t always the case. After all, web components had to start somewhere. And web development can be particularly picky with what succeeds and what doesn’t. + +So then, how did web components succeed? What was their path to broad adoption? And what are the origins behind the APIs used for modern web components? + +Let’s walk through a short history of web components and the related ecosystem to answer these questions. + +# 2010: The Early Days of MVC in JS + +While the concept of [“Model View Controller”, also commonly called MVC](https://en.wikipedia.org/wiki/Model–view–controller), has been around for some time, in JavaScript itself it failed to take hold early on. + +However, in 2010, there was an explosion around MVC and it’s related cousin: Model View View-Controller (MVVC) ). This explosion came courtesy of a slew of new frameworks that launched only a few months apart from one-another. + +[Knockout was one of the first to introduce strict MVC patterns inside of JavaScript in July 2010](https://github.com/knockout/knockout/releases/tag/v1.0.0). Knockout supported observable-based UI binding. Here, you could declare a Model, and bind data from said model directly to your HTML. + +```html @@ -47,18 +47,18 @@ function WebmailViewModel() { }; ko.applyBindings(new WebmailViewModel()); - -``` - -![A list of emails based on their subjects](./knockout_demo.png) - -While this works great for UI binding, it lacks the componentization aspect we’ve come to expect from modern frameworks. - ------- - -This was improved in the ecosystem when [Backbone saw its first release in October 2010](https://github.com/jashkenas/backbone/releases/tag/0.1.0). It introduced a `[View](https://backbonejs.org/#View-extend)`, similar to what we might expect a component to be like today. - -```javascript + +``` + +![A list of emails based on their subjects](./knockout_demo.png) + +While this works great for UI binding, it lacks the componentization aspect we’ve come to expect from modern frameworks. + +--- + +This was improved in the ecosystem when [Backbone saw its first release in October 2010](https://github.com/jashkenas/backbone/releases/tag/0.1.0). It introduced a `[View](https://backbonejs.org/#View-extend)`, similar to what we might expect a component to be like today. + +```javascript var DocumentRow = Backbone.View.extend({ tagName: "li", className: "document-row", @@ -73,18 +73,18 @@ var DocumentRow = Backbone.View.extend({ render: function() { ... } -}); -``` - -Here, we can see that we can now bind events, classes, and more to a single tag. This aligns better with the types of components we’d see in, say, React or Lit. - ------- - -But that’s not all we saw in October that year. We also saw the [initial release of Angular.js](https://github.com/angular/angular.js/releases/tag/v0.9.0) only 10 days after Backbone’s release. - -Here, we can see that it introduced a concept of controllers into the document, similar to the `Model`s of Knockout. It allowed two-way bindings from UI to data and back. - -```html +}); +``` + +Here, we can see that we can now bind events, classes, and more to a single tag. This aligns better with the types of components we’d see in, say, React or Lit. + +--- + +But that’s not all we saw in October that year. We also saw the [initial release of Angular.js](https://github.com/angular/angular.js/releases/tag/v0.9.0) only 10 days after Backbone’s release. + +Here, we can see that it introduced a concept of controllers into the document, similar to the `Model`s of Knockout. It allowed two-way bindings from UI to data and back. + +```html
  • {{todo.text}}
  • @@ -112,24 +112,24 @@ Here, we can see that it introduced a concept of controllers into the document, todoList.todoText = ""; }; }); - -``` - -While Angular was the last of the three mentioned here, it had a huge impact. It was the first time Google released a JavaScript-based MVC based library into the wild. - -Not only did they build the library, [they used it to build Google’s Feedback tool](https://www.youtube.com/watch?v=r1A1VR0ibIQ) - which powers almost all of Google’s products today. This represented a shift from their prior Java-based “[Google Web Toolkit” (GWT)](http://www.gwtproject.org/) that was widely used before. - -Later, with the [acquisition of DoubleClick](https://www.nytimes.com/2007/04/14/technology/14DoubleClick.html), the team that was working on the [migration of the DoubleClick platform for Google decided to use Angular.js as well](https://www.youtube.com/watch?v=r1A1VR0ibIQ). - -# 2011: A Glimmer in W3C Standard’s Eye - -With Angular.js continuing to grow within Google, it’s no surprise that they continued researching in-JavaScript HTML bindings. - -On this topic, Alex Russel - then a Senior Staff Engineer at Google, working on the web platform team - [gave a talk at the Fronteers conference](https://fronteers.nl/congres/2011/sessions/web-components-and-model-driven-views-alex-russell). - -In this talk, he introduces a host of libraries that allow building custom elements with experimental new APIs. - -```html + +``` + +While Angular was the last of the three mentioned here, it had a huge impact. It was the first time Google released a JavaScript-based MVC based library into the wild. + +Not only did they build the library, [they used it to build Google’s Feedback tool](https://www.youtube.com/watch?v=r1A1VR0ibIQ) - which powers almost all of Google’s products today. This represented a shift from their prior Java-based “[Google Web Toolkit” (GWT)](http://www.gwtproject.org/) that was widely used before. + +Later, with the [acquisition of DoubleClick](https://www.nytimes.com/2007/04/14/technology/14DoubleClick.html), the team that was working on the [migration of the DoubleClick platform for Google decided to use Angular.js as well](https://www.youtube.com/watch?v=r1A1VR0ibIQ). + +# 2011: A Glimmer in W3C Standard’s Eye + +With Angular.js continuing to grow within Google, it’s no surprise that they continued researching in-JavaScript HTML bindings. + +On this topic, Alex Russel - then a Senior Staff Engineer at Google, working on the web platform team - [gave a talk at the Fronteers conference](https://fronteers.nl/congres/2011/sessions/web-components-and-model-driven-views-alex-russell). + +In this talk, he introduces a host of libraries that allow building custom elements with experimental new APIs. + +```html -... -``` - -Here, he utilized the [TraceUR compiler](https://web.archive.org/web/20210311050620/https://github.com/google/traceur-compiler) (a precursor to Babel) to add classes (remember, [`class` wouldn’t land in JavaScript stable until ES6 in 2015](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)) to build a new “custom element”. - -This combined with their [new MDV library](https://web.archive.org/web/20110509081454/http://code.google.com/p/mdv) in order to create a similar development environment to what we have in browser APIs today. - -It’s important to note that at this stage, nothing was formalized inside of a specification - It was all experimental libraries acting as playgrounds for APIs. - -That would change soon after. - -# 2013: Things Start Heating Up - -In early 2013 the Google team created a [Working Draft of a specification for Custom Elements](https://web.archive.org/web/20130608123733/http://www.w3.org/TR/custom-elements/). Alongside similar working drafts for Shadow DOM APIs, they were colloquially called “[Custom Elements v0](https://www.html5rocks.com/en/tutorials/webcomponents/customelements/)”. - -With [Google Chrome’s release in 2008](https://googleblog.blogspot.com/2008/09/fresh-take-on-browser.html), they had the ability to quickly implement these non-standard APIs into Chrome in order to allow application developers to utilize them before specification stabilization. - - -One such example of this was [Polymer, which was a component library based on v0 APIs to provide two-way UI binding using MVC.](https://web.archive.org/web/20130515211406/http://www.polymer-project.org/) It’s initial alpha release was announced in early 2013, alongside the specifications. - -At [Google Dev Summit 2013, they walked through its capabilities ](https://www.youtube.com/watch?v=DH1vTVkqCDQ)and how it was able to run in other browsers by utilizing polyfills. - ------- - -Facebook, not one to be outdone on the technical engineering front, [introduced React into public in 2013](https://www.youtube.com/watch?v=GW0rj4sNH2w) - -While Polymer went deeper into the MVC route, [React relied more heavily on unidirectionality](https://coderpad.io/blog/master-react-unidirectional-data-flow/) in order to avoid state mutations. - -# 2016 & 2017: Formative Years - -While only the year prior, Polymer 1.0 was released with the usage of v0 custom element spec, [2016 saw the release of the custom element v1 specification](https://web.archive.org/web/20161030051600/http://w3c.github.io/webcomponents/spec/custom/). - - -This new version of the specification was not backwards compatible, and as a result required a shift to the new version of the specification in order to function properly. Polyfills were continued to be used as a stop-gate for browsers that didn’t have a v0 implementation. - -While [v1 was already implemented into Chrome in late 2016](https://web.archive.org/web/20161101052413/http://caniuse.com/#feat=custom-elementsv1), it wasn’t until 2017 with the release of Polymer 2.0 that it would be adopted back into the library that helped draft the specification. - -Because of this, while [YouTube’s new Polymer rewrite](https://blog.youtube/news-and-events/a-sneak-peek-at-youtubes-new-look-and/) theoretically was a huge step towards the usage of web components, it posed a problem. Browsers like [Firefox without a v0 implementation were forced to continue to use Polyfills](https://web.archive.org/web/20180724154806/https://twitter.com/cpeterso/status/1021626510296285185), which are slower than native implementations. - -# 2018 and Beyond: Maturity - -2018 is where Web Components really found their foothold. - -For a start, [Mozilla implemented the v1 specification APIs into their stable release of Firefox](https://www.mozilla.org/en-US/firefox/63.0/releasenotes/), complete with dedicated devtools. Finally, developers could use all of the web components’ APIs in their app, cross-browser, and without any concern for non-Chrome performance. - -On top of that, React’s unidirectionality seemed to have won over the Polymer team. The Polymer team announced that it would [migrate away from bidirectional binding and towards a one-way bound `LitElement`](https://www.polymer-project.org/blog/2018-05-02-roadmap-update#libraries) - -That `LitElement` would then turn into a dedicated framework called “[Lit](https://coderpad.io/blog/web-components-101-lit-framework/)”, developed to replace Polymer as its successor, that would hit [v1 in 2019](https://github.com/lit/lit/releases/tag/v1.0.0) and [v2 in 2021](https://github.com/lit/lit/releases/tag/lit%402.0.0). - -# Timeline - -Whew! That’s a lot to take in. Let’s see it all from a thousand foot view: - -- 2010: - - [Knockout.js released](https://github.com/knockout/knockout/releases/tag/v1.0.0) - - [Backbone.js alpha released](https://github.com/jashkenas/backbone/releases/tag/0.1.0) - - [Angular.js made open-source](https://web.archive.org/web/20100413141437/http://getangular.com/) - -- 2011: - - [MDV (Polymer predecessor) introduced at a conference](https://fronteers.nl/congres/2011/sessions/web-components-and-model-driven-views-alex-russell) - -- 2013: - - [Working draft spec for Web Components (v0) released](https://web.archive.org/web/20130608123733/http://www.w3.org/TR/custom-elements/) - - [Polymer (Google’s web component framework) announced](https://www.youtube.com/watch?v=DH1vTVkqCDQ) - - [React open-sourced](https://www.youtube.com/watch?v=GW0rj4sNH2w) - -- 2015: - - [Polymer 1.0 released](https://web.archive.org/web/20150814004009/https://www.polymer-project.org/1.0/) - -- 2016: - - [Custom elements v1 spec released](https://web.archive.org/web/20161030051600/http://w3c.github.io/webcomponents/spec/custom/) - - [YouTube rewritten in Polymer](https://blog.youtube/news-and-events/a-sneak-peek-at-youtubes-new-look-and/) -- 2017: - - [Polymer 2.0 released](https://github.com/Polymer/polymer/releases/tag/v2.0.0) - -- 2018: - - [Polymer announces start of migration to “LitElement”](https://www.polymer-project.org/blog/2018-05-02-roadmap-update#libraries) - - [Firefox enables web components (Polyfills no longer needed)](https://www.mozilla.org/en-US/firefox/63.0/releasenotes/) - -- 2019: - - [Lit framework 1.0 released](https://github.com/lit/lit/releases/tag/v1.0.0) - -- 2021 - - [Lit 2.0 released](https://github.com/lit/lit/releases/tag/lit%402.0.0) - -# Conclusion - -In the past 10 years we’ve seen massive changes to the web development ecosystem. No more is this more apparent than the development and continued growth of web components. - -Hopefully this should put any future learnings about web components and [framework comparisons](https://coderpad.io/blog/web-components-101-framework-comparison/) into perspective. - -We’ve waited a long time to see many of these ideas fully standardized into the web platform, and, now that they’re here, they’re helping accelerate growth of many platforms. - -Want to learn how to build them yourself? - -We have articles about how to build web components [without a framework](https://coderpad.io/blog/intro-to-web-components-vanilla-js/) as well as using [Google’s Lit framework](https://coderpad.io/blog/web-components-101-lit-framework/). +... +``` + +Here, he utilized the [TraceUR compiler](https://web.archive.org/web/20210311050620/https://github.com/google/traceur-compiler) (a precursor to Babel) to add classes (remember, [`class` wouldn’t land in JavaScript stable until ES6 in 2015](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)) to build a new “custom element”. + +This combined with their [new MDV library](https://web.archive.org/web/20110509081454/http://code.google.com/p/mdv) in order to create a similar development environment to what we have in browser APIs today. + +It’s important to note that at this stage, nothing was formalized inside of a specification - It was all experimental libraries acting as playgrounds for APIs. + +That would change soon after. + +# 2013: Things Start Heating Up + +In early 2013 the Google team created a [Working Draft of a specification for Custom Elements](https://web.archive.org/web/20130608123733/http://www.w3.org/TR/custom-elements/). Alongside similar working drafts for Shadow DOM APIs, they were colloquially called “[Custom Elements v0](https://www.html5rocks.com/en/tutorials/webcomponents/customelements/)”. + +With [Google Chrome’s release in 2008](https://googleblog.blogspot.com/2008/09/fresh-take-on-browser.html), they had the ability to quickly implement these non-standard APIs into Chrome in order to allow application developers to utilize them before specification stabilization. + +One such example of this was [Polymer, which was a component library based on v0 APIs to provide two-way UI binding using MVC.](https://web.archive.org/web/20130515211406/http://www.polymer-project.org/) It’s initial alpha release was announced in early 2013, alongside the specifications. + +At [Google Dev Summit 2013, they walked through its capabilities ](https://www.youtube.com/watch?v=DH1vTVkqCDQ)and how it was able to run in other browsers by utilizing polyfills. + +--- + +Facebook, not one to be outdone on the technical engineering front, [introduced React into public in 2013](https://www.youtube.com/watch?v=GW0rj4sNH2w) + +While Polymer went deeper into the MVC route, [React relied more heavily on unidirectionality](https://coderpad.io/blog/master-react-unidirectional-data-flow/) in order to avoid state mutations. + +# 2016 & 2017: Formative Years + +While only the year prior, Polymer 1.0 was released with the usage of v0 custom element spec, [2016 saw the release of the custom element v1 specification](https://web.archive.org/web/20161030051600/http://w3c.github.io/webcomponents/spec/custom/). + +This new version of the specification was not backwards compatible, and as a result required a shift to the new version of the specification in order to function properly. Polyfills were continued to be used as a stop-gate for browsers that didn’t have a v0 implementation. + +While [v1 was already implemented into Chrome in late 2016](https://web.archive.org/web/20161101052413/http://caniuse.com/#feat=custom-elementsv1), it wasn’t until 2017 with the release of Polymer 2.0 that it would be adopted back into the library that helped draft the specification. + +Because of this, while [YouTube’s new Polymer rewrite](https://blog.youtube/news-and-events/a-sneak-peek-at-youtubes-new-look-and/) theoretically was a huge step towards the usage of web components, it posed a problem. Browsers like [Firefox without a v0 implementation were forced to continue to use Polyfills](https://web.archive.org/web/20180724154806/https://twitter.com/cpeterso/status/1021626510296285185), which are slower than native implementations. + +# 2018 and Beyond: Maturity + +2018 is where Web Components really found their foothold. + +For a start, [Mozilla implemented the v1 specification APIs into their stable release of Firefox](https://www.mozilla.org/en-US/firefox/63.0/releasenotes/), complete with dedicated devtools. Finally, developers could use all of the web components’ APIs in their app, cross-browser, and without any concern for non-Chrome performance. + +On top of that, React’s unidirectionality seemed to have won over the Polymer team. The Polymer team announced that it would [migrate away from bidirectional binding and towards a one-way bound `LitElement`](https://www.polymer-project.org/blog/2018-05-02-roadmap-update#libraries) + +That `LitElement` would then turn into a dedicated framework called “[Lit](https://coderpad.io/blog/web-components-101-lit-framework/)”, developed to replace Polymer as its successor, that would hit [v1 in 2019](https://github.com/lit/lit/releases/tag/v1.0.0) and [v2 in 2021](https://github.com/lit/lit/releases/tag/lit%402.0.0). + +# Timeline + +Whew! That’s a lot to take in. Let’s see it all from a thousand foot view: + +- 2010: + - [Knockout.js released](https://github.com/knockout/knockout/releases/tag/v1.0.0) + - [Backbone.js alpha released](https://github.com/jashkenas/backbone/releases/tag/0.1.0) + - [Angular.js made open-source](https://web.archive.org/web/20100413141437/http://getangular.com/) + +- 2011: + - [MDV (Polymer predecessor) introduced at a conference](https://fronteers.nl/congres/2011/sessions/web-components-and-model-driven-views-alex-russell) + +- 2013: + - [Working draft spec for Web Components (v0) released](https://web.archive.org/web/20130608123733/http://www.w3.org/TR/custom-elements/) + - [Polymer (Google’s web component framework) announced](https://www.youtube.com/watch?v=DH1vTVkqCDQ) + - [React open-sourced](https://www.youtube.com/watch?v=GW0rj4sNH2w) + +- 2015: + - [Polymer 1.0 released](https://web.archive.org/web/20150814004009/https://www.polymer-project.org/1.0/) + +- 2016: + - [Custom elements v1 spec released](https://web.archive.org/web/20161030051600/http://w3c.github.io/webcomponents/spec/custom/) + - [YouTube rewritten in Polymer](https://blog.youtube/news-and-events/a-sneak-peek-at-youtubes-new-look-and/) + +- 2017: + - [Polymer 2.0 released](https://github.com/Polymer/polymer/releases/tag/v2.0.0) + +- 2018: + - [Polymer announces start of migration to “LitElement”](https://www.polymer-project.org/blog/2018-05-02-roadmap-update#libraries) + - [Firefox enables web components (Polyfills no longer needed)](https://www.mozilla.org/en-US/firefox/63.0/releasenotes/) + +- 2019: + - [Lit framework 1.0 released](https://github.com/lit/lit/releases/tag/v1.0.0) + +- 2021 + - [Lit 2.0 released](https://github.com/lit/lit/releases/tag/lit%402.0.0) + +# Conclusion + +In the past 10 years we’ve seen massive changes to the web development ecosystem. No more is this more apparent than the development and continued growth of web components. + +Hopefully this should put any future learnings about web components and [framework comparisons](https://coderpad.io/blog/web-components-101-framework-comparison/) into perspective. + +We’ve waited a long time to see many of these ideas fully standardized into the web platform, and, now that they’re here, they’re helping accelerate growth of many platforms. + +Want to learn how to build them yourself? + +We have articles about how to build web components [without a framework](https://coderpad.io/blog/intro-to-web-components-vanilla-js/) as well as using [Google’s Lit framework](https://coderpad.io/blog/web-components-101-lit-framework/). diff --git a/content/blog/web-components-101-lit-framework/index.md b/content/blog/web-components-101-lit-framework/index.md index e54575c8..478e39a6 100644 --- a/content/blog/web-components-101-lit-framework/index.md +++ b/content/blog/web-components-101-lit-framework/index.md @@ -1,4 +1,4 @@ ---- +--- { title: "Web Components 101: Lit Framework", description: "Google pushed for web components, sure, but they didn't stop there. They also went on to make an amazing framework to help build them: Lit!", @@ -10,24 +10,24 @@ originalLink: 'https://coderpad.io/blog/web-components-101-lit-framework/', series: "Web Components 101", order: 3 -} ---- - -Recently we talked about [what web components are and how you can build a web app utilizing them with only vanilla JavaScript](https://coderpad.io/blog/intro-to-web-components-vanilla-js/). - -While web components are absolutely usable with only vanilla JavaScript, more complex usage, especially pertaining to value binding, can easily become unwieldy. - -One potential solution might be using a web component framework such as VueJS or React. However, web-standard components can still be a massive boon to development. - -As such, there’s a framework called [“Lit”](https://lit.dev/) that is developed specifically to leverage web components. With [Lit 2.0 recently launching as a stable release](https://lit.dev/blog/2021-09-21-announcing-lit-2/), we thought we’d take a look at how we can simplify web component development. - -# HTML - -One of the greatest strengths of custom elements is the ability to contain multiple other elements. This makes it so that you can have custom elements for every scale: from a button to an entire page. - -To do this in a vanilla JavaScript custom element, you can use `innerHTML` to create new child elements. - -```html +} +--- + +Recently we talked about [what web components are and how you can build a web app utilizing them with only vanilla JavaScript](https://coderpad.io/blog/intro-to-web-components-vanilla-js/). + +While web components are absolutely usable with only vanilla JavaScript, more complex usage, especially pertaining to value binding, can easily become unwieldy. + +One potential solution might be using a web component framework such as VueJS or React. However, web-standard components can still be a massive boon to development. + +As such, there’s a framework called [“Lit”](https://lit.dev/) that is developed specifically to leverage web components. With [Lit 2.0 recently launching as a stable release](https://lit.dev/blog/2021-09-21-announcing-lit-2/), we thought we’d take a look at how we can simplify web component development. + +# HTML + +One of the greatest strengths of custom elements is the ability to contain multiple other elements. This makes it so that you can have custom elements for every scale: from a button to an entire page. + +To do this in a vanilla JavaScript custom element, you can use `innerHTML` to create new child elements. + +```html - -``` - -This initial example looks fairly similar to what the Lit counterpart of that code looks like: - -```html + +``` + +This initial example looks fairly similar to what the Lit counterpart of that code looks like: + +```html - -``` - - - -There are two primary differences from the vanilla JavaScript example. First, we no longer need to use the `connectedCallback` to call `render`. The LitElement’s `render` function is called by Lit itself whenever needed - such as when data changes or for an initial render - avoiding the need to manually re-call the render method. - -That said, Lit components fully support the same lifecycle methods as a vanilla custom elements. - -The second, easier-to-miss change from the vanilla JavaScript component to the Lit implementation, is that when we set our HTML, we don’t simply use a basic template literal (`

    test

    `): we pass the function `html` to the template literal (`html\`

    test

    \``). - -This leverages [a somewhat infrequently used feature of template literals called tagged templates](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates). Tagged templates allow a template literal to be passed to a function. This function can then transform the output based on the string input and expected interpolated placeholders. - -Because tagged templates return a value like any other function, you can assign the return value of `html` to a variable. - -```javascript + +``` + + + +There are two primary differences from the vanilla JavaScript example. First, we no longer need to use the `connectedCallback` to call `render`. The LitElement’s `render` function is called by Lit itself whenever needed - such as when data changes or for an initial render - avoiding the need to manually re-call the render method. + +That said, Lit components fully support the same lifecycle methods as a vanilla custom elements. + +The second, easier-to-miss change from the vanilla JavaScript component to the Lit implementation, is that when we set our HTML, we don’t simply use a basic template literal (`

    test

    `): we pass the function `html` to the template literal (`html\`

    test

    \`\`). + +This leverages [a somewhat infrequently used feature of template literals called tagged templates](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates). Tagged templates allow a template literal to be passed to a function. This function can then transform the output based on the string input and expected interpolated placeholders. + +Because tagged templates return a value like any other function, you can assign the return value of `html` to a variable. + +```javascript render { const el = html`

    Hello!

    `; return el; -} -``` - -If you were to `console.log` this value, you’d notice that it’s not an [HTMLElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement). Instead, it’s a custom value that Lit utilizes to render to proper DOM nodes. - -# Event Binding - -“If the syntax is so similar, why would I add a framework to build custom elements?” - -Well, while the Vanilla JavaScript and Lit custom element code look similar for a small demo: The story changes dramatically when you look to scale up. - -For example, if you wanted to render a button and add a click event to the button with vanilla JavaScript, you’d have to abandon the `innerHTML` element assignment method. - -First, we’ll create an element using `document.createElement`, then add events, and finally utilize [an element method like `append`](https://developer.mozilla.org/en-US/docs/Web/API/Element/append) to add the node to the DOM. - -```html +} +``` + +If you were to `console.log` this value, you’d notice that it’s not an [HTMLElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement). Instead, it’s a custom value that Lit utilizes to render to proper DOM nodes. + +# Event Binding + +“If the syntax is so similar, why would I add a framework to build custom elements?” + +Well, while the Vanilla JavaScript and Lit custom element code look similar for a small demo: The story changes dramatically when you look to scale up. + +For example, if you wanted to render a button and add a click event to the button with vanilla JavaScript, you’d have to abandon the `innerHTML` element assignment method. + +First, we’ll create an element using `document.createElement`, then add events, and finally utilize [an element method like `append`](https://developer.mozilla.org/en-US/docs/Web/API/Element/append) to add the node to the DOM. + +```html - -``` - -While this works for the initial render, it doesn’t handle any of the edgecases that,at scale,can cause long-term damage to your app’s maintainability & performance. - -For example, future re-renders of the element will duplicate the button. To solve this, you must iterate through all of the element’s [`children`](https://developer.mozilla.org/en-US/docs/Web/API/Element/children) and [`remove`](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) them one-by-one. - -Further, once the element is removed from the DOM, the click listener is not implicitly removed in the background. Because of this, it’s never released from memory and is considered a memory leak. If this issue continued to occur during long-term usage of your app, it would likely bloat memory usage and eventually crash or hang. - -To solve this, you’d need to assign a variable for every `addEventListener` you had present. This may be simple for one or two events, but add too many and it can be difficult to keep track. - -And all of this ignores the maintenance standpoint: What does that code do at a glance? - -It doesn't look anything like HTML and as a result, requires you to consistently context shift between writing standard HTML in a string and using the DOM APIs to construct elements. - -Luckily, Lit doesn’t have these issues. Here’s the same button construction and rendering to a custom element using Lit instead of vanilla JavaScript: - -```html + +``` + +While this works for the initial render, it doesn’t handle any of the edgecases that,at scale,can cause long-term damage to your app’s maintainability & performance. + +For example, future re-renders of the element will duplicate the button. To solve this, you must iterate through all of the element’s [`children`](https://developer.mozilla.org/en-US/docs/Web/API/Element/children) and [`remove`](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) them one-by-one. + +Further, once the element is removed from the DOM, the click listener is not implicitly removed in the background. Because of this, it’s never released from memory and is considered a memory leak. If this issue continued to occur during long-term usage of your app, it would likely bloat memory usage and eventually crash or hang. + +To solve this, you’d need to assign a variable for every `addEventListener` you had present. This may be simple for one or two events, but add too many and it can be difficult to keep track. + +And all of this ignores the maintenance standpoint: What does that code do at a glance? + +It doesn't look anything like HTML and as a result, requires you to consistently context shift between writing standard HTML in a string and using the DOM APIs to construct elements. + +Luckily, Lit doesn’t have these issues. Here’s the same button construction and rendering to a custom element using Lit instead of vanilla JavaScript: + +```html - -``` - - - -Yup, that’s all. Lit allows you to bind elements by using the `@` sign and passing the function as a placeholder to the `html` tagged template. Not only does this look much HTML-like, it handles event cleanup, re-rendering, and more. - -# Attributes & Properties - -As we learned before, there are two ways to pass values between and into components: attributes and values. - -Previously, when we were using vanilla JavaScript, we had to define these separately. Moreover, we had to declare which attributes to dynamically listen to value changes of. - -```javascript + +``` + + + +Yup, that’s all. Lit allows you to bind elements by using the `@` sign and passing the function as a placeholder to the `html` tagged template. Not only does this look much HTML-like, it handles event cleanup, re-rendering, and more. + +# Attributes & Properties + +As we learned before, there are two ways to pass values between and into components: attributes and values. + +Previously, when we were using vanilla JavaScript, we had to define these separately. Moreover, we had to declare which attributes to dynamically listen to value changes of. + +```javascript class MyComponent extends HTMLElement { connectedCallback() { this.render(); @@ -187,12 +187,12 @@ class MyComponent extends HTMLElement { const message = this.attributes.message.value || 'Hello world'; this.innerHTML = `

    ${message}

    `; } -} -``` - -In Lit, we declare attributes and properties using a static getter and treat them as normal values in any of our functions. - -```javascript +} +``` + +In Lit, we declare attributes and properties using a static getter and treat them as normal values in any of our functions. + +```javascript import { html, LitElement } from "https://cdn.skypack.dev/lit"; export class HelloElement extends LitElement { @@ -214,20 +214,20 @@ export class HelloElement extends LitElement { } } -window.customElements.define('hello-component', HelloElement); -``` - -For starters, we no longer have to manually call “render” when a property’s value is changed. Lit will re-render when values are changed. - -That’s not all, though: Keen eyed readers will notice that we’re declaring a type associated with the `message` property. - -Unlike the [React ecosystem’s PropTypes](https://github.com/facebook/prop-types), the `type` subproperty doesn’t do runtime type validation. Instead, it acts as an automatic type converter. - -This can be of great help as the knowledge that attributes can only be strings can be difficult to remember while debugging. - -For example, we can tell Lit to convert an attribute to a Number and it will migrate from a string that looks like a number to an actual JavaScript type number. - -```html +window.customElements.define('hello-component', HelloElement); +``` + +For starters, we no longer have to manually call “render” when a property’s value is changed. Lit will re-render when values are changed. + +That’s not all, though: Keen eyed readers will notice that we’re declaring a type associated with the `message` property. + +Unlike the [React ecosystem’s PropTypes](https://github.com/facebook/prop-types), the `type` subproperty doesn’t do runtime type validation. Instead, it acts as an automatic type converter. + +This can be of great help as the knowledge that attributes can only be strings can be difficult to remember while debugging. + +For example, we can tell Lit to convert an attribute to a Number and it will migrate from a string that looks like a number to an actual JavaScript type number. + +```html - -``` - - - -This works because properties and attributes are both created at the same time with Lit. - -However, due to the period binding not being HTML standard, it comes with the side effect of having to use a Lit template in order to bind properties. This tends not to be a problem in applications - since many tend to use and compose components throughout their applications. - -# Array Rendering - -In our article about vanilla JavaScript web components, we built a simple todo list. Let’s take another look at that example, but this time using Lit for our component code. We’ll get started with a parent `FormElement`, which will manage the data and user input. - -```javascript + +``` + + + +This works because properties and attributes are both created at the same time with Lit. + +However, due to the period binding not being HTML standard, it comes with the side effect of having to use a Lit template in order to bind properties. This tends not to be a problem in applications - since many tend to use and compose components throughout their applications. + +# Array Rendering + +In our article about vanilla JavaScript web components, we built a simple todo list. Let’s take another look at that example, but this time using Lit for our component code. We’ll get started with a parent `FormElement`, which will manage the data and user input. + +```javascript class FormElement extends LitElement { static get properties() { return { @@ -488,14 +487,14 @@ class FormElement extends LitElement { `; } -} -``` - -Now that we have a form that contains an array, an important question arises: how do we iterate through an array in order to create individual elements for a list? - -Well, while [React has `Array.map](https://reactjs.org/docs/lists-and-keys.html)` and [Vue has `v-for`](https://v3.vuejs.org/guide/list.html#mapping-an-array-to-elements-with-v-for), Lit uses a `repeat` function. Here’s an example: - -```javascript +} +``` + +Now that we have a form that contains an array, an important question arises: how do we iterate through an array in order to create individual elements for a list? + +Well, while \[React has `Array.map](https://reactjs.org/docs/lists-and-keys.html)` and [Vue has `v-for`](https://v3.vuejs.org/guide/list.html#mapping-an-array-to-elements-with-v-for), Lit uses a `repeat` function. Here’s an example: + +```javascript class TodoElement extends LitElement { // ... @@ -511,22 +510,22 @@ class TodoElement extends LitElement {
`; } -} -``` - - - -# Passing Functions - -Before we step away from code to talk pros and cons about Lit itself (shh, spoilers!); let’s take a look at a code sample that demonstrates many of the benefits over vanilla JavaScript web components we’ve talked about today. - -Readers of the previous blog post will remember that when passing an array of objects to a web component, things looked pretty decent. - -It wasn’t until we tried binding event listeners to an array of objects that things got complex (and messy). Between needing to manually create elements using `document`, dealing with `querySelector` to pass properties, manually calling “render”, and needing to implement a custom “clear” method - it was a messy experience. - -Let’s see how Lit handles the job. - -```javascript +} +``` + + + +# Passing Functions + +Before we step away from code to talk pros and cons about Lit itself (shh, spoilers!); let’s take a look at a code sample that demonstrates many of the benefits over vanilla JavaScript web components we’ve talked about today. + +Readers of the previous blog post will remember that when passing an array of objects to a web component, things looked pretty decent. + +It wasn’t until we tried binding event listeners to an array of objects that things got complex (and messy). Between needing to manually create elements using `document`, dealing with `querySelector` to pass properties, manually calling “render”, and needing to implement a custom “clear” method - it was a messy experience. + +Let’s see how Lit handles the job. + +```javascript class TodoElement extends LitElement { // ... @@ -546,21 +545,21 @@ class TodoElement extends LitElement { `; } -} -``` - - - -You will notice that we’re using a `filter` within our `render` method. Because this logic is within the `render` method, it will run on every UI update. This is important to note in case you have expensive operations: you should avoid running those within the render method. - -Outside of this, however - that’s all there is! It reads just like HTML would (with the added benefit of cleanup and prop passing), handles dynamic data, and more! - -# Conclusion - -The ability to leverage Lit in an application makes maintaining and improving a project easier than rolling web components yourself. - -Lit demonstrates significant growth in web components from the early days of [Polymer](http://polymer-project.org/). This growth is in no small part due to the Lit team themselves, either! - -Before it was a fully fledged framework, the project started from the `lit-html` package, which was an offshoot of Polymer. The Polymer team was instrumental in standardizing the modern variant of web components. - -The ability to use Lit can strongly enhance web component development, but there are other options out there. Next time, we’ll talk about what the competitors are doing, what the pros and cons of each are, and how you can make the best choice for your applications. +} +``` + + + +You will notice that we’re using a `filter` within our `render` method. Because this logic is within the `render` method, it will run on every UI update. This is important to note in case you have expensive operations: you should avoid running those within the render method. + +Outside of this, however - that’s all there is! It reads just like HTML would (with the added benefit of cleanup and prop passing), handles dynamic data, and more! + +# Conclusion + +The ability to leverage Lit in an application makes maintaining and improving a project easier than rolling web components yourself. + +Lit demonstrates significant growth in web components from the early days of [Polymer](http://polymer-project.org/). This growth is in no small part due to the Lit team themselves, either! + +Before it was a fully fledged framework, the project started from the `lit-html` package, which was an offshoot of Polymer. The Polymer team was instrumental in standardizing the modern variant of web components. + +The ability to use Lit can strongly enhance web component development, but there are other options out there. Next time, we’ll talk about what the competitors are doing, what the pros and cons of each are, and how you can make the best choice for your applications. diff --git a/content/blog/what-do-files-extensions-do/index.md b/content/blog/what-do-files-extensions-do/index.md index 4f950d60..47ca1d61 100644 --- a/content/blog/what-do-files-extensions-do/index.md +++ b/content/blog/what-do-files-extensions-do/index.md @@ -1,4 +1,4 @@ ---- +--- { title: "What do file extensions do?", description: "A file extension isn't the only way a file is inditified, so what does it do?", @@ -8,33 +8,33 @@ tags: ["computer science"], attached: [], license: "cc-by-nc-sa-4" -} ---- - -> A filename extension or file type is an identifier specified as a suffix to the name of computer file. - [Wikipedia](https://en.wikipedia.org/wiki/Filename_extension) - -A long & terse explanation of a file extension exists but to boil it down into simpler terms the file extension is used by a computer to check against a registry of programs to see if a program is registered on the system that can open the file. While there are some differences based on how they are treated by the operating system you use, in most cases, they are used as a simple check to allow a system to see what program can open the file. - -# Viewing the File Extension - -When most people look at a file they probably don't see a file extension after the name. Often, by default, the file extension is hidden from the user. You can easily find articles that outline how to [turn file extensions on for macOS](https://support.apple.com/guide/mac-help/show-or-hide-filename-extensions-on-mac-mchlp2304/mac) or [how to turn it on for Windows](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/). Now when looking at the file its extension will be visible right after the name. - -![A preview of what it's like to have file extensions on and off in Windows 10](./file_extensions.png) - -As an example, most pictures you have will end in `.jpg`, `.png`, `.gif`, `.webp`, or `.avif`. A program will have a `.exe`, `.bash`, or `.bat`. A music file might have a `.mp3`, `.mp4`, `.flac`, or `.ogg`. A text file can be `.docx`, `.txt`, or `.odf`. Then there are spreadsheets, videos, hardware drivers, databases, and many other types of file extensions with more being made every day. - -Keep in mind, these file extensions are just part of the file name, they aren't part of your file's contents. If you were to remove or change the file extension and then add it back, nothing bad would happen to your file and it would act the same as it did before. - -# Opening the File - -Whenever you open a file, whether it's through a double click or open a file in an operating system from a menu the computer will go and see if there is a program registered to open that type of file extension. If it can find one registered to open the file, it takes the file and sends it to the program. If it can't find one then the computer will ask you to choose one of the programs on your computer that are registered to be associated with the file type to be used to open those types of files from now on. Of course, you could also tell your computer to change the program used to open the file menu and telling it to "open with" for a different program or by editing the file association table manually to register the program for the future. Then the program starts up then it opens the file and then the program can show the file in the way it is supposed to. - -# What happens if you open a file with another program - -> This is a serious warning about the following information: You can make your files unrecoverable if you change the file extension or open a file with another program it is not designed to be opened with. This can lead to a permanent loss of data. The following is only an example and should not be taken as an endorsement to try this on your system. DO NOT TRY THIS AT HOME WITHOUT TAKING PROPER PRECAUTIONS! - -A file on a computer is stored the same way as everything on a computer is: in a binary representation. Any program works with binary, and thus you could forcibly open a file with another program either by manually making the program open the file or by changing the file's extension. See the warning above. This can ruin the file depending on the program used to open it and should only be done if you know what you're doing and must do this. Sometimes though a file will open just fine. This can commonly be seen with Text files and Image files. Often when you change the file extension and open it in an appropriate program it will open just fine. Sometimes it won't, but that is due to the program and not the file. The file opens just fine because the very beginning of the binary representation is a set of [Magic Bytes](https://en.wikipedia.org/wiki/File_format#Magic_number) that identify the type of file beyond just the file extension. This identifying information is then used by the program to match the instruction set to operate the type of file. Not all programs operate this way though. Some of them only rely on opening known good files, and if used to open a file will just start operating on it right away. This is often how a program destroys a file because it was designed to work on specific types of files and because that program is single-use it is never designed to safely use other file types so it doesn't check for them and relies purely on the operating system to call the program. Although rare, these programs do exist. More often than not though the two systems are used together. If you don't change the extension or open a program with an unexpected program this is a rare occurrence. - -# A basic understanding - -Now armed with knowledge about what a file extension is, how it helps a computer, and a little about the backup mechanisms meant to aid this series of systems it probably makes more sense why there are different programs for different types of files. +} +--- + +> A filename extension or file type is an identifier specified as a suffix to the name of computer file. - [Wikipedia](https://en.wikipedia.org/wiki/Filename_extension) + +A long & terse explanation of a file extension exists but to boil it down into simpler terms the file extension is used by a computer to check against a registry of programs to see if a program is registered on the system that can open the file. While there are some differences based on how they are treated by the operating system you use, in most cases, they are used as a simple check to allow a system to see what program can open the file. + +# Viewing the File Extension + +When most people look at a file they probably don't see a file extension after the name. Often, by default, the file extension is hidden from the user. You can easily find articles that outline how to [turn file extensions on for macOS](https://support.apple.com/guide/mac-help/show-or-hide-filename-extensions-on-mac-mchlp2304/mac) or [how to turn it on for Windows](https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/). Now when looking at the file its extension will be visible right after the name. + +![A preview of what it's like to have file extensions on and off in Windows 10](./file_extensions.png) + +As an example, most pictures you have will end in `.jpg`, `.png`, `.gif`, `.webp`, or `.avif`. A program will have a `.exe`, `.bash`, or `.bat`. A music file might have a `.mp3`, `.mp4`, `.flac`, or `.ogg`. A text file can be `.docx`, `.txt`, or `.odf`. Then there are spreadsheets, videos, hardware drivers, databases, and many other types of file extensions with more being made every day. + +Keep in mind, these file extensions are just part of the file name, they aren't part of your file's contents. If you were to remove or change the file extension and then add it back, nothing bad would happen to your file and it would act the same as it did before. + +# Opening the File + +Whenever you open a file, whether it's through a double click or open a file in an operating system from a menu the computer will go and see if there is a program registered to open that type of file extension. If it can find one registered to open the file, it takes the file and sends it to the program. If it can't find one then the computer will ask you to choose one of the programs on your computer that are registered to be associated with the file type to be used to open those types of files from now on. Of course, you could also tell your computer to change the program used to open the file menu and telling it to "open with" for a different program or by editing the file association table manually to register the program for the future. Then the program starts up then it opens the file and then the program can show the file in the way it is supposed to. + +# What happens if you open a file with another program + +> This is a serious warning about the following information: You can make your files unrecoverable if you change the file extension or open a file with another program it is not designed to be opened with. This can lead to a permanent loss of data. The following is only an example and should not be taken as an endorsement to try this on your system. DO NOT TRY THIS AT HOME WITHOUT TAKING PROPER PRECAUTIONS! + +A file on a computer is stored the same way as everything on a computer is: in a binary representation. Any program works with binary, and thus you could forcibly open a file with another program either by manually making the program open the file or by changing the file's extension. See the warning above. This can ruin the file depending on the program used to open it and should only be done if you know what you're doing and must do this. Sometimes though a file will open just fine. This can commonly be seen with Text files and Image files. Often when you change the file extension and open it in an appropriate program it will open just fine. Sometimes it won't, but that is due to the program and not the file. The file opens just fine because the very beginning of the binary representation is a set of [Magic Bytes](https://en.wikipedia.org/wiki/File_format#Magic_number) that identify the type of file beyond just the file extension. This identifying information is then used by the program to match the instruction set to operate the type of file. Not all programs operate this way though. Some of them only rely on opening known good files, and if used to open a file will just start operating on it right away. This is often how a program destroys a file because it was designed to work on specific types of files and because that program is single-use it is never designed to safely use other file types so it doesn't check for them and relies purely on the operating system to call the program. Although rare, these programs do exist. More often than not though the two systems are used together. If you don't change the extension or open a program with an unexpected program this is a rare occurrence. + +# A basic understanding + +Now armed with knowledge about what a file extension is, how it helps a computer, and a little about the backup mechanisms meant to aid this series of systems it probably makes more sense why there are different programs for different types of files. diff --git a/content/blog/what-is-primitive-obsession/index.md b/content/blog/what-is-primitive-obsession/index.md index 35f67296..1d49403c 100644 --- a/content/blog/what-is-primitive-obsession/index.md +++ b/content/blog/what-is-primitive-obsession/index.md @@ -14,20 +14,21 @@ Primitive obsession is an extremely common code smell, and when identified and fix, it greatly helps to reduce the amount of bugs that you may find in your code. This code smell is one that most developers can't intuitively identify. # What are primitive types? + In order to know what primitive obsession is about, it's useful to firstly define primitive types. Primitive types are essentially the **basic building blocks** of a language. These are integers, strings, chars, floating-point numbers etc. # What is Primitive obsession? + Primitive obsession is when your codebase relies on primitive types more than it should, and this results in them being able to control the logic of your application to some extent. For example, you may have the following in C#: - ```cs class User { public int Id { get; set; } public string Name { get; set; } } -``` +``` And this may look like a perfectly good type. However it is flawed in various ways. For example, we're not able to easily enforce any sort of constraints. @@ -98,6 +99,7 @@ Now we know for absolute certain that the `Password` of a `User` is always going You could even go a step further and make it immutable, but I'll leave that for another time! # Conclusion + Primitive Obsession is one of the least identified code smells, and for some reason isn't as popular as others. A good way I've found to identify primitive obsession is to see if you often find yourself checking if a variable satisfies a set of rules. If that's the case then you're better of making a custom type for it, with a constructor that is able to validate the input of the value you're trying to assign to it. diff --git a/content/blog/what-is-ssr-and-ssg/index.md b/content/blog/what-is-ssr-and-ssg/index.md index d69ad92b..cc5b9e76 100644 --- a/content/blog/what-is-ssr-and-ssg/index.md +++ b/content/blog/what-is-ssr-and-ssg/index.md @@ -18,10 +18,10 @@ We'll walk through all of these questions and provide answers for each. First, w While many sites today are built using a component-based framework like Angular, React, or Vue, there's nothing wrong with good ole' HTML. For sites like this, you typically provide an HTML file for each of the routes of your site. When the user requests one of the routes, your server will return the HTML for it. From there, [your browser parses that code and provides the content directly to the user](/posts/understanding-the-dom/). All in all, the process looks something like this: -1) You build HTML, CSS, JS -2) You put it on a server -3) The client downloads the HTML, CSS, JS from server -4) The client immediately sees content on screen +1. You build HTML, CSS, JS +2. You put it on a server +3. The client downloads the HTML, CSS, JS from server +4. The client immediately sees content on screen ![A diagram explaining how the steps above would flow](./normal.svg) @@ -31,11 +31,11 @@ This is a reasonably straightforward flow once you get the hang of it. Let's tak While you may not be familiar with this term, you're more than likely familiar with how you'd implement one of these; After all, this is the default when building an Angular, React, or Vue site. Let's use a React site as an example. When you build a typical React SPA without utilizing a framework like NextJS or Gatsby, you'd: -1) You build the React code -2) You put it on a server -3) The client downloads the React code from the server -4) The React code runs and generates the HTML/CSS on the client's computer -5) The user **then** sees the content on screen after React runs +1. You build the React code +2. You put it on a server +3. The client downloads the React code from the server +4. The React code runs and generates the HTML/CSS on the client's computer +5. The user **then** sees the content on screen after React runs ![A diagram explaining how the steps above would flow](./csr.svg) @@ -45,12 +45,12 @@ This is because React's code has to initialize to render the components on scree Because React has to initialize _somewhere_, what if we were to move the initial rendering off to the server? Imagine - for each request the user sends your way, you spin up an instance of React. Then, you're able to serve up the initial render (also called "fully hydrated") HTML and CSS to the user, ready to roll. That's just what server-side rendering is! -1) You build the React code -2) You put it on a server -3) The client requests data -4) The server runs the React code on the server to generate the HTML/CSS -5) The server then sends the generated HTML/CSS on screen -6) The user then sees the content on screen. React doesn't have to run on their computer +1. You build the React code +2. You put it on a server +3. The client requests data +4. The server runs the React code on the server to generate the HTML/CSS +5. The server then sends the generated HTML/CSS on screen +6. The user then sees the content on screen. React doesn't have to run on their computer ![A diagram explaining how the steps above would flow](./ssr.svg) @@ -68,15 +68,15 @@ If SSR is ["passing the buck"](https://en.wikipedia.org/wiki/Buck_passing) to th While the industry widely recognizes the term "Static Site Generation," I prefer the term "compile-side rendering" or "compile-time server-side rendering." This is because I feel they outline a better explanation of the flow of displaying content to the user. On an SSG site, you'd: -1) You build the React code -2) You generate the HTML and CSS on your development machine before deploying to a server (run build) -3) You put the generated built code on a server -4) The client downloads the HTML, CSS, JS from the built code on the server -5) The client immediately sees content on screen +1. You build the React code +2. You generate the HTML and CSS on your development machine before deploying to a server (run build) +3. You put the generated built code on a server +4. The client downloads the HTML, CSS, JS from the built code on the server +5. The client immediately sees content on screen ![A diagram explaining how the aforementioned steps would flow](./ssg.svg) -This simply extends the existing build process that many front-end frameworks have. After [Babel's done with its transpilation](https://babeljs.io/), it merely executes code to compile your initial screen into static HTML and CSS. This isn't entirely dissimilar from how SSR hydrates your initial screen, but it's done at compile-time, not at request time. +This simply extends the existing build process that many front-end frameworks have. After [Babel's done with its transpilation](https://babeljs.io/), it merely executes code to compile your initial screen into static HTML and CSS. This isn't entirely dissimilar from how SSR hydrates your initial screen, but it's done at compile-time, not at request time. Since you're only hosting HTML and CSS again, you're able to host your site as you would a client-side rendered app: Using a CDN. This means that you can geo-sparse your hosting much more trivially but comes with the caveat that you're no longer to do rapid network queries to generate the UI as you could with SSR. @@ -84,13 +84,12 @@ Since you're only hosting HTML and CSS again, you're able to host your site as y It may be tempting to look through these options, find one that you think is the best, and [overfit](https://en.wiktionary.org/wiki/overfit) yourself into a conclusion that one is superior to all the others. That said, each of these methods has its strengths and weaknesses. - -| Tool | Pros | Cons | -| ---------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| Vanilla HTM |
  • Fast
|
  • Hard to scale
| -| Client Side Rendering (CSR) |
  • Easy to scale
  • Ease of engineering
|
  • Slow JS initialization
  • SEO concerns
| -| Server Server Render (SSR) |
  • Query based optimization
  • Better SEO handling
  • Usable without client JS enabled
|
  • Heavier server load
  • Needs specific server
  • More dev effort than CSR
| -| Compile Time Rendering (SSG) |
  • Layout based optimization
  • Better SEO handling
  • Usable without client JS enabled
  • CDN hostable
|
  • No access to query data
  • More dev effort than CSR
| +| Tool | Pros | Cons | +| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| Vanilla HTM |
  • Fast
|
  • Hard to scale
| +| Client Side Rendering (CSR) |
  • Easy to scale
  • Ease of engineering
|
  • Slow JS initialization
  • SEO concerns
| +| Server Server Render (SSR) |
  • Query based optimization
  • Better SEO handling
  • Usable without client JS enabled
|
  • Heavier server load
  • Needs specific server
  • More dev effort than CSR
| +| Compile Time Rendering (SSG) |
  • Layout based optimization
  • Better SEO handling
  • Usable without client JS enabled
  • CDN hostable
|
  • No access to query data
  • More dev effort than CSR
| Consider each of these utilities a tool in your toolbox. You may be working on a landing page for a client where SSG would fit best — working on an internal SPA that only has a limited budget allocated to it? Client-side rendering might be your best bet there! Are you working on a public-facing app that highly depends on real-time data? SSR's for you! Each of these has its utility in their problem-space. It's good to keep that in mind when selecting one for your next project. @@ -122,9 +121,6 @@ All in all, while lighthouse might score you lower, you can rest assured that yo As mentioned previously, having SSR and SSG in your toolbox are incredibly useful to have at your disposal. While not appropriate for every application, those that are tend to see great advantages from the concepts. Hopefully we've been able to provide a bit of insight that'll spark further learning and research into them. - - Now you have familiarity with what SSR and SSG are, maybe you want to take a stab at implementing it? [We took a look recently at creating a blog using an Angular SSG solution called Scully](/posts/making-an-angular-blog-with-scully/). - As always, let us know what you think down in the comments below or [in our community Discord](https://discord.gg/FMcvc6T). diff --git a/content/blog/when-to-use-map-instead-of-loop/index.md b/content/blog/when-to-use-map-instead-of-loop/index.md index e1e955e4..c519bdca 100644 --- a/content/blog/when-to-use-map-instead-of-loop/index.md +++ b/content/blog/when-to-use-map-instead-of-loop/index.md @@ -11,9 +11,11 @@ license: 'cc-by-nc-nd-4' } --- + Many programmers use a **loop** or **filter** where HashMap data structure could be considered. ## Finding user by id using Loops + ```js let userIdToBeSearched = 103; const users = [ @@ -38,11 +40,13 @@ if (user) { console.log("user does not exit with id: ", userIdToBeSearched); } ``` + The above solution has a time complexity of **O(n)**, where n represents the number of users. If there are 1 thousand users, in the worst case, we will search every user to find a match. > Considering user id will be unique for each user, this is a good indication to use a HashMap instead of a loop since all keys in the Map are Unique. ## Finding user by id using Map + ```js let userIdToBeSearched = 103; const users = new Map(); @@ -59,6 +63,7 @@ else { console.log("user does not exit with id: ", userIdToBeSearched); } ``` + When using a **Map**, it takes constant time **O(1)** to find the user! All great, but note constructing the HashMap from the array still requires **O(n)** time. In conclusion, use Map when frequently searching based on the **unique** field such as **id**. Please note Map cannot be used in case of searching based on the non-unique field such as **name** diff --git a/content/blog/why-react-18-broke-your-app/index.md b/content/blog/why-react-18-broke-your-app/index.md index 6e1e7162..cb5eb06f 100644 --- a/content/blog/why-react-18-broke-your-app/index.md +++ b/content/blog/why-react-18-broke-your-app/index.md @@ -1,4 +1,4 @@ ---- +--- { title: "Why React 18 Broke Your App", description: "React 18's internal changes improved a lot, but may have broken your app in the process. Here's why and how you can fix it", @@ -8,57 +8,56 @@ attached: [], license: 'coderpad', originalLink: 'https://coderpad.io/blog/development/why-react-18-broke-your-app/' -} ---- - -You’ve just gotten done with [your React 18 upgrade](https://coderpad.io/blog/how-to-upgrade-to-react-18/), and, after some light QA testing, don’t find anything. “An easy upgrade,” you think. - -Unfortunately, down the road, you receive some internal bug reports from other developers that make it sound like your debounce hook isn’t working quite right. You decide to make a minimal reproduction and create a demo of said hook. - -You expect it to throw an “alert” dialog after a second of waiting, but weirdly, the dialog never runs at all. - - - -This is strange because it was working just last week on your machine! Why did this happen? What changed? - -**The reason your app broke in React 18 is that you’re using `StrictMode`.** - -Simply go into your `index.js` (or `index.ts`) file, and change this bit of code: - -```jsx +} +--- + +You’ve just gotten done with [your React 18 upgrade](https://coderpad.io/blog/how-to-upgrade-to-react-18/), and, after some light QA testing, don’t find anything. “An easy upgrade,” you think. + +Unfortunately, down the road, you receive some internal bug reports from other developers that make it sound like your debounce hook isn’t working quite right. You decide to make a minimal reproduction and create a demo of said hook. + +You expect it to throw an “alert” dialog after a second of waiting, but weirdly, the dialog never runs at all. + + + +This is strange because it was working just last week on your machine! Why did this happen? What changed? + +**The reason your app broke in React 18 is that you’re using `StrictMode`.** + +Simply go into your `index.js` (or `index.ts`) file, and change this bit of code: + +```jsx render( -); -``` - -To read like this: - -```jsx +); +``` + +To read like this: + +```jsx render( -); -``` - -All of the bugs that were seemingly introduced within your app in React 18 are suddenly gone. - - -Only one problem: These bugs are real and existed in your codebase before React 18 - you just didn’t realize it. - -## Proof of broken component - -Looking at our example from before, we’re using [React 18’s `createRoot` API](https://coderpad.io/blog/how-to-upgrade-to-react-18/) to render our `App` inside of a `StrictMode` wrapper in lines 56 - 60. - - - -Currently, when you press the button, it doesn’t do anything. However, if you remove the - -`StrictMode` and reload the page, you can see an `Alert` after a second of being debounced. - -Looking through the code, let’s add some `console.log`s into our `useDebounce`, since that’s where our function is supposed to be called. - -```jsx +); +``` + +All of the bugs that were seemingly introduced within your app in React 18 are suddenly gone. + +Only one problem: These bugs are real and existed in your codebase before React 18 - you just didn’t realize it. + +## Proof of broken component + +Looking at our example from before, we’re using [React 18’s `createRoot` API](https://coderpad.io/blog/how-to-upgrade-to-react-18/) to render our `App` inside of a `StrictMode` wrapper in lines 56 - 60. + + + +Currently, when you press the button, it doesn’t do anything. However, if you remove the + +`StrictMode` and reload the page, you can see an `Alert` after a second of being debounced. + +Looking through the code, let’s add some `console.log`s into our `useDebounce`, since that’s where our function is supposed to be called. + +```jsx function useDebounce(cb, delay) { const inputsRef = React.useRef({ cb, delay }); const isMounted = useIsMounted(); @@ -74,18 +73,18 @@ function useDebounce(cb, delay) { }, delay), [delay] ); -} -``` - -> ``` -> Before function is called Object { inputsRef: {…}, delay: 1000, isMounted: false } -> ``` - -Oh! It seems like `isMounted` is never being set to true, and therefore the `inputsRef.current` callback is not being called: that’s our function we wanted to be debounced. - -Let’s take a look at the `useIsMounted()` codebase: - -```jsx +} +``` + +> ``` +> Before function is called Object { inputsRef: {…}, delay: 1000, isMounted: false } +> ``` + +Oh! It seems like `isMounted` is never being set to true, and therefore the `inputsRef.current` callback is not being called: that’s our function we wanted to be debounced. + +Let’s take a look at the `useIsMounted()` codebase: + +```jsx function useIsMounted() { const isMountedRef = React.useRef(true); React.useEffect(() => { @@ -94,38 +93,38 @@ function useIsMounted() { }; }, []); return () => isMountedRef.current; -} -``` - -This code, at first glance, makes sense. After all, while we’re doing a cleanup in the return function of `useEffect` to remove it at first render, `useRef`'s initial setter runs at the start of each render, right? - -Well, not quite. - -## What changed in React 18? - -In older versions of React, you would mount a component once and that would be it. As a result, the initial value of `useRef` and `useState` could almost be treated as if they were set once and then forgotten about. - -In React 18, the React developer team decided to change this behavior and [re-mount each component more than once in strict mode](https://github.com/reactwg/react-18/discussions/19). This is in strong part due to the fact that a potential future React feature will have exactly that behavior. - -See, one of the features that the React team is hoping to add in a future release utilizes a concept of “[reusable state](https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state)”. The general idea behind reusable state is such that if you have a tab that’s un-mounted (say when the user tabs away), then re-mounted (when the user tabs back), React will recover the data that was assigned to said tab component. This data being immediately available allows you to render the respective component immediately without hesitation. - -Because of this, while data inside of, say, `useState` may be persisted, it’s imperative that effects are properly cleaned up and handled properly. [To quote the React docs](https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state): - -> This feature will give React better performance out-of-the-box but requires components to be resilient to effects being mounted and destroyed multiple times. - -However, this behavior shift in Strict Mode within React 18 isn’t just protective future-proofing from the React team: it’s also a reminder to follow React’s rules properly and to clean up your actions as expected. - -After all, the [React team themselves have been warning that an empty dependent array](https://reactjs.org/docs/hooks-reference.html#usememo) (`[]` as the second argument) should not guarantee that it only runs once for ages now. - -In fact, this article may be a bit of a misnomer - [the React team says they’ve upgraded thousands of components in Facebook’s core codebase without significant issues](https://github.com/reactwg/react-18/discussions/19#discussioncomment-796197=). More than likely, a majority of applications out there will be able to upgrade to the newest version of React without any problems. - -All that said, these React missteps crawl their way into our applications regardless. While the React team may not anticipate many breaking apps, these errors seem relatively common enough to warrant an explanation. - -## How to fix the remounting bug - -The code I linked before was written by me in a production application and it's wrong. Instead of relying on `useRef` to initialize the value once, we need to ensure the initialization runs on every instance of `useEffect`. - -```jsx +} +``` + +This code, at first glance, makes sense. After all, while we’re doing a cleanup in the return function of `useEffect` to remove it at first render, `useRef`'s initial setter runs at the start of each render, right? + +Well, not quite. + +## What changed in React 18? + +In older versions of React, you would mount a component once and that would be it. As a result, the initial value of `useRef` and `useState` could almost be treated as if they were set once and then forgotten about. + +In React 18, the React developer team decided to change this behavior and [re-mount each component more than once in strict mode](https://github.com/reactwg/react-18/discussions/19). This is in strong part due to the fact that a potential future React feature will have exactly that behavior. + +See, one of the features that the React team is hoping to add in a future release utilizes a concept of “[reusable state](https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state)”. The general idea behind reusable state is such that if you have a tab that’s un-mounted (say when the user tabs away), then re-mounted (when the user tabs back), React will recover the data that was assigned to said tab component. This data being immediately available allows you to render the respective component immediately without hesitation. + +Because of this, while data inside of, say, `useState` may be persisted, it’s imperative that effects are properly cleaned up and handled properly. [To quote the React docs](https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state): + +> This feature will give React better performance out-of-the-box but requires components to be resilient to effects being mounted and destroyed multiple times. + +However, this behavior shift in Strict Mode within React 18 isn’t just protective future-proofing from the React team: it’s also a reminder to follow React’s rules properly and to clean up your actions as expected. + +After all, the [React team themselves have been warning that an empty dependent array](https://reactjs.org/docs/hooks-reference.html#usememo) (`[]` as the second argument) should not guarantee that it only runs once for ages now. + +In fact, this article may be a bit of a misnomer - [the React team says they’ve upgraded thousands of components in Facebook’s core codebase without significant issues](https://github.com/reactwg/react-18/discussions/19#discussioncomment-796197=). More than likely, a majority of applications out there will be able to upgrade to the newest version of React without any problems. + +All that said, these React missteps crawl their way into our applications regardless. While the React team may not anticipate many breaking apps, these errors seem relatively common enough to warrant an explanation. + +## How to fix the remounting bug + +The code I linked before was written by me in a production application and it's wrong. Instead of relying on `useRef` to initialize the value once, we need to ensure the initialization runs on every instance of `useEffect`. + +```jsx function useIsMounted() { const isMountedRef = React.useRef(true); React.useEffect(() => { @@ -135,25 +134,25 @@ function useIsMounted() { }; }, []); return () => isMountedRef.current; -} -``` - -This is true for the inverse as well! We need to make sure to run cleanup on any components that we may have forgotten about before. - -Many ignore this rule for `App` and other root elements that they don’t intend to re-mount, but with new strict mode behaviors, that guarantee is no longer a safe bet. - -To solve this application across your app, look for the following signs: - -- Side effects with cleanup but no setup (like our example) -- A side effect without proper cleanup -- Utilizing `[]` in `useMemo` and `useEffect` to assume that said code will only run once - -One this code is eliminated, you should be back to a fully functioning application and can re-enable StrictMode in your application! - -## Conclusion - -React 18 brings many amazing features to the table, such as [new suspense features](https://reactjs.org/docs/concurrent-mode-suspense.html), [the new useId hook](https://github.com/reactwg/react-18/discussions/111), [automatic batching](https://github.com/reactwg/react-18/discussions/21), and more. While refactor work to support these features may be frustrating at times, it’s important to remember that they a serve real-world benefit to the user. - -For example, React 18 also introduces some functionality to debounce renders in order to create a much nicer experience when rapid user input needs to be processed. - -For more on the React 18 upgrade process, take a look at [our instruction guide on how to upgrade to React 18](https://coderpad.io/blog/how-to-upgrade-to-react-18/) +} +``` + +This is true for the inverse as well! We need to make sure to run cleanup on any components that we may have forgotten about before. + +Many ignore this rule for `App` and other root elements that they don’t intend to re-mount, but with new strict mode behaviors, that guarantee is no longer a safe bet. + +To solve this application across your app, look for the following signs: + +- Side effects with cleanup but no setup (like our example) +- A side effect without proper cleanup +- Utilizing `[]` in `useMemo` and `useEffect` to assume that said code will only run once + +One this code is eliminated, you should be back to a fully functioning application and can re-enable StrictMode in your application! + +## Conclusion + +React 18 brings many amazing features to the table, such as [new suspense features](https://reactjs.org/docs/concurrent-mode-suspense.html), [the new useId hook](https://github.com/reactwg/react-18/discussions/111), [automatic batching](https://github.com/reactwg/react-18/discussions/21), and more. While refactor work to support these features may be frustrating at times, it’s important to remember that they a serve real-world benefit to the user. + +For example, React 18 also introduces some functionality to debounce renders in order to create a much nicer experience when rapid user input needs to be processed. + +For more on the React 18 upgrade process, take a look at [our instruction guide on how to upgrade to React 18](https://coderpad.io/blog/how-to-upgrade-to-react-18/) diff --git a/content/blog/windows-subsystem-for-linux/index.md b/content/blog/windows-subsystem-for-linux/index.md index 19029f5d..7ac1bfd2 100644 --- a/content/blog/windows-subsystem-for-linux/index.md +++ b/content/blog/windows-subsystem-for-linux/index.md @@ -14,7 +14,7 @@ Windows Subsystem for Linux (WSL) lets you run software designed for Linux. This gives Windows users access to tools and web developers environments closer resembling that of their peers or the webservers hosting their code. -## Getting Started +## Getting Started First make sure Windows is updated, WSL required additional setup steps prior to version 2004. Then run open PowerShell (as Admin) and run `wsl --list --online`. This will list all the available OS's for WSL. @@ -34,7 +34,7 @@ Ubuntu-18.04 Ubuntu 18.04 LTS Ubuntu-20.04 Ubuntu 20.04 LTS ``` -## Installing +## Installing Pick your favorite flavor, mine is Ubuntu or Debian if I think I might need any older tools. Then run `wsl --install -d `. @@ -63,7 +63,7 @@ Installation successful! user@MACHINE_NAME:~$ ``` -## Setup +## Setup Run `sudo apt update` to refresh all your apt-get repos. diff --git a/content/blog/writing-better-angular-tests/index.md b/content/blog/writing-better-angular-tests/index.md index afed8806..bfbba173 100644 --- a/content/blog/writing-better-angular-tests/index.md +++ b/content/blog/writing-better-angular-tests/index.md @@ -1,4 +1,4 @@ ---- +--- { title: "Writing better tests for Angular with Angular Testing Library", description: "A simple explination of writing better tests for Angular applications and setting up Angular Testing Library", @@ -8,79 +8,79 @@ tags: ["testing", "angular"], attached: [], license: "cc-by-nc-sa-4" -} ---- - -Some evangelicals say that before code ever exists, there always needs to be a test to know how the code should be written. That frankly isn't true. A test isn't _strictly_ needed to determine how to code. What **is** needed are tests that give confidence that as code is written, a change to already existing functionality doesn't happen and that new functionality will behave properly as time goes on. To this end, a lot of testing libraries and frameworks exist. Often times, tests are written in regards to the library or framework used and not to the end product's specifications. For Angular, this is especially true when the default testing implementation is for testing angular, and not for testing what a developer would use Angular to build. **Tests should be written in the same way a user would use them.** We don't need to test Angular; we need to test what we make with Angular. - -# Writing tests for an Angular application does not mean testing Angular {#test-the-web-not-angular} - -In regards to Angular and writing tests, we must first understand what the tests are for. For a great many projects, that means testing a webpage. In proper testing for a webpage, the underlying library should be able to be changed at any time for maintainability purposes, and the tests should still work. To that end, we must write tests for the web and not for Angular. When using the Angular CLI, it sets up some tests, but when looking closely at the tests, it becomes apparent that the tests are testing Angular and not the output. - -```js +} +--- + +Some evangelicals say that before code ever exists, there always needs to be a test to know how the code should be written. That frankly isn't true. A test isn't _strictly_ needed to determine how to code. What **is** needed are tests that give confidence that as code is written, a change to already existing functionality doesn't happen and that new functionality will behave properly as time goes on. To this end, a lot of testing libraries and frameworks exist. Often times, tests are written in regards to the library or framework used and not to the end product's specifications. For Angular, this is especially true when the default testing implementation is for testing angular, and not for testing what a developer would use Angular to build. **Tests should be written in the same way a user would use them.** We don't need to test Angular; we need to test what we make with Angular. + +# Writing tests for an Angular application does not mean testing Angular {#test-the-web-not-angular} + +In regards to Angular and writing tests, we must first understand what the tests are for. For a great many projects, that means testing a webpage. In proper testing for a webpage, the underlying library should be able to be changed at any time for maintainability purposes, and the tests should still work. To that end, we must write tests for the web and not for Angular. When using the Angular CLI, it sets up some tests, but when looking closely at the tests, it becomes apparent that the tests are testing Angular and not the output. + +```js it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; expect(app).toBeTruthy(); -}); -``` - -This test isn't a very good test. It doesn't say anything about the actual output of the application component itself. When the output is a full, rich webpage and tests are testing Angular, then the tests won't do much when the content of the webpage is changed. - -While the default testing setup does allow for the writing of tests that would test the outputted HTML they are still specific to Angular - -```js +}); +``` + +This test isn't a very good test. It doesn't say anything about the actual output of the application component itself. When the output is a full, rich webpage and tests are testing Angular, then the tests won't do much when the content of the webpage is changed. + +While the default testing setup does allow for the writing of tests that would test the outputted HTML they are still specific to Angular + +```js it('should render title', () => { const fixture = TestBed.createComponent(AppComponent); fixture.detectChanges(); const compiled = fixture.nativeElement; expect(compiled.querySelector('.content span').textContent).toContain('The app is running!'); -}); -``` - -That test looks a little better, but it's still very tied to Angular. The test requires in-depth knowledge of how Angular actually routes and moves all the bits around to write tests for it, and as a result, the tests are completely tied into Angular and the current API footprint. If — over the years — Angular is retired, these tests will no longer be valid. - -If the tests were just tailored to the outputted DOM or containers it would be a much easier and more adaptable test. - -```js +}); +``` + +That test looks a little better, but it's still very tied to Angular. The test requires in-depth knowledge of how Angular actually routes and moves all the bits around to write tests for it, and as a result, the tests are completely tied into Angular and the current API footprint. If — over the years — Angular is retired, these tests will no longer be valid. + +If the tests were just tailored to the outputted DOM or containers it would be a much easier and more adaptable test. + +```js test('should render counter', async () => { await render(AppComponent); expect(document.querySelector('.content span').innerText).toBe('The app is running!'); -}); -``` - -This test no longer even needs Angular to be the library chosen. It just requires that a render method, when given the component, will render it to the DOM present in the testing environment. This can be run in the Framework, and even tested against in a real world browser. This is a good test in that the first `span` inside of `.content` has the `innerText` value expected in the test. These are all JavaScript and DOM APIs and thus can be trusted in any environment that adheres to them. - -Writing tests that don't rely on testing Angular, but instead rely on the DOM, allows the application to be tested in a way that a user would use the application instead of the way that Angular internally works. - -# Fixing that shortcoming using Testing Library {#testing-library} - -Thankfully, writing tests like these have been made simple by a testing library simply called "[Testing Library](https://testing-library.com)." Testing Library is a collection of libraries for various frameworks and applications. One of the supported libraries is Angular, through the [Angular Testing Library](https://testing-library.com/docs/angular-testing-library/intro). This can be used to test Angular apps in a simple DOM focused manner with some nice helpers to make it even easier to work with. It relies on [Jest](https://jestjs.io/) as an extension to the Jasmine testing framework to make testing easier, and more end-results focused. With that tooling, a project can have tests much less focused on Angular and much more focused on what is being made. - -## Transitioning to Jest and Angular Testing Library {#transitioning-to-jest} - -### Get rid of Karma {#remove-karma} - -Angular ships with Karma alongside Jasmine for running tests and collecting coverage. With Jest, an Angular project no longer needs Karma or the other packages that would be installed by the Angular CLI. - -#### Uninstall Karma - -```bash -npm uninstall karma karma-chrome-launcher karma-coverage-istanbul-reporter karma-jasmine karma-jasmine-html-reporter -``` - -#### Remove the leftover configurations {#remove-karma-config} - -Deleting the following will remove the leftover configuration files from the project: - -```bash +}); +``` + +This test no longer even needs Angular to be the library chosen. It just requires that a render method, when given the component, will render it to the DOM present in the testing environment. This can be run in the Framework, and even tested against in a real world browser. This is a good test in that the first `span` inside of `.content` has the `innerText` value expected in the test. These are all JavaScript and DOM APIs and thus can be trusted in any environment that adheres to them. + +Writing tests that don't rely on testing Angular, but instead rely on the DOM, allows the application to be tested in a way that a user would use the application instead of the way that Angular internally works. + +# Fixing that shortcoming using Testing Library {#testing-library} + +Thankfully, writing tests like these have been made simple by a testing library simply called "[Testing Library](https://testing-library.com)." Testing Library is a collection of libraries for various frameworks and applications. One of the supported libraries is Angular, through the [Angular Testing Library](https://testing-library.com/docs/angular-testing-library/intro). This can be used to test Angular apps in a simple DOM focused manner with some nice helpers to make it even easier to work with. It relies on [Jest](https://jestjs.io/) as an extension to the Jasmine testing framework to make testing easier, and more end-results focused. With that tooling, a project can have tests much less focused on Angular and much more focused on what is being made. + +## Transitioning to Jest and Angular Testing Library {#transitioning-to-jest} + +### Get rid of Karma {#remove-karma} + +Angular ships with Karma alongside Jasmine for running tests and collecting coverage. With Jest, an Angular project no longer needs Karma or the other packages that would be installed by the Angular CLI. + +#### Uninstall Karma + +```bash +npm uninstall karma karma-chrome-launcher karma-coverage-istanbul-reporter karma-jasmine karma-jasmine-html-reporter +``` + +#### Remove the leftover configurations {#remove-karma-config} + +Deleting the following will remove the leftover configuration files from the project: + +```bash karma.config.js -src/test.ts -``` - -Once those two files are deleted, any references to `src/test.ts` will need to be removed. Removing the paths from the following file that reference them cleans it up easily enough: - -```json +src/test.ts +``` + +Once those two files are deleted, any references to `src/test.ts` will need to be removed. Removing the paths from the following file that reference them cleans it up easily enough: + +```json tsconfig.spec.json { ..., @@ -88,22 +88,23 @@ tsconfig.spec.json "src/test.ts", <- delete ... ] -} -``` - -The project also no longer needs the `test` key inside of `angular.json` as it stands, and thus it's contents can be removed. Don't worry, we'll be making `ng test` work again later. -```json +} +``` + +The project also no longer needs the `test` key inside of `angular.json` as it stands, and thus it's contents can be removed. Don't worry, we'll be making `ng test` work again later. + +```json angular.json { ..., "test": {} <- delete contents, but leave the key .... -} -``` - -Finally the project no longer needs the Jasmine types in the spec configuration - -```json +} +``` + +Finally the project no longer needs the Jasmine types in the spec configuration + +```json tsconfig.spec.json { ..., @@ -114,43 +115,43 @@ tsconfig.spec.json ... ] } -} -``` - -Now the project is ready for installing any other test runner. - -### Setting up Jest {#setup-jest} - -Now that the project has no Karma it can be setup with Jest - -#### Install Jest - -```bash -npm i -D @types/jest jest jest-preset-angular ts-jest @angular-builders/jest -``` - -This installs Jest, the types for Jest, a TypeScript pre-processor for Jest, and a preset that makes setting up Jest much easier. - -#### Configure Jest - -The project now needs to know how to best utilize Jest. Creating and modify the following files will allow Jest to load it's own configuration. - -```js +} +``` + +Now the project is ready for installing any other test runner. + +### Setting up Jest {#setup-jest} + +Now that the project has no Karma it can be setup with Jest + +#### Install Jest + +```bash +npm i -D @types/jest jest jest-preset-angular ts-jest @angular-builders/jest +``` + +This installs Jest, the types for Jest, a TypeScript pre-processor for Jest, and a preset that makes setting up Jest much easier. + +#### Configure Jest + +The project now needs to know how to best utilize Jest. Creating and modify the following files will allow Jest to load it's own configuration. + +```js jest.config.js module.exports = { preset: 'jest-preset-angular', setupFilesAfterEnv: [ '/jest.setup.ts' ] -}; -``` - -```typescript +}; +``` + +```typescript jest.setup.ts -import 'jest-preset-angular'; -``` - -```json +import 'jest-preset-angular'; +``` + +```json tsconfig.spec.json { ..., @@ -161,10 +162,10 @@ tsconfig.spec.json ... ] } -} -``` - -```json +} +``` + +```json tsconfig.json { ..., @@ -175,10 +176,10 @@ tsconfig.json ... }, ... -} -``` - -```json +} +``` + +```json package.json { ..., @@ -189,10 +190,10 @@ package.json ... }, ... -} -``` - -```json +} +``` + +```json angular.json { ..., @@ -200,19 +201,19 @@ angular.json "builder": "@angular-builders/jest:run" <- new } .... -} -``` - -Jest is now the test runner for the projectand it can be run with NPM, Yarn, or the Angular CLI. It can now be used in combination with Testing Library. - -### Install Angular Testing Library - -Now the project is ready to have better tests written for it and by using [Angular Testing Library](https://testing-library.com/docs/angular-testing-library/intro) the tests can be simplified with some great helpers. - -```bash -npm install --save-dev @testing-library/angular -``` - -# Ready, Steady, Test! {#conclusion} - -Now that the project has a better testing library with some great helpers better tests can be written. There are plenty of [great examples](https://testing-library.com/docs/angular-testing-library/examples) for learning and [Tim Deschryver](https://timdeschryver.dev/blog/good-testing-practices-with-angular-testing-library) has more examples to help in that endeavor, and the Angular Testing Library will make tests much simpler to write and maintain. With Angular, good tests, and plenty of confidence anyone would be happy to ship a project with this setup. +} +``` + +Jest is now the test runner for the projectand it can be run with NPM, Yarn, or the Angular CLI. It can now be used in combination with Testing Library. + +### Install Angular Testing Library + +Now the project is ready to have better tests written for it and by using [Angular Testing Library](https://testing-library.com/docs/angular-testing-library/intro) the tests can be simplified with some great helpers. + +```bash +npm install --save-dev @testing-library/angular +``` + +# Ready, Steady, Test! {#conclusion} + +Now that the project has a better testing library with some great helpers better tests can be written. There are plenty of [great examples](https://testing-library.com/docs/angular-testing-library/examples) for learning and [Tim Deschryver](https://timdeschryver.dev/blog/good-testing-practices-with-angular-testing-library) has more examples to help in that endeavor, and the Angular Testing Library will make tests much simpler to write and maintain. With Angular, good tests, and plenty of confidence anyone would be happy to ship a project with this setup. diff --git a/content/collections/framework-field-guide/above.md b/content/collections/framework-field-guide/above.md index 11567dbb..a72a3213 100644 --- a/content/collections/framework-field-guide/above.md +++ b/content/collections/framework-field-guide/above.md @@ -1,26 +1,25 @@
-
- -## Why learn React, Angular, **and** Vue?! - -By learning React, Angular, and Vue all at once you gain: -- Deeper understanding of core concepts than you'd have by only learning one framework -- Insight into different programming methodologies -- Appreciation for the "why" behind framework tradeoffs -- A superpower to learn similar UI frameworks much faster - -Don't want to learn all three? **That's okay.** You can easily select a single framework and use this book to learn it front-to-back. - -
- +
+ +## Why learn React, Angular, **and** Vue?! + +By learning React, Angular, and Vue all at once you gain: + +- Deeper understanding of core concepts than you'd have by only learning one framework +- Insight into different programming methodologies +- Appreciation for the "why" behind framework tradeoffs +- A superpower to learn similar UI frameworks much faster + +Don't want to learn all three? **That's okay.** You can easily select a single framework and use this book to learn it front-to-back. + +
+
-
- - +
+
-
- - -
\ No newline at end of file + + + diff --git a/content/collections/framework-field-guide/index.md b/content/collections/framework-field-guide/index.md index 6f566999..26b6c55a 100644 --- a/content/collections/framework-field-guide/index.md +++ b/content/collections/framework-field-guide/index.md @@ -69,6 +69,7 @@ For instances where the frameworks diverge, you'll see tabs to see the relevant For example, here's a "Hello world" component in each framework: + # React ```jsx @@ -108,9 +109,9 @@ In the book print, these tabs will be turned into sub-headings. This book is primarily for three sets of people: -1) Newcomers, who are looking to learn these frameworks for the first time. -2) Engineers who've learned one framework and are looking for an easy way to learn one of the others. -3) Those looking to 1-up their knowledge of these frameworks' internals +1. Newcomers, who are looking to learn these frameworks for the first time. +2. Engineers who've learned one framework and are looking for an easy way to learn one of the others. +3. Those looking to 1-up their knowledge of these frameworks' internals This book will be starting with the very basics of what a component is, all the way into re-creating the core elements of these frameworks from scratch. Don't believe me? [**Here's sneak peek of the "React Internals" chapter I wrote via a Twitter thread where I build `useState` in Vanilla JS**](https://twitter.com/crutchcorn/status/1527059744392814592). diff --git a/content/site/about-us.es.md b/content/site/about-us.es.md index df2c878f..e823a9bc 100644 --- a/content/site/about-us.es.md +++ b/content/site/about-us.es.md @@ -73,7 +73,7 @@ Como lo mencionamos antes, también tenemos un servidor de Discord donde podemos Si quieres aprender más sobre los patrocinios y su impacto en nuestro sitio, puedes leer [los detalles que publicamos en GitHub](https://github.com/unicorn-utterances/unicorn-utterances/issues?q=is%3Aissue+label%3Adisclosure+is%3Aclosed). - + En pocas palabras: ningún patrocinador toma decisiones sobre el contenido publicado en el sitio. # Declaración de Ética {#ethics} diff --git a/content/site/about-us.fr.md b/content/site/about-us.fr.md index 4813e49a..1576c4a8 100644 --- a/content/site/about-us.fr.md +++ b/content/site/about-us.fr.md @@ -73,7 +73,7 @@ Et comme nous l’avons déjà cité, on a un serveur Discord ou on parle tech, Pour plus d’informations concernant nos sponsors et leurs impact sur notre site, vous pouvez consulter [les divulgations que nous avons publiées sur GitHub](https://github.com/unicorn-utterances/unicorn-utterances/issues?q=is%3Aissue+label%3Adisclosure+is%3Aclosed). - + (Bref: Les sponsors n'ont pas un effet direct sur le contenu du site) # Code d’éthique {#ethics} diff --git a/content/site/about-us.md b/content/site/about-us.md index 08772128..387fda55 100644 --- a/content/site/about-us.md +++ b/content/site/about-us.md @@ -73,7 +73,7 @@ As mentioned previously, we also have a Discord where we chat tech, help out wit If you want to learn more about our sponsorships and how they impact our site, you can read through [our disclosures that we've posted on GitHub](https://github.com/unicorn-utterances/unicorn-utterances/issues?q=is%3Aissue+label%3Adisclosure+is%3Aclosed). - + TLDR: No sponsor has any say about the content hosted on the site # Statement of Ethics {#ethics} diff --git a/public/sponsors/README.md b/public/sponsors/README.md index 163fe9bb..dea532a2 100644 --- a/public/sponsors/README.md +++ b/public/sponsors/README.md @@ -1,3 +1,3 @@ These assets belong entirely to the sponsors themselves. We claim no rights -over these files in any way. As a result, please consult the associated +over these files in any way. As a result, please consult the associated group for inquiries regarding rights of these assets. diff --git a/src/utils/markdown/plugins/tabs/README.md b/src/utils/markdown/plugins/tabs/README.md index e2691aa3..0dcabe3f 100644 --- a/src/utils/markdown/plugins/tabs/README.md +++ b/src/utils/markdown/plugins/tabs/README.md @@ -1,6 +1,5 @@ A rehype plugin for rendering tabbed content from HTML comments and headings. - ![preview](https://user-images.githubusercontent.com/9100169/148681602-03f6f446-7dea-4efb-ad82-132f6a8debdd.gif) This is particularly useful when paired with a `remark` parsing step. @@ -27,7 +26,6 @@ Ciao! ``` - ### Markdown Example ```markdown @@ -99,4 +97,4 @@ It would render "One" and "Three" as tab headings, but "Two" would be listed as ## Special Thanks -This syntax is inspired by: https://jhildenbiddle.github.io/docsify-tabs/#/ +This syntax is inspired by:
Subject