Published: Jun 13, 2017

Bower is going away. Even the bower team is recommending developers to move over to npm (or Yarn which I personally prefer) and Webpack. As one can see from the screenshot, we get the following warning when running npm i bower from cli.

In this post, I will demonstrate how to migrate a legacy bower based project to npm and webpack.

{
"directory": "wwwroot/bower"
}
view raw .bowerrc hosted with ❤ by GitHub

To make it more interesting, the bower is configured so that Front-End dependencies are installed in public web directory. Which means the web directory contains all the public files of libraries and plugins. Including the corresponding source files which by the way we don't want to include in our public files.

First step: migrate to package.json

{
"name": "bower-to-webpack",
"dependencies": {
"datetimepicker": "~2.5.4",
"jquery": "~2.1.4",
"jquery-ui": "~1.11.2",
"lodash": "^4.17.2"
}
}
view raw bower.json hosted with ❤ by GitHub

By running npm install <package@version>, we install all the dependencies form bower.json to the package.json

{
"name": "bower-to-webpack",
"description": "Bye bye Bower! Or how to migrate from Bower to npm and Webpack",
"author": "Andrejs Abrickis",
"dependencies": {
"jquery": "^2.1.4",
"jquery-datetimepicker": "https://github.com/xdan/datetimepicker/archive/2.5.4.tar.gz",
"jquery-ui-dist": "^1.12.1",
"lodash": "^4.17.2"
},
"devDependencies": {
"copy-webpack-plugin": "^4.0.1",
"webpack": "^2.6.1"
},
"scripts": {
"webpack": "webpack"
}
}
view raw package.json hosted with ❤ by GitHub

After installing the package.json looks like this. Note that I’m pointing to some explicit GitHub versions because some of those legacy versions of packages cannot be found on npmjs.org. Another thing you can notice is the devDependencies section containing copy-webpack-plugin and webpack, which I will talk about shortly.

Next step: setting up Webpack.

As you seen I've installed two devDependencies which will replace the bower. First one is webpack, a tool which allows to bundle JS files and perform many more static assets related tasks. One can read more about webpack here.

The second one is copy-webpack-plugin which is used to copy files from source to target destinations. In this case, we are going to copy Front-End dependencies from node_nodules to the public web directory.

const path = require('path');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
// assets.js
const Assets = require('./assets');
module.exports = {
entry: {
app: "./app.js",
},
output: {
path: __dirname + "/wwwroot/",
filename: "[name].bundle.js"
},
plugins: [
new CopyWebpackPlugin(
Assets.map(asset => {
return {
from: path.resolve(__dirname, `./node_modules/${asset}`),
to: path.resolve(__dirname, './wwwroot/npm')
};
})
)
]
};
view raw webpack.config.js hosted with ❤ by GitHub

When set up in webpack.config.js, the plugin works like this. It takes an array of assets objects containing the from path of the file we want to copy. And to path as the destination where we to copy the files. Whenever we run webpack it will copy the files. And this is how with the help of webpack's plugin we can get rid of bower.

To keep the webpack.config.js clean, we can extract and maintain the paths of project’s static assets into a separate JavaScript module.

const CSS = [
'jquery-ui-dist/jquery-ui.min.css',
'jquery-datetimepicker/jquery.datetimepicker.css'
];
const JS = [
'jquery-ui-dist/jquery-ui.min.js',
'jquery-datetimepicker/jquery.datetimepicker.min.js',
'jquery/dist/jquery.min.js',
'lodash/lodash.min.js'
];
module.exports = [...JS, ...CSS];
view raw assets.js hosted with ❤ by GitHub

And the final project structure looks like this. Bower related files and folders can be safely removed and the project will keep running.

I hope with this post I’ve shown that migrating away from bower is not that much of a work. And in the end, we’ve removed an extra dependency of a tool as well as having all the references of Front-End dependencies in a single place in the package.json file.