Final output (clock app)
Strategy

How to Publish Your Vue.js Component on NPM


You’ve made an awesome component with Vue.js that you think other developers could use in their projects. How can you share it with them?

In this article, I’ll show you how to prepare your component so that it can be packaged and published on NPM. I’ll use an example project and demonstrate the following:

  • Ensuring dependencies are not included in the package
  • Using Webpack to create separate builds for the browser and Node
  • Creating a plugin for the browser
  • Important configuration of package.json
  • Publishing on NPM

Case Study Project: Vue Clock

I’ve created this simple clock component which I’m going to publish on NPM. Maybe it’s not the coolest component you’ve ever seen, but it’s good enough for a demonstration.

Final output (clock app)

Final output (clock app)

Here’s the component file. There’s nothing too special here, but note that I’m importing the moment library in order to format the time. It’s important to exclude dependencies from your package, which we’ll look at shortly.

Clock.vue

Most of what I need to do to prepare this component for NPM is done with Webpack. Here’s the basic Webpack setup that I’ll be adding to in this article. It shouldn’t include many surprises if you’ve used Vue and Webpack before:

webpack.config.js

Externals

The externals configuration option provides a way of excluding dependencies from the Webpack output bundle. I don’t want my package to include dependencies because they will bloat its size and potentially cause version conflicts in the user’s environment. The user will have to install dependencies themselves.

In the case study project, I’m using the moment library as a dependency. To ensure it doesn’t get bundled into my package, I’ll specify it as an external in my Webpack configuration:

webpack.config.js

Environment Builds

In Vue.js, there are two different environments where a user might want to install a component. Firstly, the browser e.g.

Secondly, Node.js-based development environments e.g.

Ideally, I want users to be able to use Vue Clock in either environment. Unfortunately, these environments require the code to be bundled differently, which means I’ll have to set up two different builds.

To do this, I’ll create two separate Webpack configurations. This is easier than it sounds because the configurations will be almost identical. First I’ll create a common configuration object, then use webpack-merge to include it in both environment configurations:

webpack.config.js

The common configuration is exactly as it was before (I’ve abbreviated most of it to save space), except I’ve removed the entry and output.filename options. I’ll specify these individually in the separate build configurations.

Browser Bundle

Browsers can’t import JavaScript modules from another file the same way a Node can. They can use a script loader like AMD, but for maximum ease, I want to allow my component script to be added more simply as a global variable.

Also, I don’t want the user to have to think too hard to figure out how to use the component. I’ll make it so the component can easily be registered as a global component when the user includes the script. Vue’s plugin system will help here.

The result I’m aiming for is this simple setup:

index.html

Plugin

First, I’ll create a plugin wrapper to allow for easy installation of the component:

plugin.js

This plugin registers the component globally, so the user can call the clock component anywhere in their application.

Webpack Configuration

I’ll now use the plugin file as the entry point for the browser build. I’ll output to a file called vue-clock.min.js as that’ll be most obvious to the user.

Exporting as a Library

Webpack can expose your bundled script in a variety of different ways, e.g. as an AMD or CommonJS module, as an object, as a global variable etc. You can specify this with the libraryTarget option.

For the browser bundle, I’ll use the window target. I could also use UMD for more flexibility, but since I’m creating two bundles already, I’ll just confine this bundle for use in the browser.

I’ll also specify the library name as ‘VueClock’. This means that when a browser includes the bundle, it will be available as the global window.VueClock.

Node Bundle

To allow users to use the component in a Node-based development environment, I’ll use the UMD library target for the Node bundle. UMD is a flexible module type that allows code to be used in a variety of different script loaders and environments.

Note that the Node bundle uses the single-file component as its entry point and does not use plugin wrapper, as it is not needed. This allows a more flexible installation:

package.json

Before publishing to NPM I’ll setup my package.json file. A detailed description of each option is available on npmjs.com.

package.json

I’ve abbreviated most of this file, but the important things to note are:

1. The main script file i.e. "main": "dist/vue-clock.js". This points the Node bundle file, ensuring that modules loaders know which file to read i.e.

2. Dependencies. Since I’ve excluded any dependencies from the package, users must install the dependencies to use the package.

Publishing to NPM

Now that my component is set up correctly, it’s ready to be published on NPM. I won’t repeat the instructions here since they’re covered nicely on npmjs.com.

Here’s the result:

Publishing on npm

Publishing on npm

Further Reading



Source link

Single file component
Strategy

Vue.js Single-File JavaScript Components in the Browser


Browser support for native JavaScript modules is finally happening. The latest versions of Safari and Chrome support them, Firefox and Edge will soon too.

One of the cool things about JavaScript modules for Vue.js users is that they allow you to organize your components into their own files without any kind of build step required.

In this article, I’m going to show you how to write a single-file component as a JavaScript module and use it in a Vue.js app. You can do this all in the browser without any Babel or Webpack!

When I say “single-file component” I’m talking about a single JavaScript file which exports a complete component definition. I’m not talking about the single .vue file you’re used to. Sorry if you’re disappointed. But I still think this is pretty cool, so check it out.

Project Setup

Let’s use the vue-cli simple template to do this. That’s right, the one without any Webpack.

The complete code for this tutorial is in this GitHub repo if you want to download it.

Change into the directory and create the files we’ll need:

