Let’s Make a QR Code Generator With a Serverless Function!

QR codes are funny, right? We love them, then hate them, then love them again. Anyways, they’ve lately been popping up again and it got me thinking about how they’re made. There are like a gazillion QR code generators out there, but say it’s something you need to do on your own website. This package can do that. But it’s also weighs in at a hefty 180 KB for everything it needs to generate stuff. You wouldn’t want to serve all that along with the rest of your scripts.

Now, I’m relatively new to the concept of cloud functions, but I hear that’s the bee’s knees for something just like this. That way, the function lives somewhere on a server that can be called when it’s needed. Sorta like a little API to run the function.

Some hosts offer some sort of cloud function feature. DigitalOcean happens to be one of them! And, like Droplets, functions are pretty easy to deploy.

Create a functions folder locally

DigitalOcean has a CLI that with a command that’ll scaffold things for us, so cd wherever you want to set things up and run:

doctl serverless init --language js qr-generator

Notice the language is explicitly declared. DigitalOcean functions also support PHP and Python.

We get a nice clean project called qr-generator with a /packages folder that holds all the project’s functions. There’s a sample function in there, but we can overlook it for now and create a qr folder right next to it:

That folder is where both the qrcode package and our qr.js function are going to live. So, let’s cd into packages/sample/qr and install the package:

npm install --save qrcode

Now we can write the function in a new qr.js file:

const qrcode = require('qrcode')

exports.main = (args) => {
  return qrcode.toDataURL(args.text).then(res => ({
    headers:  { 'content-type': 'text/html; charset=UTF-8' },
    body: args.img == undefined ? res : `<img src="${res}">`
  }))
}

if (process.env.TEST) exports.main({text:"hello"}).then(console.log)

All that’s doing is requiring the the qrcode package and exporting a function that basically generates an <img> tag with the a base64 PNG for the source. We can even test it out in the terminal:

doctl serverless functions invoke sample/qr -p "text:css-tricks.com"

Check the config file

There is one extra step we need here. When the project was scaffolded, we got this little project.yml file and it configures the function with some information about it. This is what’s in there by default:

targetNamespace: ''
parameters: {}
packages:
  - name: sample
    environment: {}
    parameters: {}
    annotations: {}
    actions:
      - name: hello
        binary: false
        main: ''
        runtime: 'nodejs:default'
        web: true
        parameters: {}
        environment: {}
        annotations: {}
        limits: {}

See those highlighted lines? The packages: name property is where in the packages folder the function lives, which is a folder called sample in this case. The actions/ name property is the name of the function itself, which is the name of the file. It’s hello by default when we spin up the project, but we named ours qr.js, so we oughta change that line from hello to qr before moving on.

Deploy the function

We can do it straight from the command line! First, we connect to the DigitalOcean sandbox environment so we have a live URL for testing:

## You will need an DO API key handy
doctl sandbox connect

Now we can deploy the function:

doctl sandbox deploy qr-generator

Once deployed, we can access the function at a URL. What’s the URL? There’s a command for that:

doctl sbx fn get sample/qr --url
https://faas-nyc1-2ef2e6cc.doserverless.co/api/v1/web/fn-10a937cb-1f12-427b-aadd-f43d0b08d64a/sample/qr

Heck yeah! No more need to ship that entire package with the rest of the scripts! We can hit that URL and generate the QR code from there.

Demo

We fetch the API and that’s really all there is to it!


Let’s Make a QR Code Generator With a Serverless Function! originally published on CSS-Tricks. You should get the newsletter.

How to Generate an Execution Plan With Planner

Planner is an execution plan generator. It generates an execution plan based on the semantically valid AST that was validated by Validator and then passes the plan to Optimizer to generate an optimized execution plan. Finally, Executor will execute the optimized plan. An execution plan is composed of a series of nodes (PlanNode).

Structure of Source Files

Here is the structure of source files for Planner.  

Gray Burst

I made this neat little gray burst thing. It’s nothing particularly special, especially compared to the amazing creativity on CodePen, but I figured I could document some of the things happening in it for learning reasons.

It’s SVG

SVG has <line x1 y1 x2 y2>, so I figured it would be easy to use for this burst look. The x1 y1 is always the middle, and the x2 y2 are randomly generated. The mental math for placing lines is pretty easy since it’s using viewBox="0 0 100 100". You might even prefer -50 -50 50 50 so that the coordinate 0 0 is in the middle.

Random numbers

const getRandomInt = (min, max) => {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min + 1)) + min;
};

It’s nice to have a function like that available for generate art. I use it not just for the line positioning but also the stroke width and opacity on the grays.

I’ve used that function so many times it makes me think native JavaScript should have a helper math function that is that clear.

