└── tutorials └── frontend ├── lit-element ├── teaser.adoc ├── article.properties ├── 05-pwa-and-offline │ ├── images │ │ ├── sw-offline.gif │ │ └── persisted-state.gif │ └── content.adoc ├── 01-starting-a-lit-element-project │ ├── images │ │ ├── todo-app.gif │ │ ├── starter-app.png │ │ └── first-component.png │ └── content.adoc ├── 04-navigation-and-code-splitting │ ├── images │ │ ├── stats-view.gif │ │ ├── lazy-load-bundle.gif │ │ └── webpack-output.png │ └── content.adoc ├── 03-state-management-with-redux │ ├── images │ │ ├── redux-dev-tools.png │ │ └── redux-finished-app.gif │ └── content.adoc └── 02-lit-element-templating-properties-and-events │ ├── images │ ├── styled.png │ ├── filters.gif │ ├── add-tasks.gif │ └── task-input.png │ └── content.adoc └── topic.properties /tutorials/frontend/lit-element/teaser.adoc: -------------------------------------------------------------------------------- 1 | // A teaser for the whole article 2 | -------------------------------------------------------------------------------- /tutorials/frontend/topic.properties: -------------------------------------------------------------------------------- 1 | # meta data per topic, likely some description 2 | -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/article.properties: -------------------------------------------------------------------------------- 1 | # Article properties, likely a title and a description 2 | -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/05-pwa-and-offline/images/sw-offline.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peholmst/learning-content/HEAD/tutorials/frontend/lit-element/05-pwa-and-offline/images/sw-offline.gif -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/05-pwa-and-offline/images/persisted-state.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peholmst/learning-content/HEAD/tutorials/frontend/lit-element/05-pwa-and-offline/images/persisted-state.gif -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/01-starting-a-lit-element-project/images/todo-app.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peholmst/learning-content/HEAD/tutorials/frontend/lit-element/01-starting-a-lit-element-project/images/todo-app.gif -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/04-navigation-and-code-splitting/images/stats-view.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peholmst/learning-content/HEAD/tutorials/frontend/lit-element/04-navigation-and-code-splitting/images/stats-view.gif -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/01-starting-a-lit-element-project/images/starter-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peholmst/learning-content/HEAD/tutorials/frontend/lit-element/01-starting-a-lit-element-project/images/starter-app.png -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/03-state-management-with-redux/images/redux-dev-tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peholmst/learning-content/HEAD/tutorials/frontend/lit-element/03-state-management-with-redux/images/redux-dev-tools.png -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/01-starting-a-lit-element-project/images/first-component.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peholmst/learning-content/HEAD/tutorials/frontend/lit-element/01-starting-a-lit-element-project/images/first-component.png -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/03-state-management-with-redux/images/redux-finished-app.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peholmst/learning-content/HEAD/tutorials/frontend/lit-element/03-state-management-with-redux/images/redux-finished-app.gif -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/04-navigation-and-code-splitting/images/lazy-load-bundle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peholmst/learning-content/HEAD/tutorials/frontend/lit-element/04-navigation-and-code-splitting/images/lazy-load-bundle.gif -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/04-navigation-and-code-splitting/images/webpack-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peholmst/learning-content/HEAD/tutorials/frontend/lit-element/04-navigation-and-code-splitting/images/webpack-output.png -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/02-lit-element-templating-properties-and-events/images/styled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peholmst/learning-content/HEAD/tutorials/frontend/lit-element/02-lit-element-templating-properties-and-events/images/styled.png -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/02-lit-element-templating-properties-and-events/images/filters.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peholmst/learning-content/HEAD/tutorials/frontend/lit-element/02-lit-element-templating-properties-and-events/images/filters.gif -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/02-lit-element-templating-properties-and-events/images/add-tasks.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peholmst/learning-content/HEAD/tutorials/frontend/lit-element/02-lit-element-templating-properties-and-events/images/add-tasks.gif -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/02-lit-element-templating-properties-and-events/images/task-input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peholmst/learning-content/HEAD/tutorials/frontend/lit-element/02-lit-element-templating-properties-and-events/images/task-input.png -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/01-starting-a-lit-element-project/content.adoc: -------------------------------------------------------------------------------- 1 | = Creating a LitElement project 2 | 3 | :title: Creating a LitElement project 4 | :authors: marcus 5 | :type: text, video 6 | :topic: frontend 7 | :tags: LitElement, templating 8 | :description: Learn how to set up a new project with LitElement 9 | :repo: https://github.com/vaadin-learning-center/lit-element-tutorial-01-starting-a-lit-element-project 10 | :linkattrs: 11 | :imagesdir: ./images 12 | 13 | 14 | In this series of tutorials, you learn how to build an application using Web Components and LitElement. The topics we cover are: 15 | 16 | . Starting a LitElement project 17 | . lit-html templating and events 18 | . State management with Redux 19 | . Navigation and code splitting 20 | . PWA and offline 21 | 22 | .The app we are building 23 | image::todo-app.gif[Todo tutorial app using LitElement, lit-html, and redux.] 24 | 25 | 26 | == Download the LitElement starter 27 | We are using https://webpack.js.org/[Webpack^] to serve the application during development and for building the application for production. This tutorial does not cover Webpack configuration. Instead, we start with a pre-configured project skeleton. 28 | 29 | 30 | https://github.com/vaadin-learning-center/lit-element-tutorial-00-starter/archive/master.zip[Download LitElement starter, role="cta"] 31 | 32 | Once you have downloaded the starter, unzip it and run: 33 | 34 | [source,terminal] 35 | $ npm install 36 | 37 | Then start the development server and navigate to http://localhost:8080. 38 | 39 | [source,terminal] 40 | $ npm run dev 41 | 42 | image::starter-app.png[Empty starter app running on localhost] 43 | 44 | If everything went well, you should see the empty application. You are now ready to get started! 45 | 46 | == Creating the first component 47 | 48 | Start by installing LitElement. 49 | 50 | [source,terminal] 51 | $ npm install --save @polymer/lit-element 52 | 53 | Create a new folder `*views*` in the `*src*` folder, and create a file `*todo-view.js*` in it. We always name our files the same as their HTML tag names to make it easier to navigate the source. 54 | 55 | .`*views/todo-view.js*` 56 | [source,javascript] 57 | ---- 58 | import { LitElement, html } from '@polymer/lit-element'; //<1> 59 | 60 | class TodoView extends LitElement { //<2> 61 | render() { 62 | return html` //<3> 63 |

