Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I setup webpack to minify and combine scss and javascript like CodeKit?

I'm having trouble using webpack instead of Codekit v1.9.3. I started working to move from CodeKit to Grunt and Gulp, and then learned about webpack which sounds very cool. I just can't seem to get it working correctly.

"Like Codekit" means I can:

  • Write javascript with the coffeescript syntax
  • Have all script source files and libraries minified / uglified and combined into one file
  • Selectively include components of the bootstrap-sass (scss) framework as needed
  • Maintain a small file with bootstrap customizations via sass variables, like $brand-primary
  • Use webpack --watch to compile both scripts and styles automatically when they are changed
  • End up with one css file and one script file that can be included with a stylesheet and script tag.

Codekit Project Setup

Bower resources:

I'm currently storing these globally, outside of the project:

~/bower_components/twbs-bootstrap-sass/vendor/assets/stylesheets 

Because CodeKit supports compass, I've got this in my config.rb file:

add_import_path "~/bower_components/twbs-bootstrap-sass/vendor/assets/stylesheets" 

Project Structure

js/fancybox.js js/main.js               <-- currently the compiled js 'output' file js/main.coffee  css/styles.css           <-- currently the compiled css 'output' file  scss/styles.scss scss/modules/_bootstrap-customizations.scss scss/modules/_typography.scss scss/partials/_header.scss scss/partials/_footer.scss 

Contents of styles.scss

@import "modules/bootstrap-customizations";  # local customizations @import "bootstrap/variables"; @import "bootstrap/mixins"; ...                                          # load bootstrap files as required @import "bootstrap/wells"; 

System Setup:

  • system: OS X 10.9
  • node - v0.10.32
  • npm - v2.1.7
  • zsh - zsh 5.0.7 (x86_64-apple-darwin13.4.0)

node was installed with homebrew's brew install node and seems to be working fine otherwise.


What I've Tried

I've read over these pages:

  • http://webpack.github.io/docs/configuration.html
  • https://github.com/petehunt/webpack-howto
  • http://webpack.github.io/docs/tutorials/getting-started/
  • https://www.npmjs.org/package/bootstrap-sass-webpack

I've attempted to create a webpack.config.js file several times, my latest attempt was several versions of this:

module.exports = {     entry: [     "./node_modules/bootstrap-sass-webpack!./bootstrap-sass.config.js",     "./js/main.coffee"     ],     output: {         path: __dirname,         filename: "main.js"     },     module: {         loaders: [         { test: /\.css$/, loader: "style!css" }         ]     } }; 

Webpack Error

When I run webpack I get this:

ERROR in ./~/bootstrap-sass-webpack/~/css-loader!/Users/cwd/~/sass-loader!./~/bootstrap-sass-webpack/bootstrap-sass-styles.loader.js!./bootstrap-sass.config.js stdin:1: file to import not found or unreadable: "~bootstrap-sass/assets/stylesheets/bootstrap/variables 

NPM Error

I get an error when attempting to npm install bootstrap-sass, and not had any luck when searching for a solution. I'm not even sure I need this module.

npm ERR! Darwin 13.4.0 npm ERR! argv "node" "/usr/local/bin/npm" "install" "bootstrap-sass" npm ERR! node v0.10.32 npm ERR! npm  v2.1.7 npm ERR! code EPEERINVALID  npm ERR! peerinvalid The package bootstrap-sass does not satisfy its siblings' peerDependencies requirements! npm ERR! peerinvalid Peer [email protected] wants bootstrap-sass@~3.2.0  npm ERR! Please include the following file with any support request: npm ERR!     /Users/cwd/webpack-test/npm-debug.log 

Sources of Confusion

The most confusing parts of webpack for me are:

  1. Where should things like require("bootstrap-sass-webpack") be added - is it in the webpack.config.js file, or in the js/main.js file?
  2. Should modules like this available to webpack as soon as they are installed with npm install ?
  3. I thought that I should do npm install webpack -g so that webpack was installed globally, and use npm install without the -g for the other modules. However, I don't see any node_modules folder being created in my project. Shouldn't there be one?
  4. How are the search paths determined / specified for things like require("bootstrap-sass-webpack") ?

What node modules should I install to be able to do this? And what should my webpack.config.js look like?

like image 407
cwd Avatar asked Nov 10 '14 19:11

cwd


1 Answers

Introduction

Webpack is mainly a JavaScript-bundler. Its "native" language is JavaScript and every other source requires a loader which transforms it to JavaScript. If you require() an html-file for example...

var template = require("./some-template.html"); 

...you'll need the html-loader. It turns...

<div>     <img src="./assets/img.png"> </div> 

...into...

module.exports = "<div>\n    <img src=\"" + require("./assets/img.png") + "\">\n</div>"; 

If a loader doesn't return JavaScript, it needs to be "piped" to another loader.


How to load SASS-files

Configure loaders

In order to use SASS you'll need at least the sass-loader and the css-loader. The css-loader returns a JavaScript string. If you want to import the returned JavaScript string as StyleSheet, you'll also need the style-loader.

Run npm i sass-loader css-loader style-loader --save

Now you need to apply these loaders on all files that match /\.scss$/:

// webpack.config.js ... module: {     loaders: [         // the loaders will be applied from right to left         { test: /\.scss$/, loader: "style!css!sass" }     ] } ... 

You can also pass options to node-sass as query parameters:

{     test: /\.scss$/, loader: "style!css!sass?includePaths[]=" +          path.resolve(__dirname, "./bower_components/bootstrap-sass/assets/stylesheets/" } 

Since bootstrap references icons via the url() statement, the css-loader will try to include these assets into the bundle and will throw an exception otherwise. That's why you'll also need the file-loader:

// webpack.config.js ... module: {     loaders: [         { test: /\.scss$/, loader: "style!css!sass" },         { test: /\.jpe?g$|\.gif$|\.png$|\.svg$|\.woff$|\.ttf$/, loader: "file" },     ] } ... 

Configure entry

To include bootstrap into your bundle there are several ways. One is via the multi-entry option as you've already tried. I recommend to use a single entry where you require() your main sass-file:

// main.js require("./main.scss"); 

Given that your includePaths are configured then you can do:

// main.scss // Set the font path so that url() points to the actual file $icon-font-path: "../../../fonts/bootstrap";  @import "bootstrap"; 

Please note that import statements inside scss-files are not touched by webpack because libsass has no api (yet) to provide custom resolvers.

To prevent code duplication it's also important to have a single main sass-file, because webpack compiles every sass-file individually.

With the coffee-loader installed via npm your final webpack.config.js should look like:

module.exports = {     entry: "./js/main.coffee",     output: {         path: __dirname,         filename: "main.js"     },     module: {         loaders: [             { test: /\.scss$/, loader: "style!css!sass" },             { test: /\.jpe?g$|\.gif$|\.png$|\.svg$|\.woff$|\.ttf$/, loader: "file" },             { test: /\.coffee$/, loader: "coffee" }         ]     } }; 

Webpack globally?

It's best not to install webpack globally, because it's a dependency of your project and thus should be controlled via npm. You can use the scripts-section of your package.json:

{     ...     "scripts": {         "start": "webpack --config path/to/webpack.config.js & node server.js"     } } 

Then you just need to run npm start

like image 76
Johannes Ewald Avatar answered Sep 16 '22 18:09

Johannes Ewald