Generating HTML with template literals is so easy

This is very readable to me:

let newLines;
for (let i = 0; i < NUM_LINES; i++) {
  newLines += `
  <line 
    x1="50"
    y1="50"
    x2="${getRandomInt(10, 90)}"
    y2="${getRandomInt(10, 90)}"
    stroke="rgba(0, 0, 0, 0.${getRandomInt(0, 25)})"
    stroke-linecap="round"
    stroke-width="${getRandomInt(1, 2)}"
  />`;
}

svg.insertAdjacentHTML("afterbegin", newLines);

Interactivity in the form of click-to-regenerate

If there is a single function to kick off drawing the artwork, click-to-regenerate is as easy as:

doArt();

window.addEventListener("click", doArt);

Rounding

I find it far more pleasing with stroke-linecap="round". It’s nice we can do that with stroke endings in SVG.

The coordinates of the lines don’t move — it’s just a CSS transform

I just popped this on the lines:

line {
  transform-origin: center;
  animation: do 4s infinite alternate;
}
line:nth-child(6n) {
  animation-delay: -1s;
}
line:nth-child(6n + 1) {
  animation-delay: -2s;
}
line:nth-child(6n + 2) {
  animation-delay: -3s;
}
line:nth-child(6n + 3) {
  animation-delay: -4s;
}
line:nth-child(6n + 4) {
  animation-delay: -5s;
}

@keyframes do {
  100% {
    transform: scale(0.69);
  }
}

It might look like the lines are only getting longers/shorter, but really it’s the whole line that is shrinking with scale(). You just barely notice the thinning of the lines since they are so much longer than wide.

Notice the negative animation delays. That’s to stagger out the animations so they feel a bit random, but still have them all start at the same time.

What else could be done?

  • Colorization could be cool. Even pleasing, perhaps?
  • I like the idea of grouping aesthetics. As in, if you make all the strokes randomized between 1-10, it feels almost too random, but if it randomized between groups of 1-2, 2-4, or 8-10, the aesthetics feel more considered. Likewise with colorization — entirely random colors are too random. It would be more interesting to see randomization within stricter parameters.
  • More movement. Rotation? Movement around the page? More bursts?
  • Most of all, being able to play with more parameters right on the demo itself is always fun. dat.GUI is always cool for that.


The post Gray Burst appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

Layoutit Grid: Learning CSS Grid Visually With a Generator

Layoutit Grid is an interactive open source CSS Grid generator. It lets you draw your designs and see the code as you go. You can interact with the code, add or remove track lines and drag them around to change the sizing — and you get to see the CSS and HTML change in real time!

Animated gif of the tool which is split into three columns: one that sets the number of grid rows and columns, one to name and visualize the layout, and the last to see the code.
Add some tracks and see how they’re made in CSS

When you are done with a layout, you can create a CodePen or grab the code to jumpstart your next project. The tool brings the code to the forefront, helping you learn CSS grid as you work directly with it.

CSS Grid is a whole new way of thinking about layouts

We can now create robust responsive layouts for our web experiences. We can finally learn to design with a coherent set of layout tools instead of memorizing piles of hacks to force elements into position.

Now, I’m not saying a generator like this excuses us from knowing the code we write. We should all learn how CSS Grid and Flexbox work. Even if your stronghold is JavaScript, having a solid foundation in CSS knowledge is a powerful ally when communicating your ideas. When sharing a prototype for a component, a UX interaction, or even an algorithm in an online sandbox, the way in which your work is presented can make a big difference. The ability to develop proper layouts — and define the styles that create them — is fundamental.

Crafting layouts in CSS should not be a daunting task. CSS Grid is actually quite fun to use! For example, using named grid areas feels like an ASCII art version of drawing a design on a piece of paper. Lets create the layout of a photos app, a feed of pics and the people in them side by side for its main content and the typical header, footer and a config sidebar.

.photos-app {
  /* For our app layout, lets place things in a grid */
  display: grid;
  /* We want 3 columns and 3 rows, and these are the responsive
     track sizes using `fr` (fraction of the remaining space) */
  grid-template-columns: 20% 1fr 1fr;
  grid-template-rows: 0.5fr 1.7fr 0.3fr;
  /* Let's separate our tracks a bit */
  gap: 1em;
  /* We now have 3x3 cells, here is where each section is placed */
  grid-template-areas:
    "header header header"  /* a header stretching in the top row */
    "config photos people"  /* a left sidebar, and our app content */
    "footer footer footer"; /* and a footer along the bottom row  */
}

.the-header {
  /* In each section, let's define the name we use to refence the area */
  grid-area: "header";
}