Remove the inline script from index.html and instead use script tags to link to our modules. Note the type="module" attribute:

Creating a Single-File JavaScript Component

This is a component like any other you’ve created, only you export the configuration object since it’s a module:

SingleFileComponent.js

Now we can import it and use it in our Vue app:

app.js

index.html

Serving the App

For a simple project like this all you need is a static server on the command line with the http-server module:

To view the app you will, of course, need to use a browser which supports JavaScript modules. I’m using Chrome 61.

Single file component

Single file component

Fallback

What if the user’s browser doesn’t support JavaScript modules? This will be the case for most users, for a while.

We can use a script tag with the nomodule attribute to write a simple error message to the document:

A far better fallback, though, would be to use a Webpack bundled version of the project. This simple config will do the job:

After a build, the bundle can now be loaded as the fallback script:

This Webpack version will work identically in a browser without native module support. Here it is in Firefox, note that build.js has loaded and not the module:

Loading component from build

Loading component from build

Performance Comparison

Since we’ve now got two versions of the app available, one using the native JavaScript module system, and the other using Webpack, what performance difference is there?

JavaScript modules vs Webpack

JavaScript modules vs Webpack

Using the module system gives you a smaller project size. However, the Webpack project loads quicker overall.

Note: these figures are from a Lighthouse test with an HTTP/2 server.

I suspect preloading would improve the speed of the modules project, but we’re a bit early for this to work:

Vue Twitter conversation

Webpack is still the better choice for module-based architectures, but it’s nice to know native modules are a thing.

Further Reading



Source link

Adding Dynamic And Async Functionality To JAMstack Sites — S...
Strategy

How To Create A Headless WordPress Site On The JAMstack — Sm…


About The Authors

Sarah Drasner is an award-winning Speaker, Head of Developer Experience at Netlify, Vue core team member, and Staff Writer at CSS-Tricks. Sarah is formerly …
More about
Sarah & Geoff

In this post, we’ll set up a demo site and tutorial for headless WordPress, including a starter template! We’ll use the WordPress dashboard for rich content editing, while migrating the front-end architecture to the JAMstack to benefit from better security, performance, and reliability. We’ll do this by setting up a Vue application with Nuxt, pulling in the posts from our application via the WordPress API.

In the first article of this series, we walked through Smashing Magazine’s journey from WordPress to the JAMstack. We covered the reasons for the change, the benefits that came with it, and hurdles that were encountered along the way.

Like any large engineering project, the team came out the other end knowing more about the spectrum of successes and failures within the project. In this post, we’ll set up a demo site and tutorial for what our current recommendations would be for a WordPress project at scale: retaining a WordPress dashboard for rich content editing, while migrating the Front End Architecture to the JAMstack to benefit from better security, performance, and reliability.

We’ll do this by setting up a Vue application with Nuxt, and use WordPress in a headless manner — pulling in the posts from our application via the WordPress API. The demo is here, and the open-source repo is here.

(Large preview)

Deploy to Netlify buttonIf you wish to skip all the steps below, we’ve prepared a template for you. You can hit the deploy button below and modify it to your needs.

What follows is a comprehensive tutorial of how we set this all up. Let’s dig in!

Enter The WordPress REST API

One of the most interesting features of WordPress is that it includes an API right out of the box. It’s been around since late 2016 when it shipped in WordPress 4.7 and with it came opportunities to use WordPress new ways. What sort of ways? Well, the one we’re most interested in covering today is how it allows for the separation of the WordPress content and the Front End. Where building a WordPress theme in PHP was once the only way to develop an interface for a WordPress-powered site, the REST API ushered in a new era where the content management powers of WordPress could be extended for use outside the root WordPress directory on a server — whether that be an app, a hand-coded site, or even different platforms altogether. We’re no longer tethered to PHP.

This model of development is called a Headless CMS. It’s worth mentioning that Drupal and most other popular content management systems out there also offer a headless model, so a lot of what we show in this article isn’t just specific to WordPress.

In other words, WordPress is used purely for its content management interface (the WordPress admin) and the data entered into it is syndicated anywhere that requests the data via the API. It means your same old site content can now be developed as a static site, progressive web app, or any other way while continuing the use of WordPress as the engine for creating content.

Getting Started

Let’s make a few assumptions before we dive right in:

  • WordPress is already up and running.
    Going over a WordPress install is outside what we want to look at in this article and it’s already well documented.
  • We have content to work with.
    The site would be nothing without feeding it some data from the WordPress REST API.
  • The front-end is developed in Vue.
    We could use any number of other things, like React, Jekyll, Hugo, or whatever. We just happen to really like Vue and, truth be told, it’s likely the direction the Smashing Magazine project would have gone if they could start the process again.
  • We’re using Netlify.
    It was the platform Smashing migrated to, and is straightforward to work with. Full disclosure, Sarah works there. She also works there because she loves their service. 🙂

Setting Up Vue With Nuxt

Like WordPress, there’s already stellar documentation for setting up a Vue project, and Sarah has a Frontend Masters course (all the materials are free and open source on her GitHub). No need to rehash that here.

But what we’re actually going to do is create our app using NuxtJS. It adds a bunch of features to a typical Vue project (e.g. bundling, hot reloading, server-side rendering, and routing to name a few) that we’d otherwise have to piece together. In other words, it gives us a nice head start.

