How to write a webpack scaffold

Also known as: “Choosing a title is harder than writing an article”

Setting up a new project may require some time, you may want to organize your files in an appropriate project structure, choose the right tools, configure them and make them work together. This is often time-consuming and can be hard for beginners, for these reasons we have many tools like create-react-app, vue create and yeoman helping us kickstart our projects.

Scaffolding with Webpack

What if we could just create a webpack configuration file without having to write it by hands? Wouldn’t the world be a better place?

Yes, it would.

If you agree with me, you will be happy to know that webpack-cli actually has a command that guides you setting up a configuration file just by answering some questions. Take a look at the webpack-cli init documentation.

In this article, we will dig under the hood and see how to create and publish a webpack scaffold to set up a vue project.

How does it look

I’ve published a scaffold called “webpack-scaffold-vue” to npm, if you have webpack-cli you can try it by running:

webpack-cli init webpack-scaffold-vue

You will be asked to answer some questions:

And your folder will fill with nice stuff. You can quickly try your brand new project running:

yarn serve

Setup

I’ve decided to call my package “webpack-scaffold-vue”, we start creating our package:

mkdir webpack-scaffold-vue
cd webpack-scaffold-vue
npm init
touch index.js
A scaffold is just a npm package, to make it discoverable by webpack-cli it should be published and it’s name must begin with “webpack-scaffold-”

Under the hood, the scaffolding system uses Yeoman to define generators, let’s install it:

yarn add yeoman-generator

Inside index.js we can now create the skeleton of our scaffold extending the Generator class:

prompting, write and install are Yeoman methods that we are going to use in the next steps if you want to know more check Yeoman’s documentation

Inside our constructor, we create a JSON object that we will transform into a webpack configuration file:

Notice that we are creating an object called “configurations”, each of its properties will become a webpack configuration created using the values from webpackOptions

“Wait, our dev.webpackOptions is empty…”, don’t worry, we will fill it soon with the data given by our user.

Prompting

Now that our skeleton is in place it’s time to print some questions to get the user preferences. Yeoman uses Inquirer, we are going to install a package called webpack-scaffold that offers some utilities to quickly define Inquirer prompts:

yarn add @webpack-cli/webpack-scaffold

Inside the prompting method, we use this.prompt(…), a Yeoman function that prints an array of prompts in the terminal sequentially and returns the user responses:

We want to use the answer to the first question as the name of our scaffolded project. Since we want this name to be compliant with npm naming rules, we have to check if the value provided by the user doesn’t contain spaces or uppercase letters. We can do this using an InputValidate from the webpack-scaffold package, that allows us to validate the user input using a function:

Now that we have created our prompts we can see it working, let’s create the folder where we are going to test our scaffold:

cd ..
mkdir test-scaffold
cd test-scaffold
webpack-cli init ../webpack-scaffold-vue

If we’ve done everything right we should see in the terminal the questions we’ve just created!

Create configurations

Before beginning, we take the user answers and we replace each missing answer with its default value. We then store the updated answers in a class attribute to make it available to other methods:

Now that we have the user preferences in this.answers we can start working on our configurations 🎉🎉

First of all, we want to generate a webpack.config.js file. We will do this by creating a function that generates a valid webpack configuration given the user preferences. We keep it in a separate file named config/webpack-config.js that looks like:

There are many other options available, check the webpack documentation

You may have noticed that in the code above we use VueLoaderPlugin, HtmlWebpackPlugin and CopyWebpackPlugin. Those are webpack plugins and need to be imported in our generated webpack configuration in order to work. We do this setting dev.topScope which is a property used to add some code at the beginning of our configuration:

Writing to the file system

Now comes the best part, we write everything to the file system feeling very proud of ourselves

It’s time to implement our writing() method, that’s the Yeoman method where all the should be placed. We will write on the file system 3 different kinds of files:

1. Webpack configurations

We use the configuration object we prepared in the previous steps:

That’s it, this will create a .yo-rc.json file that will be picked up by webpack-cli to generate a webpack configuration file in the root directory of the scaffolded project.

You can generate more than one configuration file by adding different keys in your configuration object

2. JSON files

We use Yeoman fs.extendJSON(destPath, json) function to write a JSON to a file in the file system, as we did before we will have many modules each exporting a function that returns our JSON configuration. Let’s generate the package.json using user preferences:

In the previous code, we have created the package.json and other configuration files for eslint and babel.

3. Templates

For non-JSON files we use fs.copyTpl(srcPath, dstPath, param) to copy any template file from our scaffold directory to our scaffolded project:

Install dependencies

We expand our Generator again adding a Yeoman method called install() and we use this.installDependencies() to install the dependencies we specified in our package.json:

This will only use yarn, remember to use the package manager specified by the user.

Publish

Install np (Sindresorhus ❤️):

yarn add np

Run np, it will guide you publishing your package to npm:

yarn np

Cheers!

Congratulation to us, we just published a webpack scaffold!

Now the most important part, let me know what you have created! You can tweet to @misterdev_ and leave feedback in the comments!