{"id":21626,"date":"2017-11-20T20:51:09","date_gmt":"2017-11-20T20:51:09","guid":{"rendered":"http:\/\/getting_started_with_stenciljs"},"modified":"2017-11-20T20:51:09","modified_gmt":"2017-11-20T20:51:09","slug":"getting_started_with_stenciljs","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs","title":{"rendered":"Getting Started with StencilJS"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p><a href=\"https:\/\/stenciljs.com\">StencilJS<\/a> is a new compiler for composing user interfaces using pure custom components. Stencil enables you to build components using new, cutting-edge technologies, such as TypeScript and JSX, then generates a pure <a href=\"http:\/\/robdodson.me\/why-web-components\/\">custom component<\/a> that can be used anywhere supported. This means you can import a Stencil generated component into React, Angular, Vue, etc.<\/p>\n<h2>Background<\/h2>\n<p>Stencil is basically a compiler, not necessarily a UI library. A compiler that transforms TSX (TypeScript + JSX) into self-contained custom components.<\/p>\n<p>Before you start learning about the tool, it\u2019s important to note that Stencil is not another heavy JavaScript framework you need to learn. If you have worked with Angular or React, or understand web components, then Stencil is worth a look.<\/p>\n<p>Stencil enables you to write some TSX and SCSS, which it compiles down into shippable components. It was built by the Ionic team to help them write smaller, reusable components without having to carry along the weight of Angular. However, this led to solving a more general problem. We can write platform-independent component with our favorite tools (TS, JSX, etc) and compile to standard custom components which can then be used with any framework and supporting browsers.  All features of Stencil boil down to optimization and performance, which is the motivation behind Stencil.<\/p>\n<p>Stencil also provides a lot of progressive features out of the box, including easy server-side rendering and service worker installation. Now let\u2019s take a look at a practical approach to using Stencil and some of its interesting features.<\/p>\n<h2>Installing Stencil<\/h2>\n<p>Even Stencil\u2019s installation is simple. You can clone a starter template from GitHub and install the npm dependencies. No major configuration, just clone, install and run.<\/p>\n<p>Clone the repository from GitHub to your machine:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\"># Clone starter<\/span>\ngit <span class=\"hljs-keyword\">clone<\/span> https:<span class=\"hljs-comment\">\/\/github.com\/ionic-team\/stencil-starter.git todo<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Install the dependencies:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\"># Enter the cloned project<\/span>\ncd todo\n\n<span class=\"hljs-comment\"># Install dependencies<\/span>\nnpm install\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You can start the app at port <code>3333<\/code> using the following command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npm start\n<\/code><\/span><\/pre>\n<p>All our component code will be written in <code>src\/components<\/code>. You can ignore the <code>my-name<\/code> starter component, since we will remove it from the face of the project.<\/p>\n<h2>Creating Components<\/h2>\n<p>Each component is saved in a containing folder, such as a TSX file. The containing folder also can contain an SCSS file for the component\u2019s styles.<\/p>\n<p>Let\u2019s start with a container component that will serve as the app\u2019s shell. Create a folder named <code>site<\/code> in the <code>components<\/code> folder, then add <code>site.tsx<\/code> and <code>site.scss<\/code> files in the folder. You just created an empty Stencil component.<\/p>\n<p>Throughout the article, we will skip the SCSS contents for brevity. You can grab them from the <a href=\"https:\/\/github.com\/christiannwamba\/stencil-gs\">GitHub repo provided<\/a>. With that in mind, let\u2019s add some component content:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ components\/site\/site.tsx<\/span>\n<span class=\"hljs-keyword\">import<\/span> { Component } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@stencil\/core'<\/span>;\n\n@Component({\n  <span class=\"hljs-attr\">tag<\/span>: <span class=\"hljs-string\">'todo-site'<\/span>,\n  <span class=\"hljs-attr\">styleUrl<\/span>: <span class=\"hljs-string\">'site.scss'<\/span>\n})\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Site<\/span> <\/span>{\n  \n  render() {\n    <span class=\"hljs-keyword\">return<\/span> (\n      <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"wrapper\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">nav<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"container\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span>&gt;<\/span>To - Do<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">nav<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"container\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"row\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"col-md-offset-4 col-md-4 col-sm 12\"<\/span>&gt;<\/span>\n\t\t\t\t{\/* Todo App goes here *\/}\n\t\t\t\t\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n    );\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<ul>\n<li>The <code>Component<\/code> decorator &#8211; which is imported from <code>@stencil\/core<\/code>  &#8211; defines a class as a component.<\/li>\n<li>The <code>Site<\/code> class, which is decorated with the <code>Component<\/code> decorator, gets extended by the decorator to posses component features.<\/li>\n<li>One of these features is having a tag, a style and a template. The tag and style is defined using an object and passing the object as argument to the decorator. The <code>render<\/code> method returns <a href=\"https:\/\/jsx.github.io\/\">JSX<\/a>, which serves as the template for the component. This template is what gets rendered to the browser when the component is mounted.<\/li>\n<\/ul>\n<p>The tag is used to mount the component. In this case, replace <code>my-name<\/code> tag in <code>index.html<\/code> with the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">todo-site<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">todo-site<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Then run the app using <code>npm start<\/code>. You should get the following:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-res.cloudinary.com\/image\/upload\/w_700,c_fill\/dpr_auto\/getting-started-with-stencil_jbni1b.png\" alt=\"StencilJS\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1400\" height=\"1159\"\/><\/p>\n<h2>Composing Hierarchical Components<\/h2>\n<p>Just like every other scenario in which you used components, Stencil components can be composed with each other. This is the beauty of web components. A component can have multiple children and grandchildren, as well as siblings. This enables you to write small, self-contained components that can work with other smaller components and carry out a single task.<\/p>\n<p>As an example, let\u2019s create another component called <code>TodoList<\/code> and compose with the <code>Site<\/code> component. The former will be a child component to the latter.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ components\/todo-list\/todo-list.tsx<\/span>\n<span class=\"hljs-keyword\">import<\/span> { Component } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@stencil\/core'<\/span>;\n\n@Component({\n  <span class=\"hljs-attr\">tag<\/span>: <span class=\"hljs-string\">'todo-list'<\/span>,\n  <span class=\"hljs-attr\">styleUrl<\/span>: <span class=\"hljs-string\">'todo-list.scss'<\/span>\n})\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">TodoList<\/span> <\/span>{\n  \n  render() {\n    <span class=\"hljs-keyword\">return<\/span> (\n      <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"todo-list\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span>&gt;<\/span>Write some code<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n    );\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Same syntax with the <code>Site<\/code> component, with different names and visuals. Let\u2019s now add the component to the parent <code>Site<\/code> component:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Site<\/span> <\/span>{\n  render() {\n    <span class=\"hljs-keyword\">return<\/span> (\n      <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"wrapper\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">nav<\/span>&gt;<\/span>\n          ...\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">nav<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"container\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"row\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"col-md-offset-4 col-md-4 col-sm 12\"<\/span>&gt;<\/span>\n              {\/* Child component, TodoList *\/}\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">todo-list<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">todo-list<\/span>&gt;<\/span>\n              \n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n    );\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We don\u2019t have to import the component child class to the parent class. We only need to include the <code>todo-list<\/code> tag and then Stencil looks up the component in the <code>components<\/code> folder and loads it accordingly.<\/p>\n<h2>States and Props<\/h2>\n<p>So far, we have just been dealing with static contents and markup. Most components you will write in Stencil will be useless if they do not handle dynamic contents and markup. States and Props decorators are used to bring life to Stencil components.<\/p>\n<h3>States<\/h3>\n<p>A state is a mutable chunk of data defined in a component. After initialization, it can be overwritten, deleted and updated to fit the needs of a component. A state is basically a class property decorated with the <code>State<\/code> decorator:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { Component, State } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@stencil\/core'<\/span>;\n\n@Component({\n  <span class=\"hljs-attr\">tag<\/span>: <span class=\"hljs-string\">'todo-site'<\/span>,\n  <span class=\"hljs-attr\">styleUrl<\/span>: <span class=\"hljs-string\">'site.scss'<\/span>\n})\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Site<\/span> <\/span>{\n  \n  <span class=\"hljs-comment\">\/\/ todos as a state<\/span>\n  @State() todos: Todo&#91;] = &#91;\n    {<span class=\"hljs-attr\">task<\/span>: <span class=\"hljs-string\">'Cook'<\/span>, <span class=\"hljs-attr\">completed<\/span>: <span class=\"hljs-literal\">false<\/span>},\n    {<span class=\"hljs-attr\">task<\/span>: <span class=\"hljs-string\">'Dance'<\/span>, <span class=\"hljs-attr\">completed<\/span>: <span class=\"hljs-literal\">true<\/span>},\n    {<span class=\"hljs-attr\">task<\/span>: <span class=\"hljs-string\">'Eat'<\/span>, <span class=\"hljs-attr\">completed<\/span>: <span class=\"hljs-literal\">false<\/span>}\n  ];\n\n  render() {\n    <span class=\"hljs-keyword\">return<\/span> (\n      <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"wrapper\"<\/span>&gt;<\/span>\n        ...\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"container\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"row\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"col-md-offset-4 col-md-4 col-sm 12\"<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">todo-list<\/span> <span class=\"hljs-attr\">todos<\/span>=<span class=\"hljs-string\">{this.todos}<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">todo-list<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n    );\n  }\n}\n\ninterface Todo {\n  <span class=\"hljs-attr\">task<\/span>: string;\n  completed: boolean;\n}\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The <code>todos<\/code> property is defined as a state and initialized with an array with three Todo objects. The object is typed as a <code>Todo<\/code> interface and has task (string) and completed (boolean) properties.<\/p>\n<p>A state, unlike props, can be updated at runtime, which makes them mutable. In our case, for example, we can add or remove tasks.<\/p>\n<p>The <code>todos<\/code> state is used in the component by passing it down to the <code>todo-list<\/code> component using props.<\/p>\n<h3>Props<\/h3>\n<p>Take another look on how we passed the array of todos to the <code>todo-list<\/code> component:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">todo-list<\/span> <span class=\"hljs-attr\">todos<\/span>=<span class=\"hljs-string\">{this.todos}<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">todo-list<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The <code>todos<\/code> property, which is passed the array of todo items is what is referred to as <code>props<\/code>.<\/p>\n<p>Before the <code>todo-list<\/code> component can receive values via <code>todos<\/code> props, it needs to be aware of the incoming values. In that case, we need to create a <code>todos<\/code> property on the component class and decorate the class using <code>Props<\/code>:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { Component, Prop } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@stencil\/core'<\/span>;\n\n@Component({\n  <span class=\"hljs-attr\">tag<\/span>: <span class=\"hljs-string\">'todo-list'<\/span>,\n  <span class=\"hljs-attr\">styleUrl<\/span>: <span class=\"hljs-string\">'todo-list.scss'<\/span>\n})\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">TodoList<\/span> <\/span>{\n\n  @Prop() todos: Todo&#91;];\n  \n  completedClass(todo: Todo) : string {\n    <span class=\"hljs-keyword\">return<\/span> todo.completed ? <span class=\"hljs-string\">'completed'<\/span> : <span class=\"hljs-string\">''<\/span>;\n  }\n  \n  render() {\n    <span class=\"hljs-keyword\">return<\/span> (\n      <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"todo-list\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n          {this.todos.map(todo =&gt; <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">{this.completedClass(todo)}<\/span> &gt;<\/span>{todo.task}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span>)}\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n    );\n  }\n}\n\ninterface Todo {\n  <span class=\"hljs-attr\">task<\/span>: string;\n  completed: boolean;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The property is defined as an array and typed with the Todo interface, as well. When the component receives this value, we iterate over each of the items in the array using <code>map<\/code> and display them in a <code>li<\/code> tag. There is a also a <code>completedClass<\/code> method, which returns <code>completed<\/code> or empty string if the <code>completed<\/code> property of the each todo is <code>true<\/code> or <code>false<\/code> respectively.<\/p>\n<blockquote>\n<p>There is a major difference between states and props. States are mutable and can be changed at runtime, while props will always retain the value it received throughout runtime. Props also are received as attributes via the component\u2019s tag.<\/p>\n<\/blockquote>\n<h2>Events and Listeners<\/h2>\n<p>Now we got the problem of dynamic content of the table, we need to worry about interaction. How do we create new tasks? What happens when each todo item is clicked? Let\u2019s answer those questions now.<\/p>\n<p>An event is raised when a user interacts with your component. We can create and emit custom events for such interactions. Events are raised with Event Emitters and are decorated with the <code>Event<\/code> decorator.<\/p>\n<p>Let\u2019s see some event logic by clicking on each item in the todo list:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { Component, Event, EventEmitter, Prop } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@stencil\/core'<\/span>;\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">TodoList<\/span> <\/span>{\n\n  @Prop() todos: Todo&#91;];\n  @Event() toggleTodo: EventEmitter;\n\n  ...\n \n  <span class=\"hljs-comment\">\/\/ Event handler. Triggered by onClick<\/span>\n  <span class=\"hljs-comment\">\/\/ DOM event on the template in render()<\/span>\n  handleToggleTodo(todo) {\n    <span class=\"hljs-keyword\">this<\/span>.toggleTodo.emit(todo)\n  }\n  \n  render() {\n    <span class=\"hljs-keyword\">return<\/span> (\n      <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"todo-list\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n          {this.todos.map(todo =&gt; <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">{this.completedClass(todo)}<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{this.handleToggleTodo.bind(this,<\/span> <span class=\"hljs-attr\">todo<\/span>)}&gt;<\/span>{todo.task}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span>)}\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n    );\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In the render method, you can see we have an <code>onClick<\/code> attribute attached to each <code>li<\/code> method in the <code>map<\/code> iteration. This attribute attaches a DOM event; a click event to be precise.<\/p>\n<p>When this button is clicked, the <code>handleToggleTodo<\/code> method is called with the right context while passing the actual todo item that was clicked.<\/p>\n<p>The <code>handleToggleTodo<\/code> method then emits a <strong>custom<\/strong> event. This custom event (<code>toggleTodo<\/code>) is decorated as <code>Event<\/code> and defined as <code>EventEmitter<\/code> type. Calling <code>emit<\/code> on the custom event triggers a global event that we can listen to from anywhere in the app.<\/p>\n<p>We can head to the parent component (Site) and create a listener for the event:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { Component, State, Listen } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@stencil\/core'<\/span>;\n...\nexport <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Site<\/span> <\/span>{\n  ...\n  @Listen(<span class=\"hljs-string\">'toggleTodo'<\/span>)\n  toggleTodo(e): <span class=\"hljs-keyword\">void<\/span> {\n    <span class=\"hljs-comment\">\/\/ Retrieve event payload<\/span>\n    <span class=\"hljs-comment\">\/\/ from e.detail<\/span>\n    <span class=\"hljs-keyword\">const<\/span> todo = e.detail;\n    <span class=\"hljs-keyword\">this<\/span>.todos = <span class=\"hljs-keyword\">this<\/span>.todos.map(<span class=\"hljs-function\"><span class=\"hljs-params\">x<\/span> =&gt;<\/span> {\n      <span class=\"hljs-keyword\">if<\/span> (x.task === todo.task) {\n        <span class=\"hljs-keyword\">const<\/span> updated = {\n          <span class=\"hljs-attr\">task<\/span>: x.task,\n          <span class=\"hljs-attr\">completed<\/span>: !x.completed\n        };\n        <span class=\"hljs-keyword\">return<\/span> updated;\n      }\n      <span class=\"hljs-keyword\">return<\/span> x;\n    })\n  }\n  ...\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The event listener is of course a decorated method. The method must be decorated with <code>Listener<\/code> and the decorator is passed the actual name of the emitter; in our case <code>toggleTodo<\/code>.<\/p>\n<blockquote>\n<p>The name of the method handling the event doesn\u2019t have to be the same as the event emitted. What is important is that the method is decorated and that the decorator is passed the name of the emitted event.<\/p>\n<\/blockquote>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-res.cloudinary.com\/image\/upload\/w_700,c_fill\/dpr_auto\/Screen_Shot_2017-09-25_at_6.24.09_AM_vzbgkv.png\" alt=\"StencilJS\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1400\" height=\"1159\"\/><\/p>\n<h3>Creating New Todos<\/h3>\n<p>You have learned so much about Stencil and Stencil components. Before we conclude, let\u2019s add another component that we can use to add more todo items to the todo list:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ components\/todo-form\/todo-form.tsx<\/span>\n<span class=\"hljs-keyword\">import<\/span> { Component, Event, EventEmitter, State } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@stencil\/core'<\/span>;\n\n@Component({\n  <span class=\"hljs-attr\">tag<\/span>: <span class=\"hljs-string\">'todo-form'<\/span>,\n  <span class=\"hljs-attr\">styleUrl<\/span>: <span class=\"hljs-string\">'todo-form.scss'<\/span>\n})\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">TodoForm<\/span> <\/span>{\n\n  @Event() newTodo: EventEmitter;\n  @State() todo: string;\n\n\n  handleChange(e) {\n    <span class=\"hljs-keyword\">this<\/span>.todo = (e.target <span class=\"hljs-keyword\">as<\/span> HTMLTextAreaElement).value;\n  }\n\n  handleNewTodo() {\n    <span class=\"hljs-keyword\">this<\/span>.newTodo.emit(<span class=\"hljs-keyword\">this<\/span>.todo);\n    <span class=\"hljs-keyword\">this<\/span>.todo = <span class=\"hljs-string\">''<\/span>;\n  }\n\n  render() {\n    <span class=\"hljs-keyword\">return<\/span> (\n      <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"todo-form\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"form-control\"<\/span> <span class=\"hljs-attr\">placeholder<\/span>=<span class=\"hljs-string\">\"New Task\"<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{this.todo}<\/span> <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{this.handleChange.bind(this)}<\/span> \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{this.handleNewTodo.bind(this)}<\/span>&gt;<\/span>Add<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n    );\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Not so much a big difference from what we have dealt with in previous sections. Here are the obvious additions:<\/p>\n<ul>\n<li>We have an internal state property (<code>todo<\/code>) that tracks the text being entered in the input field. When the value changes, we set the value of the state property to the new value of the input field.<\/li>\n<li>There is a button that submits the current value of <code>todo<\/code> anytime the button is clicked. It does so by triggering a <code>handleNewTodo<\/code> method which in turn emits a <code>newTodo<\/code> custom event<\/li>\n<\/ul>\n<p>Back to the parent component, we can add a listener to update the list of todo items:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { Component, State, Listen } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@stencil\/core'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Site<\/span> <\/span>{\n  @State() todos: Todo&#91;] = &#91;\n    {<span class=\"hljs-attr\">task<\/span>: <span class=\"hljs-string\">'Cook'<\/span>, <span class=\"hljs-attr\">completed<\/span>: <span class=\"hljs-literal\">false<\/span>},\n    {<span class=\"hljs-attr\">task<\/span>: <span class=\"hljs-string\">'Dance'<\/span>, <span class=\"hljs-attr\">completed<\/span>: <span class=\"hljs-literal\">true<\/span>},\n    {<span class=\"hljs-attr\">task<\/span>: <span class=\"hljs-string\">'Eat'<\/span>, <span class=\"hljs-attr\">completed<\/span>: <span class=\"hljs-literal\">false<\/span>}\n  ];\n\n  @Listen(<span class=\"hljs-string\">'newTodo'<\/span>)\n  newTodo(e) {\n    <span class=\"hljs-keyword\">const<\/span> newTodo = {\n      <span class=\"hljs-attr\">task<\/span>: e.detail,\n      <span class=\"hljs-attr\">completed<\/span>: <span class=\"hljs-literal\">false<\/span>\n    };\n    <span class=\"hljs-keyword\">this<\/span>.todos = &#91;...this.todos, newTodo];\n  }\n ...\n render() {\n    <span class=\"hljs-keyword\">return<\/span> (\n      <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"wrapper\"<\/span>&gt;<\/span>\n        ...\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"container\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"row\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"col-md-offset-4 col-md-4 col-sm 12\"<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">todo-form<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">todo-form<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">todo-list<\/span> <span class=\"hljs-attr\">todos<\/span>=<span class=\"hljs-string\">{this.todos}<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">todo-list<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n    );\n  }\n}\n...\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<ul>\n<li>The <code>newTodo<\/code> method, which handles the custom event, updates the list of todos with the new task we added.<\/li>\n<li>We also added the form component in the render method: <code>&lt;todo-form&gt;&lt;\/todo-form&gt;<\/code>.<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-res.cloudinary.com\/image\/upload\/w_700,c_fill\/dpr_auto\/Screen_Shot_2017-09-25_at_6.45.20_AM_lrsizi.png\" alt=\"StencilJS\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1400\" height=\"1159\"\/><\/p>\n<h2>Conclusion<\/h2>\n<p>While we covered a lot of interesting Stencil concepts, there are many other features, such as routing, offline-first, SSR and more, to explore. As a matter of fact, to start building an offline experience, just run <code>npm build<\/code> to generate app builds with a service worker.<\/p>\n<p>You can head right to the <a href=\"https:\/\/stenciljs.com\/\">Stencil website<\/a> to learn more about these advanced features. Stencil has an <a href=\"https:\/\/stencil-worldwide.slack.com\">engaging Slack community<\/a> which you can be apart of to get help faster. You can also follow the <a href=\"https:\/\/twitter.com\/stenciljs\">Stencil team on Twitter<\/a> to get updates on the tool.  You also can get the demo from the <a href=\"https:\/\/github.com\/christiannwamba\/stencil-gs\">Github repo<\/a> and play with the examples you saw in this article.<\/p>\n<p><a href=\"https:\/\/cloudinary.com\">Cloudinary<\/a> enables you to manage (store, transform and deliver) media contents from the cloud. You can get started with the free plan that supports 300,000 images and videos and offload media assets management in your app to Cloudinary.<\/p>\n<p>In the next post we will discuss how to <a href=\"https:\/\/blog.ionicframework.com\/make-a-video-web-component-the-stencil-way\/\">Make a Video Web Component, the Stencil Way<\/a> with Cloudinary!<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":21627,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,177],"class_list":["post-21626","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-javascript"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Getting Started with StencilJS<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Getting Started with StencilJS\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2017-11-20T20:51:09+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723711\/Web_Assets\/blog\/StecilJS_2000x1100\/StecilJS_2000x1100.png?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"1540\" \/>\n\t<meta property=\"og:image:height\" content=\"847\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Getting Started with StencilJS\",\"datePublished\":\"2017-11-20T20:51:09+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs\"},\"wordCount\":4,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723711\/Web_Assets\/blog\/StecilJS_2000x1100\/StecilJS_2000x1100.png?_i=AA\",\"keywords\":[\"Guest Post\",\"Javascript\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2017\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs\",\"url\":\"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs\",\"name\":\"Getting Started with StencilJS\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723711\/Web_Assets\/blog\/StecilJS_2000x1100\/StecilJS_2000x1100.png?_i=AA\",\"datePublished\":\"2017-11-20T20:51:09+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723711\/Web_Assets\/blog\/StecilJS_2000x1100\/StecilJS_2000x1100.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723711\/Web_Assets\/blog\/StecilJS_2000x1100\/StecilJS_2000x1100.png?_i=AA\",\"width\":1540,\"height\":847},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Getting Started with StencilJS\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Getting Started with StencilJS","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs","og_locale":"en_US","og_type":"article","og_title":"Getting Started with StencilJS","og_url":"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs","og_site_name":"Cloudinary Blog","article_published_time":"2017-11-20T20:51:09+00:00","og_image":[{"width":1540,"height":847,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723711\/Web_Assets\/blog\/StecilJS_2000x1100\/StecilJS_2000x1100.png?_i=AA","type":"image\/png"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs"},"author":{"name":"","@id":""},"headline":"Getting Started with StencilJS","datePublished":"2017-11-20T20:51:09+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs"},"wordCount":4,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723711\/Web_Assets\/blog\/StecilJS_2000x1100\/StecilJS_2000x1100.png?_i=AA","keywords":["Guest Post","Javascript"],"inLanguage":"en-US","copyrightYear":"2017","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs","url":"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs","name":"Getting Started with StencilJS","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723711\/Web_Assets\/blog\/StecilJS_2000x1100\/StecilJS_2000x1100.png?_i=AA","datePublished":"2017-11-20T20:51:09+00:00","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723711\/Web_Assets\/blog\/StecilJS_2000x1100\/StecilJS_2000x1100.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723711\/Web_Assets\/blog\/StecilJS_2000x1100\/StecilJS_2000x1100.png?_i=AA","width":1540,"height":847},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/getting_started_with_stenciljs#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Getting Started with StencilJS"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723711\/Web_Assets\/blog\/StecilJS_2000x1100\/StecilJS_2000x1100.png?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/21626","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=21626"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/21626\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/21627"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=21626"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=21626"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=21626"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}