Again, setting up a NuxtJS project is super well documented, so still no need to get into that in this post. What is worth getting into is the project directory itself. It’d be nice to know what we’re getting into and where the API needs to go.

Learn how to set up a Nuxt app from scratch — it might be helpful to watch if you’re completely new to it. (Watch on Vimeo)

We’ll create the project with this command:

npx create-nuxt-app <project-name>

Here’s the general structure for a standard Nuxt project, leaving out some files for brevity:

[root-directory]
├── .nuxt
├── assets
├── components
        ├── AppNavigation.vue //any components you will reuse
        └── AppFooter.vue
├── dist
├── layouts
        └── default.vue //this gives you a standard layout, you can make many if you like, such as blog.vue, etc. We typically put our navs and footers here
├── middleware
├── node_modules
├── pages
├── index.vue //any .vue components we put in here will automatically become routed pages!
    └── about.vue
├── plugins
├── static
|        └── index.html
├── store
    └── index.js //we’ll put any state we need to share around the application in here, including the calls to the REST API to update the data. This is called a Vuex store. By creating the index page, Nuxt registers it.
└── nuxt.config.js

That’s about it for our Vue/Nuxt installation! We’ll create a component that fetches data from a WordPress site in just a bit, but this is basically what we’re working with.

Static Hosting

Before we hook the Vue app up with Netlify, let’s create a repository for the project. One of the benefits of a service like Netlify is that it can trigger a deploy when changes are pushed to the master (or some other) branch of a repository. We’ll definitely want that. Git is automatically initialized in a new Vue installation, so we get to skip that step. All we need to do is create a new repository on GitHub and push the local project to master. Anything in caps is something you will replace with your own information.

### Add files
git add .

### Add remote origin
git remote add origin git@github.com:USERNAME/REPONAME.git

### Push everything to the remote repo
git push -u origin master

Now, we’re going to head over to our Netlify account and hook things up. First, let’s add a new site from the Sites screen. If this is your first time using Netlify, it will ask you to give it the authorization to read repositories from your GitHub (or GitLab, or BitBucket) account. Let’s select the repository we set up.

(Large preview)

Netlify will confirm the branch we want to use for deployments. There’s also a spot to tell Netlify what we use for the build task that compiles our site for production and which directory to look at.

We’ll be prompted for our build command and directory. For Nuxt it’s:

  • Build command: yarn generate or npm run generate
  • Directory: dist

Check out the full instructions for deploying a Vue app to Netlify for more details. Now we can deploy! 🎉

Setting Up The Store

No, we’re not getting into e-commerce or anything. Nuxt comes equipped with the ability to use a Vuex store out of the gate. This provides a central place where we can store data for components to call and consume. You can think of it like the “brains” of the application.

The /store directory is empty by default. Let’s create a file in there to start making a place where we can store data for the index page. Let’s creatively call that index.js. Sarah has a VS Code extension with shortcuts that make this setup fairly trivial. With that installed (assuming you’re using VS Code, of course) we can type vstore2 and it spits out everything we need:

export const state = () => ({
    value: 'myvalue'
})

export const getters = {
    getterValue: state => {
        return state.value
    }
}

export const mutations = {
    updateValue: (state, payload) => {
        state.value = payload
    }
}

export const actions = {
    updateActionValue({ commit }) {
        commit('updateValue', payload)
    }
}

Basically, the setup is as follows:

  • state holds the posts, or whatever info we need to store.
  • mutations will hold functions that will update the state. Mutations are the only thing that can update state actions cannot.
  • actions can make asynchronous API calls. We’ll use this to make the call to WordPress API and then commit a mutation to update the state. First, we’ll check if there’s any length to the posts array in state, which means we already called the API, so we don’t do it again.

Right off, we can nix the getters block because we won’t be using those right now. Next, we can replace the value: ‘myValue’ in the state with an empty array that will be reserved for our posts data:posts: []. This is where we’re going to hold all of our data! This way, any component that needs the data has a place to grab it.

The only way we can update the state is with mutations, so that’s where we’re headed next. Thanks to the snippet, all we need to do is update the generic names in the block with something more specific to our state. So, instead of updateValue, let’s go with updatePosts; and instead of state.value, let’s do state.posts. What this mutation is doing is taking a payload of data and changing the state to use that payload.

Now let’s look at the actions block. Actions are how we’re able to work with data asynchronously. Asynchronous calls are how we’ll fetch data from the WordPress API. Let’s update the boilerplate values with our own:

/*
this is where we will eventually hold the data for all of our posts
*/
export const state = () => ({
    posts: []
})
/*
this will update the state with the posts
*/
export const mutations = {
    updatePosts: (state, posts) => {
        state.posts = posts
    }
}
/*

actions is where we will make an API call that gathers the posts,
and then commits the mutation to update it
*/
export const actions = {
    //this will be asynchronous
    async getPosts({
        state,
        commit
    }) {
        //the first thing we’ll do is check if there’s any length to the posts array in state, which means we already called the API, so don’t do it again.
        if (state.posts.length) return
    }
}

If that errors along the way, we’ll catch those errors and log them to the console. In production apps, we would also check if the environment was development before logging to the console.

Next, in that action we set up we’re going to try to get the posts from the API:

export const actions = {
 async getPosts({ state, commit }) {
   if (state.posts.length) return
   try {
     let posts = await fetch( `https://css-tricks.com/wp-json/wp/v2/posts?page=1&per_page=20&_embed=1`
     ).then(res => res.json())
     posts = posts
       .filter(el => el.status === "publish")
       .map(({ id, slug, title, excerpt, date, tags, content }) => ({
         id
         slug,
         title,
         excerpt,
         date,
         tags,
         content
       }))
     commit("updatePosts", posts)
   } catch (err) {
     console.log(err)
   }
}

You might have noticed we don’t just take all of the information and store it, we’re filtering out only what we need. We do this because WordPress does indeed store a good deal of data for each and every post, only some of which might be needed for our purposes. If you’re familiar with REST APIs, then you might already know that they typically return everything. For more information about this, you can check out a great post by Sebastian Scholl on the topic.

That’s where the .filter() method comes in. We can use it to fetch just the schema we need which is a good performance boost. If we head back to our store, we can filter the data in posts and use .map() to create a new array of that data.

Let’s do this so that we only get published posts (because we don’t want drafts showing up in our feed), the Post ID (for distinguishing between posts), the post slug (good for linking up posts), the post title (yeah, kinda important), and the post excerpt (for a little preview of the content), and some other things like tags. We can drop this in the try block right before the commit is made.

This will give us data that looks like this:

posts: [
 {
   content:Object
     protected:false
     rendered:"<p>Fluid typography is the idea ..."
   date:"2019-11-29T08:11:40"
   excerpt:Object
     protected:false
     rendered:"<p>Fluid typography is the idea ..."
   id:299523
   slug:"simplified-fluid-typography"
   tags:Array[1]
     0:963
   title:Object
     rendered:"Simplified Fluid Typography"
   },
 …
]

OK, so we’ve created a bunch of functions but now they need to be called somewhere in order to render the data. Let’s head back into our index.vue file in the /pages directory to do that. We can make the call in a script block just below our template markup.

Let’s Render Them!

In this case, we want to create a template that renders a loop of blog posts. You know, the sort of page that shows the latest 10 or so posts. We already have the file we need, which is the index.vue file in the /pages directory. This is the file that Nuxt recognizes as the “homepage” of the app. We could just as easily create a new file if we wanted the feed of posts somewhere else, but we’re using this since we’re dealing with a site that’s based around a blog. Let’s open that file, clear out what’s already there and drop our own template markup in there.

We’ll dispatch this action, and render the posts:

<template>
<div class="posts">
  <main>
    <h2>Posts</h2>
  <!-- here we loop through the posts -->
    <div class="post" v-for="post in posts" :key="post.id">
      <h3>
      <!-- for each one of them, we’ll render their title, and link off to their individual page -->
        <a :href="https://www.smashingmagazine.com/`blog/${post.slug}`">{{ post.title.rendered }}</a>
      </h3>
      <div v-html="post.excerpt.rendered"></div>
      <a :href="https://www.smashingmagazine.com/`blog/${post.slug}`" class="readmore">Read more ⟶</a>
    </div>
  </main>
  </div>
</template>

<script>
export default {
computed: {
  posts() {
    return this.$store.state.posts;
  },
 },
created() {
  this.$store.dispatch("getPosts");
},
};
</script>
(Large preview)

In the created lifecycle method, you see we’re kicking off that action that will fetch the posts from the API. Then we’ll store those posts we get in a computed property called posts. Then in the template, we loop through all the posts, and render the title and the excerpt from each one, linking off to an individual post page for the whole post (think like single.php) that we haven’t built yet. So let’s do that part now!

Creating Individual Post Pages Dynamically

Nuxt has a great way of creating dynamic pages, with minimal code, you can set up a template for all of your individual posts.

First, we need to create a directory, and in there, put a page with an underscore, based on how you will render it. In our case, it will be called blog, and we’ll use the slug data we brought in from the API, with an underscore. Our directory will then look like this:

index.vue

blog/

   _slug.vue
<script>
export default {
computed: {
  posts() {
    return this.$store.state.posts;
  }
},
created() {
  this.$store.dispatch("getPosts");
}
};
</script>

We’ll dispatch the getPosts request, just in case they enter the site via one of the individual pages. We’ll also pull in the posts data from the store.

We also have to make sure this page knows which post we’re referring to. The way we’ll do this is to store this particular slug with this.$route.params.slug. Then we can find the particular post and store it as a computed property using filter:

computed: {
  ...
  post() {
    return this.posts.find(el => el.slug === this.slug);
  }
},
data() {
  return {
    slug: this.$route.params.slug
  };
},

Now that we have access to the particular post, in the template, we’ll render the title, and also the content. Due to the fact that the content is a string that has HTML elements already included that we want to use, we’ll use the vue directive v-html to render that output.

<template>
<main class="post individual">
  <h1>{{ post.title.rendered }}</h1>
  <section v-html="post.content.rendered"></section>
</main>
</template>
(Large preview)

The last thing we have to do is let Nuxt know that it needs to generate all of these dynamic routes. In our nuxt.config.js file, we’ll let nuxt know when we use the generate command (which allows nuxt to build statically), to use a function to create the routes. We’ll call our function dynamicRoutes.

generate: {
  routes: dynamicRoutes
},

Next, we’ll install axios by running yarn add axios at the top of the file we’ll import it. Then we’ll create a function that will generate an array of posts based on the slugs we retrieve from the API. I cover this in more detail in this post.

import axios from "axios"
let dynamicRoutes = () => {
return axios
  .get("https://css-tricks.com/wp-json/wp/v2/posts?page=1&per_page=20")
  .then(res => {
    return res.data.map(post => `/blog/${post.slug}`)
  })
}

This will create an array that looks something like this:

export default {
 generate: {
   routes: [
     '/blog/post-title-one',
     '/blog/post-title-two',
     '/blog/post-title-three'
   ]
 }
}

And we’re off to the races! Now let’s deploy it and see what we’ve got.

Create The Ability To Select Via Tags

The last thing we’re going to do is select posts by tag. It works very similarly for categories, and you can create all sorts of functionality based on your data in WordPress, we’re merely showing one possible path here. It’s worth exploring the API reference to see all that’s available to you.

It used to be that when you gathered the tags data from the posts, it would tell you the names of the tags. Unfortunately, in v2 of the API, it just gives you the id, so you have to then make another API call to get the actual names.

The first thing we’ll do is create another server-rendered plugin to gather the tags just as we did with the posts. This way, it will do this all at build time and be rendered for the end-user immediately (yay JAMstack!)

export default async ({ store }) => {
  await store.dispatch("getTags")
}

Next, we’ll create a getTags action, where we pass in the posts. The API call will look very similar, but we have to pass in the tags in this format, where after include UTM we pass in the IDs, comma-separated, like this:

https://css-tricks.com/wp-json/wp/v2/tags?include=1,2,3

In order to format it like that, we’ll have to take the posts and extract all the ids. We’ll do so with a .reduce() method:

async getTags({ state, commit }, posts) {
  if (state.tags.length) return
  let allTags = posts.reduce((acc, item) => {
    return acc.concat(item.tags);
  }, [])
  allTags = allTags.join()
  try {
    let tags = await fetch(
      `https://css-tricks.com/wp-json/wp/v2/tags?page=1&per_page=40&include=${allTags}`
    ).then(res => res.json())
    tags = tags.map(({ id, name }) => ({
      id, name
    }))
    commit("updateTags", tags)
  } catch (err) {
    console.log(err)
  }
}

Just like the posts, we’ll need a place in state to store the tags, and a mutation to update them:

export const state = () => ({
  posts: [],
  tags: []
})

export const mutations = {
  updatePosts: (state, posts) => {
    state.posts = posts
  },
  updateTags: (state, tags) => {
    state.tags = tags
  }
}

Now, in our index.vue page, we can bring in the tags from the store and display all of them

computed: {
  tags() {
    return this.$store.state.tags;
  },
}

<aside>
    <h2>Categories</h2>
    <div class="tags-list">
      <ul>
        <li
           v-for="tag in tags"
          :key="tag.id">
            <a>{{ tag.name }}</a>
        </li>
      </ul>
    </div>
  </aside>

This will give us this visual output:

(Large preview)

Now, this is fine, but we might want to filter the posts based on which one we selected. Fortunately, computed properties in Vue make small work of this.

<template>
<div class="posts">
  <aside>
    <h2>Categories</h2>
    <div class="tags-list">
      <ul>
        <li
          @click="updateTag(tag)"
          v-for="tag in tags"
          :key="tag.id">
            <a>{{ tag.name }}</a>
        </li>
      </ul>
    </div>
  </aside>
</div>
</template>

<script>
export default {
data() {
  return {
    selectedTag: null
  }
},
methods: {
  updateTag(tag) {
    if (!this.selectedTag) {
      this.selectedTag = tag.id
    } else {
      this.selectedTag = null
    }
  }
},
 ...
};
</script>

First, we’ll store a data property that allows us to store the selectedTag. We’ll start it off with a null value.

In the template, when we click on the tag, we’ll execute a method that will pass in which tag it is, named updateTag. We’ll use that to either set selectedTag to the tag ID or back to null, for when we’re done filtering.

From there, we’ll change our v-for directive that displays the post from"post in posts" to "post in sortedPosts". We’ll create a computed property called sortedPosts. If the selectedTag is set to null, we’ll just return all the posts, but otherwise we’ll return only the posts filtered by the selectedTag:

<template>
<main>
    <h2>Posts</h2>
    <div class="post" v-for="post in sortedPosts" :key="post.id">
    </div>
  </main>
</template>
<script>
computed: {
  sortedPosts() {
    if (!this.selectedTag) return this.posts
    return this.posts.filter(el => el.tags.includes(this.selectedTag))
  }
},
</script>

Now the last thing we want to do to polish off the application is style the selected tag just a little differently, and let the user know you can deselect it.

<template>
<div class="posts">
  <aside>
    <h2>Categories</h2>
    <div class="tags-list">
      <ul>
        <li
          @click="updateTag(tag)"
          v-for="tag in tags"
          :key="tag.id"
          :class="[tag.id === selectedTag ? activeClass : '']">
            <a>{{ tag.name }}</a>
            <span v-if="tag.id === selectedTag">✕</span>
        </li>
      </ul>
    </div>
  </aside>
</div>
</template>

<script>
export default {
data() {
  return {
    selectedTag: null,
    activeClass: 'active'
  }
},
</script>

And there you have it! All the benefits of a rich content editing system like WordPress, with the performance and security benefits of JAMstack. Now you can decouple the content creation from your development stack and use a modern JavaScript framework and the rich ecosystem in your own app!

Deploy to Netlify buttonOnce again, if you wish to skip all these steps and deploy the template directly, modifying it to your needs, we set this up for you. You can always refer back here if you need to understand how it’s built.

There are a couple of things we didn’t cover that are out of the scope of the article (it’s already quite long!)

Smashing Editorial(dm, ra, il)



Source link

bundle size
Strategy

Code Splitting With Vue.js and Webpack


One possible downside to bundling your single page app with Webpack is that you can end up with a really big bundle file, sometimes several megabytes in size!

bundle size

Bundle size

The problem with this is that a user must download the whole file and run it before they can see anything on the screen. If the user is on a mobile device with a poor connection this process could take quite some time.

Code splitting is the idea that a bundle can be fragmented into smaller files allowing the user to only download what code they need, when they need it.

For example, looking at this simple web page, we can identify portions of the app that we don’t need on the initial load:

Components required for initial page load

Components required for initial page load

What if we delayed loading these parts of the code until after the initial render? It would allow a user to see and interact with the page much quicker.

In this article, I’ll show you how Vue.js and Webpack can be used to split a single page app into more optimally sized files that can be dynamically loaded.

You may also like:
What’s New in Vue?

Async Components

The key to code splitting a Vue.js app is async components. These are components where the component definition (including its template, data, methods, etc) is loaded asynchronously.

Let’s say you’re declaring a component using the component API, i.e. Vue.component(name, definition). Rather than having a definition object as the second argument, async components have a function. This function has two notable features:

  1. It’s an executor for a Promise, i.e. it has a resolve argument.
  2. It’s a factory function, i.e. it returns an object (in this case, the component definition).

Async components are the first step for code splitting because we now have a mechanism for abstracting sections of our app’s code.

Dynamic Module Loading

We’ll also need Webpack’s help. Say we abstract our component definition into an ES6 module file:

AsyncComponent.js

How could we get our Vue.js app to load this? You may be tempted to try something like this:

However, this is static and is resolved at compile-time. What we need is a way to dynamically load this in a running app if we want to get the benefits of code splitting.

import()

Currently, it’s not possible to dynamically load a module file with JavaScript. There is, however, a dynamic module loading function currently under proposal for ECMAScript called import().

Webpack already has an implementation for import() and treats it as a code split point, putting the requested module into a separate file when the bundle is created (a separate chunk, actually, but think of it as a separate file for now).

import() takes the file name as an argument and returns a Promise. Here’s how we’d load our above module:

main.js

Note: if you’re using Babel, you’ll need to add the syntax-dynamic-import plugin so that Babel can properly parse this syntax.

Now when you build your project you’ll notice the module appears in its own file:

Asset and chunk name

Asset and chunk name

Another note: you can give a dynamically imported module chunk a name so its more easily identifiable; simply add a comment before the file name in the same way I’ve done in the above example.

Dynamic Component Loading

Bring the pieces together now: since import() returns a Promise, we can use it in conjunction with Vue’s async component functionality. Webpack will bundle AsyncComponent separately and will dynamically load it into the app via AJAX when the app calls it.

main.js

index.html

On the initial load the page will be rendered as:

When main.js runs it will initiate a request for the async component module (this happens automatically because Webpack’s import() implementation includes code that will load the module with AJAX!).

If the AJAX call is successful and the module is returned, the Promise resolves and the component can be rendered, so Vue will now re-render the page:

Here’s a diagram to help you visualize it:

AsyncComponent workflow

AsyncComponent workflow

Single File Components

The idiosyncratic way to achieve code splitting in Vue, however, is to use the beloved single file component. Here’s a refactor of the above code using an SFC.

AsyncComponent.vue

This syntax for importing is even neater:

Code Splitting Architecture

That’s the technical part out of the way. The question, now, is how can you architect an app for code splitting?

The most obvious way is by page. For example, say you have two pages in your app, a home page and an about page. These pages can be wrapped inside components, Home.vue and About.vue, and these can be the split points of the app.

But there are other ways, for example, you could split any components that are conditionally shown (tabs, modals, drop-down menus, etc.) or that are below the page fold.

For my next article, I’ll explore some different code splitting architectures for a Vue.js SPA, so stay tuned!

Further Reading



Source link

switch_react_vue_1
Strategy

Switching From React to Vue.js


So you’re a React developer and you’ve decided to try out Vue.js. Welcome to the party!

React and Vue are kind of like Coke and Pepsi, so much of what you can do in React you can also do in Vue. There are some important conceptual differences though, some of which reflect Angular’s influence on Vue.

I’ll focus on the differences in this article so you’re ready to jump into Vue and be productive straight away.

How Much Difference Is There Between React and Vue?

React and Vue have more similarities than differences:

  • Both are JavaScript libraries for creating UIs.
  • Both are fast and lightweight.
  • Both have a component-based architecture.
  • Both use a virtual DOM.
  • Both can be dropped into a single HTML file or be a module in a more sophisticated Webpack setup.
  • Both have separate, but commonly used router and state management libraries.

The big differences are that Vue typically uses an HTML template file whereas React is fully JavaScript. Vue also has mutable state and an automatic system for re-rendering called “reactivity.”

We’ll break it all down below.

Components

With Vue.js, components are declared with an API method .component which takes arguments for an id and a definition object. You’ll probably notice familiar aspects of Vue’s components and not-so-familiar aspects:

Template

You’ll notice the component has a template property which is a string of HTML markup. The Vue library includes a compiler which turns a template string into a render function at runtime. These render functions are used by the virtual DOM.

You can choose not to use a template if you instead want to define your own render function. You can even use JSX. But switching to Vue just to do that would be kind of like visiting Italy and not eating pizza…

Lifecycle Hooks

Components in Vue have similar lifecycle methods to React components as well. For example, the created hook is triggered when the component state is ready, but before the component has been mounted on the page.

One big difference: there’s no equivalent for shouldComponentUpdate. It’s not needed because of Vue’s reactivity system.

Re-Rendering

One of Vue’s initialization steps is to walk through all of the data properties and convert them to getters and setters. If you look below, you can see how the message data property has a get and set function added to it:

switch_react_vue_1

Vue added these getters and setters to enable dependency tracking and change notification when the property is accessed or modified.

Mutable State

To change the state of a component in Vue you don’t need a setState method, you just go ahead and mutate:

When the value of message is changed by the mutation, its setter is triggered. The set method will set the new value, but will also carry out a secondary task of informing Vue that a value has changed and any part of the page relying on it may need to be re-rendered.

If message is passed as a prop to any child components, Vue knows that they depend on this and they will be automatically re-rendered as well. That’s why there’s no need for a shouldComponentUpdate method on Vue components.

You may also like:
Vue Tutorial 5 — Form Data Binding.

Main Template

Vue is more like Angular with regards to the main template file. As with React, Vue needs to be mounted somewhere in the page:

But unlike React, you can continue to add to this main index.html as it is the template for your root component.

There’s also a way to define your child component templates in the index.html as well by using HTML features like x-template or inline-template. This is not considered a best practice though as it separates the template from the rest of the component definition.

Directives

Again, like Angular, Vue allows you to enhance your templates with logic via “directives.” These are special HTML attributes with the v- prefix, e.g. v-if for conditional rendering and v-bind to bind an expression to a regular HTML attribute.

The value assigned to a directive is a JavaScript expression, so you can refer to data properties, including ternary operators, etc.

Workflow

Vue doesn’t have an official create-react-app equivalent, though there is the community built create-vue-app.

The official recommendation for bootstrapping a project, however, is vue-cli. It can generate anything from a simple project with one HTML file to a fully decked-out Webpack + Server-Side Rendering project:

Single HTML File Projects

Vue’s creator Evan You dubbed his project a “progressive framework” because it can be scaled up for complex apps, or scaled down for simple apps.

React can do this too, of course. The difference is that Vue projects typically use less ES6 features and rarely use JSX, so there’s usually no need to add Babel. Plus, the Vue library all comes in one file, there’s no separate file for an equivalent of ReactDOM.

Here’s how you add Vue to a single HTML file project:

Note: if you don’t intend to use template strings and therefore don’t need the template compiler, there is a smaller build of Vue that omits this called vue.runtime.js. It’s about 20KB smaller.

Single File Components

If you’re happy to add a build step to your project with a tool like Webpack, you can utilize Vue’s Single File Components (SFCs). These are files which have the .vue extension and encapsulate the component template, JavaScript configuration, and style all in a single file:

These are without a doubt one of the coolest features of Vue because you get a “proper” template with HTML markup, but the JavaScript is right there so there’s no awkward separation of the template and logic.

There’s a Webpack loader called vue-loader which takes care of processing SFCs. In the build process, the template is converted to a render function so this is a perfect use case for the cut-down vue.runtime.js build in the browser.

Redux and More

Vue also has a Flux-based state management library called Vuex. Again, it’s similar to Redux but has a number of differences.

I don’t have time to cover it in this article so I’ll cover it next week’s article. Join my newsletter to get an email update when it’s ready!

Further Reading



Source link

Possibly The Easiest Way to Run an SSG
Strategy

Possibly The Easiest Way to Run an SSG


“Static Site Generator,” that is. We’ll get to that in a second.

Netlify is a sponsor of this site (thank you very much), and I see Zach Leatherman has gone to work over there now. Very cool. Zach is the creator of Eleventy, an SSG for Node. One thing of the many notable things about Eleventy is that you don’t even have to install it if you don’t want to. Lemme set the stage.

Say you have a three-page website, and one of the reasons you want to reach for an SSG is because you want to repeat the navigation on all three pages. An “HTML include,” one of the oldest needs in web development, is in there! We’ve covered many ways to do it in the past. So we have…

/my_project
- index.html
- about.html
- contact.html

And each of those HTML files needs this repeated chunk of navigation.

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Southside Laundromat</title>
  </head>
  <body>
    {{ INCLUDE NAVIGATION HERE }}

    Unique content to this page.

  </body>
</html>

Well why don’t we chuck that block of navigation into a file, so…

/my_project
- /_includes
  - nav.html
- index.html
- about.html
- contact.html

Which is something like…

<nav>
  <a href="/">Home</a>
  <a href="/about/">About</a>
  <a href="/contact/">Contact</a>
</nav>

So how do we actually do the include? This is where Eleventy comes in. Eleventy supports a bunch of templating languages, but the default one is Liquid. Liquid supports file includes! Like this…

{% include ./nav.html %}

So that’s the line I put in each of the three HTML files. How do I process it then? Isn’t this the moment where I have to install Eleventy to get that all going? Nope, I can run a single command on the command line to make this happen (assuming I have npm installed):

npx @11ty/eleventy

Here’s a 30-second video showing it work:

There is no package.json. There is no npm install. In a sense, this is a zero-dependency way to processes a static site, which I think is very cool. Eleventy process it all into a _site folder by default.

Say I want to deploy this static site… over on the Netlify side, I can tell it that what I want deployed is that _site folder. I don’t need to commit it either (and you shouldn’t), so I can put that in a .gitignore file. Netlify can build it with the same exact command.

I could chuck those settings into a file if that is easier to manage than the site itself. Here’s what would go into a netlify.yml file:

build:
  command: "npx @11ty/eleventy"
  publish: _site

As I was working on this baby demo, I ended up wanting a smidge of configuration for Eleventy in that I wanted my CSS files to come over to the processesed site, so…

module.exports = function(eleventyConfig) {
  eleventyConfig.addPassthroughCopy("./styles");
};

That’s all.

The post Possibly The Easiest Way to Run an SSG appeared first on CSS-Tricks.



Source link

GuideGuide for Illustrator
Strategy

GuideGuide for Illustrator


GuideGuide for Illustrator

Hello, I'm looking for the GuideGuide4 extension for illustrator (paid), I definitely didn't like GuideGuide5. If someone has and wants to make an exchange, I have the paid and licensed version 4.7.1 for photoshop.

https://preview.redd.it/8746upzf6xe41.png?width=520&format=png&auto=webp&s=9dfad1c8edaf3e1eb3b07dd3f1deff1b30f25114

submitted by /u/SaOjhon
[comments]



Source link

Final output (Shapes and colors components))
Strategy

Getting Your Head Around Vue.js Scoped Slots


Scoped slots are a useful feature of Vue.js that can make components more versatile and reusable. The only problem is they’re difficult to understand! Trying to get your head around the interweaving of parent and child scopes is like solving a tough math equation.

A good approach when you can’t understand something easily is to try put it to use in solving a problem. In this article, I’ll demonstrate how I used scoped slots to build a reusable list component.

Final output (Shapes and colors components))