This is just a small subset of what you can build with CSS Grid. The spec is quite flexible. Areas can also be placed directly using line numbers or names, or they can be placed implicitly by the browser, with the content distributed inside the grid automatically. And the spec continues to grow with additions, like subgrid.

At the same time, working with grids can be difficult, just like anything that requires a new way of thinking. It takes a lot of time to wrap our heads around this sort of thing. And one way to help do that is to…

Learn while playing

When you are learning CSS Grid, it is easy to feel intimidated by its notation and semantics. Until you develop some muscle memory for it, kickstarting the learning process with visual and interactive tools can be an excellent way to overcome that early trepidation. A lot of us have used generators while learning how to create shadows, gradients, Markdown tables, and so on. Generators, if built with care, are great learning aids.

Let’s use Layoutit Grid to recreate the same design in our example.

Generators like this aren’t meant to be leaned on forever; they’re a stepping stone. This particular one helps you experience the power of CSS Grid by materializing your designs in a few clicks along with the code to make it happen. This gives you the early wins that you need to push forward with the learning process. For some of us, generators permanently remain in our toolboxes. Not because we do not know how to craft the layouts by hand, but because having the visual feedback loop help us to quickly convert our ideas into code. So we keep playing with them.

Sarah Drasner has also created a CSS Grid generator that’s worth checking out as well.

Learn by building

Leniolabs recently open-sourced Layoutit Grid and added new features, like interactive code views, area edition, history and offline support. And there are several more in the making.

If you have ideas to improve the tool, get in touch! Open an issue and let’s discuss it on GitHub. Going into meta territory, you can also learn about the CSS Grid spec by helping us build the tool. 

We use the app to keep track of best practices in creating performant interactive web experiences. It is now powered by the newly released Vue 3 using <script setup> components and built with Vite, a new dev tool that doesn’t bundle the app while developing, which gives us instant feedback during development. If you are curious and want to build with us, fork the repo and let’s learn together!


The post Layoutit Grid: Learning CSS Grid Visually With a Generator appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

JavaScript Generators and How They Work

What Are Generators?

  • Generators in ES6 are a new way of working with functions and iterators.
  • They appear to be a function but behaves like an iterator which simplifies the task of writing iterators.
  • They are different from a normal function, as they can stop mid-execution and then continue from where they stopped.
  • In layman’s terms, they are similar to the way we put a marker/bookmark in a page of the book we are reading. Then later we resume reading the book from that particular page instead of starting all over again. Here we acted as a generator function.
  • They can generate a series of results instead of a single value.

Generator Syntax

  • Creating a generator is similar to a normal function, with the difference that it requires a * between the function keyword and function name.
  • It allows any number of spaces or no spaces in between.
  • It uses the yield keyword to pause and resume execution.
  • Since it is just a function, we can use it anywhere just like we would with normal function, i.e. inside objects and class methods.
  • Basic syntax:
// All below formats are valid with spaces/no spaces in between function keyword, * and function name.
function * functionName() {
    // Your generator related codes here.
}

// OR below format.
function *functionName() {
    // Your generator related codes here.
}

// OR below format.
function* functionName() {
    // Your generator related codes here.
}

// OR below format.
function  *  functionName() {
    // Your generator related codes here.
}

// OR below format.

function*functionName() {
    // Your generator related codes here.
}

// Inside Class method.
class testClass {
    *functionName() {}
}

// Inside object
var testObject = {
    *functionName() {}
}

Yield Keyword

  • The yield keyword is used to return data and pause the execution of the generator.
  • Every time the generator encounters yield, it halts the execution at that point and returns the specified value. It then resumes the execution upon calling the next() method on the Generator object until it finds the next yield.
  • In the context of generators, we do not say that it returned a value. We say that it has yielded the value.
  • Using return inside a generator will set the done property to true, after which it cannot generate any more values. All the code after the return statement will not execute.
  • Syntax:
// Generator with yield. 
function * generator() {
    console.log('First execution.');
    yield 'Yield First execution, saved the state and exit';
    console.log('Second execution will be on next() call.');  
    yield 'Yield second execution, saved the state and exit';
}

const generatorObj = generator();

next() in Generators

  • The generator returns an object on which we can call next().
  • Every invocation of next() will return an object containing the returned value and the status of the generator's execution.
  • The value property will contain the value and the done property will return true or false for the generator’s execution status.
  • When done becomes true, the generator stops and won’t generate any more values.
{
    value: Any,
    done: true|false
}
function * generator() {
    console.log('First execution.');
    yield 'Yield First execution, saved the state and exit';
    console.log('Second execution will be on next() call.');  
    yield 'Yield second execution, saved the state and exit';
}

