making-of.md 6.07 KB
Newer Older
1 2
# Making of this url shortener

Marc BOUVIER's avatar
Marc BOUVIER committed
3 4 5 6
https://u.baldir.fr is a static URL shortener. It means it is generated and 
served on a simple HTTP server (in our case NGinx). The links shortened will be 
added as yaml files pushed to a Git repo. Then a Gitlab CI will build and deploy
changes on a static http server (for my case through SSH on a Linode)
7 8 9

## Install gridsome cli & setup project

Marc BOUVIER's avatar
Marc BOUVIER committed
10 11 12 13
In my setup, I develop and deploy on the same machine. In a more traditional 
setup, an artefact would be generated during the build and then deployed 
remotely.

14 15 16 17 18 19 20 21 22 23 24 25 26
Follow https://gridsome.org/docs/#prerequisites

```bash
yarn global add @gridsome/cli
gridsome create u.baldir.fr
cd u.baldir.fr
# Test if it is working
gridsome develop
# go to http://localhost:8080 and http://localhost:8080/___explore (graphql)
```

## Install plugins

Marc BOUVIER's avatar
Marc BOUVIER committed
27 28 29
We want to add an entry for each url to shorten as a yaml file.
Gridsome wil read all `*.yml` files from `content/links` and convert it as a 
GraphQL collection. Then, we will use the collection in our vue components.
30

Marc BOUVIER's avatar
Marc BOUVIER committed
31 32 33
We need to install 
[`@gridsome/source-filesystem`](https://gridsome.org/plugins/@gridsome/source-filesystem) 
plugin.
34 35 36 37 38 39 40

```bash
yarn add @gridsome/source-filesystem
# or if you ar using npm
npm install @gridsome/source-filesystem
```

Marc BOUVIER's avatar
Marc BOUVIER committed
41 42 43
We also need to install a yaml transformer: 
[`@gridsome/transformer-yaml`](https://gridsome.org/plugins/@gridsome/transformer-yaml)

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
```bash
yarn add @gridsome/transformer-yaml
# or if you ar using npm
npm install @gridsome/transformer-yaml
```

## Configure plugin

In [`gridsome.config.js`](gridsome.config.js) change to the following

```json
module.exports = {
  siteName: 'u.baldir.fr',
  siteDescription: 'Baldir.fr url shortener',

  plugins: [
    {
      // Create posts from markdown files
      use: '@gridsome/source-filesystem',
      options: {
        typeName: 'Url',
        path: 'content/links/*.yml',
        route: '/:tinyUrl'
      }
    }

  ]
}
```

Marc BOUVIER's avatar
Marc BOUVIER committed
74 75
This will create a GraphQL collection `allUrl()` and also a vue Route that will 
use the property `tinyUrl` as part of the Url.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128

Create a folder to host the content : `content/links` 

Create the file `content/links/google.yml`

```yaml
tinyUrl: "google"
destinationUrl: "https://google.fr"
description: "A famous search engine"
```

Create the file `content/links/yahoo.yml`

```yaml
tinyUrl: "yahoo"
destinationUrl: "https://yahoo.fr"
description: "Another search engine"
```

The route u.baldir.fr/google will lead to 404 page because there is no template yet for the type `Url`.

Though, we can test the graphQL data by going to `localhost:4000/___explore`

Test the following query : 

```
 query {
  allUrl{
    totalCount
    edges{
      node{
        id
        path
        fileInfo{name}
        tinyUrl
        destinationUrl
      }
    }
  }
  url: url(path: "/content/links/google/"){
    id
        path
        fileInfo{name}
        tinyUrl
        destinationUrl
  }
}
```

## Create a template

Now we want a template to be applied to the site for the route we defined.

Marc BOUVIER's avatar
Marc BOUVIER committed
129 130
Create the file `src/templates/Url.vue`. Note that it matches the typeName we 
defined earlier.
131

Marc BOUVIER's avatar
Marc BOUVIER committed
132
```xml
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
<template>
  <Layout>
    <div>
    Redirecting to {{$page.url.destinationUrl}}...
    </div>
  </Layout>
</template>

<script>

export default {

  mounted(){
    window.location=this.$page.url.destinationUrl
  }

}
</script>

<page-query>
query Url ($path: String!) {
  url: url(path: $path){
        tinyUrl
        destinationUrl
  }
}
</page-query>
```

Marc BOUVIER's avatar
Marc BOUVIER committed
162 163
This template uses the data from graphQL query and redirects to the destination 
URL.
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178

Try it : localhost:4000/google

## Cleaning up

remove the files
 * src/layouts/README.md
 * src/pages/About.vue
 * src/pages/README.md
 * src/templates/README.md

 ## Make the index as a list of all short links

Modify `src/pages/index.vue` with the following.

Marc BOUVIER's avatar
Marc BOUVIER committed
179
 ```xml
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
<template>
  <div>
  <h1>Shortened URLS</h1>
    <ul>
        <li v-for="edge in $page.urls.edges" :key="edge.node.id">
            <a :href="edge.node.destinationUrl">{{edge.node.tinyUrl}}</a>({{edge.node.destinationUrl}}) : {{edge.node.description}}
        </li>
    </ul>
  </div>
</template>

<page-query>
{
  urls: allUrl(sort: [{by: "edges.nodes.tinyUrl", order: ASC}]) {
    edges {
      node {
        tinyUrl
        destinationUrl
        description
      }
    }
  }
}
</page-query>
Marc BOUVIER's avatar
doc  
Marc BOUVIER committed
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
 ```

 ## Automate deployment with Gitlab

 .gitlab-ci.yml

 ```
image: ubuntu:18.04

before_script:
  - 'apt-get update -y && apt-get install openssh-client -y && apt-get install sshpass'

build1:
  stage: build
  script:
    - sshpass -p "$server_ssh_secret" ssh -o StrictHostKeyChecking=no "$server_ssh_user@$server_ssh_url" 'cd /home/marc/sources/u.baldir.fr && git checkout master && git fetch origin && git reset --hard origin/HEAD && git pull && gridsome build'
 ```

Marc BOUVIER's avatar
Marc BOUVIER committed
222 223 224
The previous script checkout latest version from github repository and then 
builds static content with gridsome CLI.

Marc BOUVIER's avatar
doc  
Marc BOUVIER committed
225 226 227 228 229
 Set variables in your gitlab project
 * $server_ssh_secret : your ssh password
 * $server_ssh_user : your ssh user
 * $server_ssh_url : url of the server

Marc BOUVIER's avatar
Marc BOUVIER committed
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
## Alternative deployment automation

Alternatively, we could create an artifact from generated `dist` folder and 
store it as a zip file in an artifact repository. Then the CI can trigger 
this artifact to be downloaded (for instance with a ssh command) and deflated 
in the appropriate location of the HTTP server.

## Nginx configuration

No need for rewrite configuration in NGinx, it is managed by VueJs. It works 
out of the box even if we use HTTPS.

```
server {
    server_name  u.baldir.fr;

    location / {
        root   /home/marc/sources/u.baldir.fr/dist;
        index  index.html;
    }
     
    error_page  404              /404.html;

    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/u.baldir.fr/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/u.baldir.fr/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
```

 

Marc BOUVIER's avatar
doc  
Marc BOUVIER committed
268