Final output (Shapes and colors components)

You can see the finished product in this Codepen.

The Basic Component

The component we’re going to build is called my-list and it displays lists of things. The special feature is that you can customize how the list items are rendered in every usage of the component.

Let’s tackle the simplest use case first, and get my-list to render just one list of things: an array of geometric shape names and the number of sides they have.

app.js

index.html

With a bit of CSS added, that will look the following:

Example output (Shapes component)

Example output (Shapes component)
You may also like:
Building Applications With The Vue 3 Composition API.

Generalizing my-list

Now we want to make my-list versatile enough to render any kind of list. The second test case will be a list of colors, including a small swatch to show what the color looks like.

To do this, we’ll have to abstract any data specific to the shapes list. Since the items in our lists may be structured differently, we’ll give my-list a slot so the parent can define how any particular list will display.

app.js

index.html

Let’s now create two instances of the my-list component in the root instance to display our two test case lists:

app.js

That will look like this:

Example output (shapes and colors)

Example output (shapes and colors)

Superficial Components

What we’ve just created works fine, but is not great code. my-list is, by name, a component for displaying a list. But we’ve had to abstract all the logic for rendering the list into the parent. The component does little more than wrap the list with some presentational markup.

Given that there’s still repeated code in both declarations of the component (i.e. <div class="list-item" v-for="item in ...">), it’d be great if we could delegate this to the component so it isn’t so superficial.