todo-view

64 | `; 65 | } 66 | } 67 | 68 | customElements.define('todo-view', TodoView); //<4> 69 | ---- 70 | <1> Import the `LitElement` base class and `html` template function 71 | <2> Create a class for the component, extending `LitElement` 72 | <3> Define a template in the `render()` function using the `html` template function. 73 | <4> Associate the component implementation with a HTML tag using the CustomElements registry. 74 | 75 | NOTE: Tag names need to have a dash (-) to avoid naming collisions with native HTML elements. 76 | 77 | Once we have a component definition, we need to import it to the browser is aware of it. The Webpack configuration takes care of including the JavaScript in our app. 78 | 79 | .`*index.js*` 80 | [source,javascript] 81 | ---- 82 | import './styles.css'; 83 | import './views/todo-view.js'; 84 | ---- 85 | 86 | Now we can use the component like any other HTML tag. Let's add it to the `
` section of the index file. 87 | 88 | .`*index.html*` 89 | [source,html] 90 | ---- 91 | ... 92 |
93 | 94 |
95 | ... 96 | ---- 97 | 98 | NOTE: Custom elements need to have a closing tag. 99 | 100 | If you still have the development server (`npm run dev`) running, you should see the new component running: 101 | 102 | image::first-component.png[LitElement running in the application] 103 | 104 | https://github.com/learn-vaadin/lit-element-tutorial-01-starting-a-lit-element-project[Browse the finished code on GitHub, role="cta"] 105 | 106 | == Next 107 | 108 | In the next tutorial, we will implement the todo view. 109 | -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/05-pwa-and-offline/content.adoc: -------------------------------------------------------------------------------- 1 | = PWA and offline 2 | 3 | :title: PWA and offline 4 | :authors: marcus 5 | :type: text, video 6 | :topic: frontend 7 | :tags: LitElement, PWA, offline, webpack 8 | :description: Building and serving a LitElement project in production as a PWA. 9 | :repo: https://github.com/vaadin-learning-center/lit-element-tutorial-05-pwa-and-offline 10 | :linkattrs: 11 | :imagesdir: ./images 12 | 13 | In the first four tutorials in this series, we've built an app with LitElement, using Redux for state management, Vaadin Router for navigation and Webpack for building and code splitting. 14 | 15 | In this final tutorial, we turn the application into an offline-capable Progressive Web App. 16 | 17 | If you didn't do the previous steps of the tutorial, you can check out the code from the previous step as a starter: 18 | 19 | https://github.com/learn-vaadin/lit-element-tutorial-04-navigation-and-code-splitting[Source code for step 4, role="cta"] 20 | 21 | TIP: You can find out more about Progressive Web Apps on Vaadin's https://vaadin.com/pwa[PWA page^]. 22 | 23 | 24 | == Adding a Web App Manifest 25 | The first step in turning an app into a PWA is adding a manifest file to identify the app to the browser. 26 | 27 | In the `src` folder, create a file `manifest.webmanifest`: 28 | 29 | .`*src/manifest.webmanifest*` 30 | [source,json] 31 | ---- 32 | { 33 | "name": "Todo App", 34 | "short_name": "Todo", 35 | "start_url": ".", 36 | "display": "standalone", 37 | "background_color": "#2A3443", 38 | "description": "LitElement tutorial", 39 | "theme_color": "#2A3443", 40 | "icons": [ 41 | { 42 | "src": "./img/icons/icon-192x192.png", 43 | "sizes": "192x192", 44 | "type": "image/png" 45 | }, 46 | { 47 | "src": "./img/icons/icon-512x512.png", 48 | "sizes": "512x512", 49 | "type": "image/png" 50 | } 51 | ] 52 | } 53 | ---- 54 | 55 | The manifest file collects all the relevant info about your app into a single file. Link the file from `index.html`: 56 | 57 | .`*src/index.html*` 58 | [source,diff] 59 | ---- 60 | 61 | 62 | 63 | 64 | Todo 65 | + 66 | ---- 67 | 68 | Add the manifest file to the list of files Webpack copies over during the build: 69 | 70 | .`*webpack.config.js*` 71 | [source,diff] 72 | ---- 73 | const assets = [ 74 | { 75 | from: 'src/img', 76 | to: 'img/' 77 | }, 78 | + 'src/manifest.webmanifest' 79 | ]; 80 | ---- 81 | 82 | == Adding a ServiceWorker 83 | The second step in turning an app into a PWA is adding a ServiceWorker. The ServiceWorker is a script that sits between your app and the network that can be used to cache and serve resources, so the app loads fast and works reliably regardless of the network conditions. 84 | 85 | In this project, we are using https://developers.google.com/web/tools/workbox/[Workbox^] for generating the service worker. It is a widely used library for building production-grade ServiceWorkers. The project Webpack configuration uses the Workbox plugin to automatically generate a ServiceWorker that caches and serves all the static assets. 86 | 87 | Open `sw.js` in the `src` folder. 88 | 89 | .`*src/sw.js*` 90 | [source,javascript] 91 | ---- 92 | if ('workbox' in self) { 93 | workbox.precaching.precacheAndRoute(self.__precacheManifest || []); 94 | } 95 | ---- 96 | 97 | Webpack only adds a ServiceWorker when running the `prod` or `dev:sw` scripts. Detect whether or not workbox is loaded. If it is, call `precacheAndRoute` with `self.__precacheManifest` which is an array of assets generated by the build script. 98 | 99 | Load the ServiceWorker file in `index.js`: 100 | 101 | .`*src/sw.js*` 102 | [source,diff] 103 | ---- 104 | window.addEventListener('load', () => { 105 | initRouter(); 106 | + registerSW(); 107 | }); 108 | ---- 109 | 110 | .`*src/sw.js*` 111 | [source,javascript] 112 | ---- 113 | async function registerSW() { 114 | if ('serviceWorker' in navigator) { //<1> 115 | try { 116 | await navigator.serviceWorker.register('./sw.js'); //<2> 117 | } catch (e) { 118 | console.log('ServiceWorker registration failed. Sorry about that.', e); 119 | } 120 | } else { 121 | console.log('Your browser does not support ServiceWorker.'); 122 | } 123 | } 124 | ---- 125 | <1> Ensure that the browser supports ServiceWorker before trying to register it. 126 | <2> Register the ServiceWorker. Note that the path of the ServiceWorker determines its scope. 127 | 128 | Start the app with the ServiceWorker enabled, and you should see the loaded ServiceWorker in the "Application" tab of DevTools. You should also be able to go offline and refresh the page and verify that the app still loads. 129 | 130 | [source, terminal] 131 | $ npm run dev:sw 132 | 133 | .Going offline 134 | image::sw-offline.gif[Going offline] 135 | 136 | 137 | == Saving the state to localstorage 138 | The application can now start offline, but it doesn't persist the todos between runs. 139 | 140 | Because the state of the application is in a central Redux store, we have a clean way of persisting and loading the state in localstorage. 141 | 142 | Start by adding functions for saving and loading the state in `store.js`. 143 | 144 | .`*src/redux/store.js*` 145 | [source,javascript] 146 | ---- 147 | const STORAGE_KEY = '__todo_app__'; 148 | 149 | const saveState = state => { 150 | localStorage.setItem(STORAGE_KEY, JSON.stringify(state)); 151 | }; 152 | 153 | const loadState = () => { 154 | const json = localStorage.getItem(STORAGE_KEY); 155 | return json ? JSON.parse(json) : undefined; 156 | }; 157 | ---- 158 | 159 | Then, load the state from localstorage when creating the store: 160 | 161 | .`*src/redux/store.js*` 162 | [source,diff] 163 | ---- 164 | export const store = createStore( 165 | reducer, 166 | + loadState(), 167 | window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() 168 | ); 169 | ---- 170 | 171 | Finally, subscribe to the store to call `saveState` on any state changes. 172 | 173 | .`*src/redux/store.js*` 174 | [source,javascript] 175 | ---- 176 | store.subscribe(() => { 177 | saveState(store.getState()); 178 | }); 179 | ---- 180 | 181 | Now, if you rerun the application, you should be able to see the application state persists between refreshes. 182 | 183 | .State persisted between refreshes 184 | image::persisted-state.gif[State persisted between refreshes] 185 | 186 | == Conclusion 187 | This five-part tutorial has walked you through building a PWA with LitElement and Redux. 188 | 189 | You can find the finished code in GitHub: 190 | 191 | https://github.com/learn-vaadin/lit-element-tutorial-05-pwa-and-offline[Source code for this tutorial, role="cta"] 192 | 193 | == Further reading 194 | Here are some helpful resources for continued learning. 195 | 196 | * https://lit-element.polymer-project.org/[LitElement^] 197 | * https://lit-html.polymer-project.org/[lit-html^] 198 | * https://pwa-starter-kit.polymer-project.org/[PWA Starter Kit^] 199 | * https://redux.js.org/[Redux docs^] 200 | * https://developers.google.com/web/tools/workbox/guides/get-started[Workbox guide^] 201 | * https://webpack.js.org/concepts/[Webpack docs^] 202 | 203 | == Let us know what you think! 204 | As always, if you have questions or suggestions, feel free to comment below! -------------------------------------------------------------------------------- /tutorials/frontend/lit-element/04-navigation-and-code-splitting/content.adoc: -------------------------------------------------------------------------------- 1 | = Navigation and code splitting in a LitElement project 2 | 3 | :title: Navigation and code splitting in a LitElement project 4 | :authors: marcus 5 | :type: text, video 6 | :topic: frontend 7 | :tags: LitElement, navigation, webpack, code splitting 8 | :description: This tutorial teaches you how to do navigation and code splitting in a LitElement based project. 9 | :repo: https://github.com/vaadin-learning-center/lit-element-tutorial-04-navigation-and-code-splitting 10 | :linkattrs: 11 | :imagesdir: ./images 12 | 13 | So far in this tutorial series, we have built an app with LitElement and connected it to a Redux store for state management. In this tutorial, we add a new view for stats to learn how to navigate between views and how to split code for performance. 14 | 15 | If you didn't do the previous steps of the tutorial, you can download the source from the previous step as a starter: 16 | 17 | https://github.com/learn-vaadin/lit-element-tutorial-03-state-management-with-redux[Source code for step 3, role="cta"] 18 | 19 | == Install dependencies 20 | 21 | We use https://vaadin.com/router[Vaadin Router^] for navigation and https://vaadin.com/charts[Vaadin Charts^] to display stats. 22 | 23 | [source,terminal] 24 | $ npm install --save @vaadin/router @vaadin/vaadin-charts 25 | 26 | NOTE: Vaadin Charts is a commercial charting library. You can try it free for 30 days by having a vaadin.com account. + 27 | + 28 | You can also complete this tutorial without installing it by showing textual statistics on the stats view. 29 | 30 | == Set up the router 31 | Vaadin router needs an outlet where it can display the views. Update `index.html` to remove the hard-coded `` and add a new `