How To Build Web Components Using Stencil JS
Tags: react, stenciljs, component, javascript
Published: 2020-03-24 05:55:55

<main role="main"><article class=" u-minHeight100vhOffset65 u-overflowHidden postArticle postArticle--full is-supplementalPostContentLoaded is-withAccentColors" lang="en"><div class="postArticle-content js-postField js-notesSource editable" id="editor_6" g_editable="true" role="textbox" contenteditable="true" data-default-value="Title
Tell your story…" spellcheck="false"><section name="e1ca" class="section section--body section--first section--last"><div class="section-divider"><hr class="section-divider"></div><div class="section-content"><div class="section-inner sectionLayout--insetColumn"><p name="6de2" class="graf graf--p graf-after--figure">Stencil is a compiler that generates Web Components (more specifically, Custom Elements). Stencil combines the best concepts of the most popular frameworks into a simple build-time tool and we can use these web components everywhere in your JavaScript projects(Angular, React, Vue) without need to copying one thing again and again. You can either use it in your Vanilla JavaScript.</p><blockquote name="7c66" class="graf graf--blockquote graf-after--p">Stencil was created by the <a href="http://ionicframework.com/"  class="markup--anchor markup--blockquote-anchor" rel="noopener"    target="_blank">Ionic Framework</a> team to help build faster, more capable components that worked across all major frameworks.</blockquote><h3 name="6832" class="graf graf--h3 graf-after--blockquote">Goals and Features of a&nbsp;stencil</h3><p name="cc8c" class="graf graf--p graf-after--h3">Stencil aims to combine the best concepts of the most popular front-end frameworks into a compile-time tool rather than a run-time tool. It’s important to stress that Stencil’s goal is to <em class="markup--em markup--p-em">not</em> become or be seen as a “framework”, but rather our goal is to provide a great developer experience and tooling expected from a framework</p><h4 name="a64a" class="graf graf--h4 graf-after--p">Virtual DOM</h4><p name="e443" class="graf graf--p graf-after--h4">basically, The <strong class="markup--strong markup--p-strong">virtual DOM</strong> (VDOM) is a programming concept where an ideal, or “<strong class="markup--strong markup--p-strong">virtual</strong>”, representation of a UI is kept in memory and synced with the “real” <strong class="markup--strong markup--p-strong">DOM</strong> by a library.</p><h4 name="cf06" class="graf graf--h4 graf-after--p">Async rendering (inspired by React&nbsp;Fiber)</h4><p name="9900" class="graf graf--p graf-after--h4">we can also able to do an <strong class="markup--strong markup--p-strong">asynchronous</strong> call before <strong class="markup--strong markup--p-strong">rendering</strong> the data implemented in a Class</p><h4 name="89d8" class="graf graf--h4 graf-after--p">Reactive data-binding</h4><p name="358c" class="graf graf--p graf-after--h4">Reactive data-binding simply means that a flow of changes in your <strong class="markup--strong markup--p-strong">data</strong> drives action. Whether the change comes from both the DOM and the <strong class="markup--strong markup--p-strong">data</strong> in your application or just one of those, does not really matter.</p><h4 name="d87c" class="graf graf--h4 graf-after--p">TypeScript</h4><p name="2669" class="graf graf--p graf-after--h4">TypeScript is an open-source programming language developed and maintained by Microsoft. It is a strict syntactical superset of JavaScript and adds optional static typing to the language. TypeScript is designed for development of large applications and trans compiles to JavaScript</p><h4 name="0eff" class="graf graf--h4 graf-after--p">JSX</h4><p name="d9c3" class="graf graf--p graf-after--h4"><strong class="markup--strong markup--p-strong">JSX</strong> is a preprocessor step that adds XML syntax to JavaScript. You can definitely use Stencil without <strong class="markup--strong markup--p-strong">JSX</strong> but <strong class="markup--strong markup--p-strong">JSX</strong> makes Stencil components a lot more elegant. Just like XML, <strong class="markup--strong markup--p-strong">JSX </strong>tags have a tag name, attributes, and children. If an attribute value is enclosed in quotes, the value is a string.</p><h4 name="9b1c" class="graf graf--h4 graf-after--p">Live reload</h4><p name="eaec" class="graf graf--p graf-after--h4"><strong class="markup--strong markup--p-strong">Live reloading reloads</strong> or refreshes the entire app when a file changes.</p><h4 name="da39" class="graf graf--h4 graf-after--p">Web Standards</h4><p name="9d87" class="graf graf--p graf-after--h4">Components generated by Stencil, in the end, are built on top of web components, so they work in any major framework or with no framework at all. Additionally, other standards heavily relied on include ES Modules and dynamic imports which have proven to replace traditional bundlers which add unnecessary complexities and run-time JavaScript. By using web-standards, developers can learn and adopt a standard API documented across the world, rather than custom framework APIs that continue to change.</p><h4 name="a30d" class="graf graf--h4 graf-after--p">Wide Browser&nbsp;Support</h4><p name="18e5" class="graf graf--p graf-after--h4">For the small minority of browsers that do not support modern browser features and APIs, Stencil will automatically polyfill them on-demand.</p><h4 name="58ea" class="graf graf--h4 graf-after--p">Automatic Optimizations</h4><p name="4bdb" class="graf graf--p graf-after--h4">There are countless optimizations and tweaks developers must do to improve performance of components and websites. With a compiler, Stencil is able to analyze component code as an input, and generate optimized components as an output.</p><h4 name="b006" class="graf graf--h4 graf-after--p">Run-time Performance</h4><p name="a81a" class="graf graf--p graf-after--h4">Instead of writing custom client-side JavaScript which every user needs to download and parse for the app to work, Stencil instead prefers to use the already amazing APIs built directly within the browser. These APIs include Custom Elements</p><h4 name="88b8" class="graf graf--h4 graf-after--p">Tiny API</h4><p name="44ac" class="graf graf--p graf-after--h4">Stencil purposely does not come with a large custom API which needs to be learned and re-learned, but rather heavily relies on, you guessed it, web standards. Again, our goal is to not create yet-another-framework, but rather provide tooling for developers to generate future-friendly components using APIs already baked within the browser. The smaller the API, the easier to learn, and the less that can be broken.</p><h3 name="dacb" class="graf graf--h3 graf-after--p">Getting Started</h3><h4 name="c27e" class="graf graf--h4 graf-after--h3">Steps we will follow for Adding Stencil to our Simple Javascript Application</h4><ol class="postList"><li name="c42a" class="graf graf--li graf-after--h4">Crating a simple Stencil component</li><li name="580a" class="graf graf--li graf-after--li">Modify this component according to our requirements</li><li name="80ae" class="graf graf--li graf-after--li">Add this component into Our Javascript Application</li></ol><h4 name="35cc" class="graf graf--h4 graf-after--li">Crating a simple Stencil component</h4><p name="21f0" class="graf graf--p graf-after--h4">Stencil requires a recent LTS version of <a href="https://nodejs.org/"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">NodeJS</a> and npm. Make sure you’ve installed and/or updated Node before continuing.</p><blockquote name="7ddf" class="graf graf--blockquote graf-after--p"><em class="markup--em markup--blockquote-em">Note that you will need to use npm 6 or higher.</em></blockquote><p name="f5c5" class="graf graf--p graf-after--blockquote">For Creating Project in a stencil, you have to open your system terminal and type</p><pre name="e4f3" class="graf graf--pre graf-after--p">npm init stencil</pre><figure tabindex="0" contenteditable="false" name="cfa7" class="graf graf--figure graf-after--pre"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 404px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 57.8%;"></div><img class="graf-image" data-image-id="1*KtN2Rl0RTPT49jpmychtVw.png" data-width="1101" data-height="636" src="https://cdn-images-1.medium.com/max/720/1*KtN2Rl0RTPT49jpmychtVw.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Stencil Init</figcaption></figure><p name="8241" class="graf graf--p graf-after--figure">Stencil can be used to create standalone components or entire apps. After running init you will be provided with a prompt so that you can choose the type of project to start.</p><p name="d0c2" class="graf graf--p graf-after--p"><strong class="markup--strong markup--p-strong">In this Blog, we will cover components part of the stencil.</strong></p><p name="5d0c" class="graf graf--p graf-after--p">so after clicking on component, it will ask you for the component name</p><figure tabindex="0" contenteditable="false" name="d0e8" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 404px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 57.8%;"></div><img class="graf-image" data-image-id="1*K_tkptBjX2U2E3fvqUq-Rg.png" data-width="1103" data-height="637" src="https://cdn-images-1.medium.com/max/720/1*K_tkptBjX2U2E3fvqUq-Rg.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Component name&nbsp;Stencil</figcaption></figure><p name="c31e" class="graf graf--p graf-after--figure">After the name, it will ask for confirmation of the name</p><figure tabindex="0" contenteditable="false" name="74cd" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 408px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 58.3%;"></div><img class="graf-image" data-image-id="1*4DlY4vbaCQWj6JSUiW1EgA.png" data-width="1101" data-height="642" src="https://cdn-images-1.medium.com/max/720/1*4DlY4vbaCQWj6JSUiW1EgA.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Confirm Stencil</figcaption></figure><p name="0b68" class="graf graf--p graf-after--figure">when you press ‘<strong class="markup--strong markup--p-strong">Y</strong>’ here and press <strong class="markup--strong markup--p-strong">enter</strong> key. it will create your component</p><figure tabindex="0" contenteditable="false" name="240b" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 404px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 57.699999999999996%;"></div><img class="graf-image" data-image-id="1*bhGZgWwIfHbIZfN990XYSg.png" data-width="1105" data-height="638" src="https://cdn-images-1.medium.com/max/720/1*bhGZgWwIfHbIZfN990XYSg.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Component Create&nbsp;Stencil</figcaption></figure><p name="bc87" class="graf graf--p graf-after--figure">so once it finishes go to your project folder and run</p><pre name="7743" class="graf graf--pre graf-after--p">npm start</pre><p name="9aa2" class="graf graf--p graf-after--pre">to spin up the development server and it should automatically open in a new tab in your browser if it doesn’t you can find it on <strong class="markup--strong markup--p-strong">localhost:3333</strong></p><figure tabindex="0" contenteditable="false" name="9c3c" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 394px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 56.3%;"></div><img class="graf-image" data-image-id="1*wH9-6ObOlqSwQOQyZ_dM1A.png" data-width="1920" data-height="1080" src="https://cdn-images-1.medium.com/max/720/1*wH9-6ObOlqSwQOQyZ_dM1A.png"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Stencil app&nbsp;started</figcaption></figure><p name="e62d" class="graf graf--p graf-after--figure">and you should see ` Hello, World! I’m Stencil ‘Don’t call me a framework’ JS`</p><p name="e9ca" class="graf graf--p graf-after--p">Okay so now let’s look into the folder we got from the command to find out what is responsible for this output. so I have opened the project folder with visual studio code, of course, you can use webstorm, atom, sublime whatever you like. Inside of this folder, you can see a couple of folder and file. The files are mostly config file. you won’t see a webpack config file yeah stencil might use webpack behind the scene but it doesn’t expose the configuration to you because of the stencil itself a compiler it false the idea of doing that logic for you.</p><p name="2951" class="graf graf--p graf-after--p">In stencil, you don’t need to config a webpack to bundle all your files and framework and so on together because again you are not using a framework here.</p><p name="1e95" class="graf graf--p graf-after--p">Now let’s have a look in Source folder in which we write our own component as you might guess in the components folder and there you find one folder named my-component with two files inside of it.</p><p name="8b60" class="graf graf--p graf-after--p">When you check my-component.tsx&nbsp;. This might look bit like angular to you it uses typescript and decorators and then again it’s look bit like React because we have the render method where we return some HTML but that is JSX. and we also have a css file where we can style our own component.</p><p name="1e0c" class="graf graf--p graf-after--p">and we also have an index.html file in the source folder where we have added our component. But again, in the end, we just split out a couple of javascript files you can drop into any project, But for testing, it gives us an index.html file</p><h4 name="32b7" class="graf graf--h4 graf-after--p">Modify this component according to our requirements</h4><p name="3873" class="graf graf--p graf-after--h4">Now we will modify existing my-component.tsx file and makes one component which is responsible for creating custom modal.</p><figure tabindex="0" contenteditable="false" name="3b2a" class="graf graf--figure graf--iframe graf-after--p is-defaultValue"><div class="aspectRatioPlaceholder is-locked"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 35.699999999999996%;"></div><div class="iframeContainer">{% gist https://gist.github.com/enappd/91bb802faca33009dbee5a40637d6591.js %}</div></div></figure><p name="c495" class="graf graf--p graf-after--figure">So here we have modified our my-component.tsx file for creating custom modal.</p><figure tabindex="0" contenteditable="false" name="4571" class="graf graf--figure graf-after--p is-defaultValue"><div class="aspectRatioPlaceholder is-locked" style="max-width: 300px; max-height: 533px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 177.7%;"></div><img class="graf-image" data-image-id="1*AkbAbyZr8zAPIVO23z9nwQ.jpeg" data-width="300" data-height="533" src="https://cdn-images-1.medium.com/max/720/1*AkbAbyZr8zAPIVO23z9nwQ.jpeg"><div class="crosshair u-ignoreBlock"></div></div></figure><p name="4e2c" class="graf graf--p graf-after--figure">In this example, we have used 4 decorators</p><ol class="postList"><li name="5e41" class="graf graf--li graf-after--p">Component&nbsp;:- <a href="https://stenciljs.com/docs/component#component-decorator"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">@Component()</a> declares a new web component</li></ol><p name="3e1c" class="graf graf--p graf-after--li">Each Stencil Component must be decorated with a <code class="markup--code markup--p-code">@Component()</code> decorator from the <code class="markup--code markup--p-code">@stencil/core</code> package. In the simplest case, developers must provide an HTML <code class="markup--code markup--p-code">tag</code> name for the component. Often times, a <code class="markup--code markup--p-code">styleUrl</code> is used as well, or even <code class="markup--code markup--p-code">styleUrls</code>, where multiple different style sheets can be provided for different application modes/themes.</p><p name="0988" class="graf graf--p graf-after--p">2. Prop&nbsp;:- <a href="https://stenciljs.com/docs/properties#prop-decorator"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">@Prop()</a> declares an exposed property/attribute</p><p name="4a5b" class="graf graf--p graf-after--p">Props are custom attribute/properties exposed publicly on the element that developers can provide values for. Children components should not know about or reference parent components, so Props should be used to pass data down from the parent to the child. Components need to explicitly declare the Props they expect to receive using the <code class="markup--code markup--p-code">@Prop()</code> decorator. Props can be a <code class="markup--code markup--p-code">number</code>, <code class="markup--code markup--p-code">string</code>, <code class="markup--code markup--p-code">boolean</code>, or even an <code class="markup--code markup--p-code">Object</code> or <code class="markup--code markup--p-code">Array</code>. By default, when a member decorated with a <code class="markup--code markup--p-code">@Prop()</code> decorator is set, the component will efficiently re-render.</p><p name="731b" class="graf graf--p graf-after--p">3. Method&nbsp;:- <a href="https://stenciljs.com/docs/methods#method-decorator"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">@Method()</a> declares an exposed public method</p><p name="a7c5" class="graf graf--p graf-after--p">The <code class="markup--code markup--p-code">@Method()</code> decorator is used to expose methods on the public API. Functions decorated with the <code class="markup--code markup--p-code">@Method()</code> decorator can be called directly from the element, ie. they are intented to be callable from the outside!</p><p name="a0f2" class="graf graf--p graf-after--p">4. State&nbsp;:- <a href="https://stenciljs.com/docs/state#state-decorator"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">@State()</a> declares an internal state of the component</p><p name="d3a2" class="graf graf--p graf-after--p">The <code class="markup--code markup--p-code">@State()</code> decorator can be used to manage internal data for a component. This means that a user cannot modify this data from outside the component, but the component can modify it however it sees fit. Any changes to a <code class="markup--code markup--p-code">@State()</code> property will cause the components <code class="markup--code markup--p-code">render</code> function to be called again.</p><p name="a8f9" class="graf graf--p graf-after--p">Here you can modify CSS and tsx according to your requirements.</p><p name="d774" class="graf graf--p graf-after--p">All the css related to your component should go into your-component.css file and you can write the logic for the code in your-component.tsx file</p><h4 name="7615" class="graf graf--h4 graf-after--p">How to use This Component In Simple Java script&nbsp;project</h4><p name="b982" class="graf graf--p graf-after--h4">Integrating a component built with Stencil to a project without a JavaScript framework is straight forward. If you’re using a simple HTML page, you can add your component via a script tag. like this</p><pre name="70df" class="graf graf--pre graf-after--p">&lt;script type="module" src="/build/stencilcomponent.esm.js"&gt;&lt;/script&gt;</pre><pre name="a3d0" class="graf graf--pre graf-after--pre">&lt;script nomodule src="/build/stencilcomponent.js"&gt;&lt;/script&gt;</pre><p name="2f1b" class="graf graf--p graf-after--pre">So after Modification in our index file, it will something look like this</p><figure tabindex="0" contenteditable="false" name="3b06" class="graf graf--figure graf--iframe graf-after--p is-defaultValue"><div class="aspectRatioPlaceholder is-locked"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 35.699999999999996%;"></div><div class="iframeContainer">{% gist https://gist.github.com/enappd/e9eeb1f9730df5e4feb7c9485e31f901.js %}</div></div></figure><p name="1298" class="graf graf--p graf-after--figure">In this project, I have some created some more components according to mobile UI you can check the <a href="https://github.com/enappd/StencilComponents"  class="markup--anchor markup--p-anchor" rel="noopener"    target="_blank">complete source code here for the example</a></p><figure tabindex="0" contenteditable="false" name="a449" class="graf graf--figure graf-after--p is-defaultValue"><div class="aspectRatioPlaceholder is-locked" style="max-width: 300px; max-height: 533px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 177.7%;"></div><img class="graf-image" data-image-id="1*cUWw6f2WU7UMchF73h61Dw.jpeg" data-width="300" data-height="533" src="https://cdn-images-1.medium.com/max/720/1*cUWw6f2WU7UMchF73h61Dw.jpeg"><div class="crosshair u-ignoreBlock"></div></div></figure><h3 name="f388" class="graf graf--h3 graf-after--figure">Conclusion</h3><p name="c8cb" class="graf graf--p graf-after--h3">We looked at how to create a custom component in stencil and how to use it is a simple javascript Project. We have also learned how to pass props to a parent component to children component and how to call a component function in a parent component.</p><h3 name="047c" class="graf graf--h3 graf-after--p">Next Steps</h3><p name="178a" class="graf graf--p graf-after--h3">Now that you have learned how to create custom components in Stencil and how to use it in a simple javascript project, you can also try:</p><ul class="postList"><li name="9f48" class="graf graf--li graf-after--p is-selected"><a href="https://enappd.com/blog/ionic-4-paypal-payment-integration-for-apps-and-pwa/16"  class="markup--anchor markup--li-anchor" rel="nofollow noopener noopener noopener noopener noopener noopener noopener noopener"    target="_blank">Ionic 4 PayPal payment integration&#8202;—&#8202;for Apps and PWA</a></li><li name="aa95" class="graf graf--li graf-after--li"><a href="https://enappd.com/blog/ionic-4-stripe-payment-integration-with-firebase-for-apps-and-pwa/17"  class="markup--anchor markup--li-anchor" rel="nofollow noopener noopener noopener noopener noopener noopener noopener noopener"    target="_blank">Ionic 4 Stripe payment integration&#8202;—&#8202;for Apps and PWA</a></li><li name="fc67" class="graf graf--li graf-after--li"><a href="https://enappd.com/blog/how-to-integrate-apple-pay-in-ionic-4-apps/21"  class="markup--anchor markup--li-anchor" rel="nofollow noopener noopener noopener noopener noopener noopener noopener noopener"    target="_blank">Ionic 4 Apple Pay integration</a></li><li name="b1fc" class="graf graf--li graf-after--li"><a href="https://enappd.com/blog/twitter-login-in-ionic-4-apps-using-firebase/24"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Twitter login in Ionic 4 with Firebase</a></li><li name="57fe" class="graf graf--li graf-after--li"><a href="https://enappd.com/blog/facebook-login-in-ionic-4-apps-using-firebase/25"  class="markup--anchor markup--li-anchor" rel="noopener"    target="_blank">Facebook login in Ionic 4 with Firebase</a></li><li name="97f4" class="graf graf--li graf-after--li"><a href="https://medium.com/enappd/using-geolocation-and-beacon-plugins-in-ionic-4-754b41304007"  class="markup--anchor markup--li-anchor"    target="_blank">Geolocation</a> in Ionic 4</li><li name="34a6" class="graf graf--li graf-after--li"><a href="https://medium.com/enappd/qr-code-scanning-and-optical-character-recognition-ocr-in-ionic-4-95fd46be91dd"  class="markup--anchor markup--li-anchor"    target="_blank">QR Code and scanners</a> in Ionic 4 and</li><li name="de81" class="graf graf--li graf-after--li"><a href="https://medium.com/enappd/how-to-translate-in-ionic-4-globalization-internationalization-and-localization-31ec5807a8bc"  class="markup--anchor markup--li-anchor"    target="_blank">Translations in Ionic 4</a></li></ul><p name="2930" class="graf graf--p graf-after--li">If you need a base to start your next Ionic 4 app, you can make your next awesome app using <a href="https://store.enappd.com/product/ionic-4-full-app/"  class="markup--anchor markup--p-anchor" rel="noopener nofollow noopener noopener nofollow noopener noopener nofollow noopener noopener noopener noopener noopener noopener noopener noopener"    target="_blank">Ionic 4 Full App</a></p><figure tabindex="0" contenteditable="false" name="89dc" class="graf graf--figure graf-after--p"><div class="aspectRatioPlaceholder is-locked" style="max-width: 700px; max-height: 442px;"><div class="aspectRatioPlaceholder-fill" style="padding-bottom: 63.2%;"></div><img class="graf-image" data-image-id="1*2BzL8TesnBHuazHr3VA4SQ.jpeg" data-width="760" data-height="480" src="https://cdn-images-1.medium.com/max/720/1*2BzL8TesnBHuazHr3VA4SQ.jpeg"><div class="crosshair u-ignoreBlock"></div></div><br/><figcaption class="imageCaption" contenteditable="true" data-default-value="Type caption for image (optional)">Use Ionic 4 Full app template for your next awesome&nbsp;app</figcaption></figure><p name="099a" class="graf graf--p graf--empty graf-after--figure graf--trailing"><br></p></div></div></section></div></article></main>