Scoped Slots

To allow us to do this, we’ll use a scoped slot instead of a regular slot. Scoped slots allow you to pass a template to the slot instead of passing a rendered element. It’s called a “scoped” slot because although the template is rendered in the parent scope, it will have access to certain child data.

For example, a component child with a scoped slot might look like the following.

A parent that uses this component will declare a template element in the slot. This template element will have an attribute scope that names an alias object. Any props added to the slot (in the child’s template) are available as properties of the alias object.

Renders as:

Using a Scoped Slot in my-list

Let’s pass the list arrays to my-list as props. Then we can replace the slot with a scoped slot. That way my-list can be responsible for iterating the list items, but the parent can still define how each list item should display.

index.html

Now we get my-list to iterate the items. Inside the v-for loop, item is an alias to the current list item. We can create a slot and bind that list item to the slot using v-bind="item".

app.js

index.html

Note: if you haven’t seen v-bind used without an argument before, this will bind the properties of an entire object to the element. This is useful with scoped slots as often the objects you bind will have arbitrary properties which now don’t need to be specified by name.

Now we’ll return to our root instance and declare a template within the slot of my-list. Looking at the shapes list first, the template must include the scope property to which we assign an alias shape. This alias allows us to access the scoped props. Inside the template, we can use exactly the same markup we had before to display our shape list items.

Now, here’s the full template:

Conclusion

Although this approach has just as much markup as before, it has delegated the common functionality to the component which makes for a more robust design.

Further Reading



Source link