const generatorObj = generator();

// After below execution, generator will yield value, return below object and pause execution.
// {value: 'Yield First execution, saved the state and exit', done: false}
setTimeout(() => console.log(generatorObj.next()), 1000);

// After below execution, generator will yield value, return below object and pause execution.
// {value: 'Yield First execution, saved the state and exit', done: false} 
setTimeout(() => console.log(generatorObj.next()), 3000);

// After below execution, generator will yield value, return below object and close execution.
// {value: undefined, done: true}
setTimeout(() => console.log(generatorObj.next()), 5000);
  • The below screenshot shows the different states of a generator during its execution of how it gets "suspended" when it encounters the yield keyword, resumes when next() is called, and then gets closed after the execution is complete:JavaScript generators
  • If we use return then it will not execute any code present after the return statement. Sample code (JSFiddle link: generator with return statement):
  • function * generator() {
        console.log('First execution.');
        yield 'Yield First execution, saved the state and exit';
        return 'Execution ends here due to return and will not execute rest of the codes.';  
        // All below codes will not get executed.
        yield 'Yield second execution, saved the state and exit';
    }
    
    const generatorObj = generator();
    
    // After below execution, generator will yield value, return below object and pause execution.
    // {value: 'Yield First execution, saved the state and exit', done: false}
    setTimeout(() => console.log(generatorObj.next()), 1000);
    
    // After below execution, generator will yield value, return below object and completes the execution.
    // {value: 'Execution ends here due to return and will not execute rest of the codes.', done: true}
    setTimeout(() => console.log(generatorObj.next()), 3000);
    
    // generator execution is already completed so it will just return value as undefined and done as true.
    // {value: undefined, done: true}
    setTimeout(() => console.log(generatorObj.next()), 5000);
  • We can also pass values to next().
    Sample code (JSFiddle link: next() with value passed):
  • function * generator() {
        console.log('First execution.');
        yield 'Yield First execution, saved the state and exit';
        console.log('Second execution will be on next() call.');  
        let passedArgument = yield 'Yield second execution, saved the state and exit';
        yield passedArgument;
    }
    
    const generatorObj = generator();
    
    // After below execution, generator will yield value, return below object and pause execution.
    // {value: 'Yield First execution, saved the state and exit', done: false}
    setTimeout(() => console.log(generatorObj.next()), 1000);
    
    // After below execution, generator will yield value, return below object and pause execution.
    // {value: 'Yield First execution, saved the state and exit', done: false} 
    setTimeout(() => console.log(generatorObj.next()), 3000);
    
    // After below execution, generator will yield value, return below object and pause execution.
    // {value: "This is the passed value", done: false}
    setTimeout(() => console.log(generatorObj.next('This is the passed value')), 5000);
    
    // After below execution, generator will yield value, return below object and close execution.
    // {value: undefined, done: true}
    setTimeout(() => console.log(generatorObj.next()), 7000);

    Why Use Generators

    • Implementing Iterables:
      • Implementation of an iterator in JavaScript requires things to be done manually, like:
        • Creating an iterator object.
        • Implemeting the next() method.
        • Making a return object for next() in the proper format: { value: Any, done: true | false }
        • Saving the state.
      • The below sample code shows how hard it is to manually implement everything in an iterator.
      const iterableObj = {
          [Symbol.iterator]() {
              var counter = 0;
              return {
                  next() {
                      counter++;
                          if (counter === 1) {
                              return { value: 'step one', done: false};
                          } else if (counter === 2) {
                              return { value: 'step two', done: false};
                          } else if (counter === 3) {
                              return { value: 'step three', done: false};
                          }
                      return { value: '', done: true };
                  }
              }
          },
      }
      
      for (const val of iterableObj) {
          console.log(val);
      }
      • The below sample code shows how easy it is with a generator which handles most of the things on its own.
      function * iterableObj() {
          yield 'step one';
          yield 'step two';
          yield 'step three';
      }
      
      for (const val of iterableObj()) {
        console.log(val);
      }
    • Lazy execution: Generator helps to delay the evaluation of an expression until its value is required. So, if we don’t need a value, it won’t exist and is calculated only when we need it.
    • Memory efficient: It is memory efficient because we generate only the values that are required. We need to pre-generate all the values in case of normal functions and keep them in case we can use them later. But generators can defer the computation of any expressions/code until we need it.

    Limitations

    • Generators are one-time access only. Once you’ve exhausted all the values, you can’t iterate over it again. To generate the values again, you need to make a new generator object.
    • Generators do not allow random access with arrays. 

    I hope this post has helped you get a better grasp on  JavaScript generators and their basic functionalities.

    Happy coding!