diff --git a/README.md b/README.md index e07657389..e60bf77f9 100644 --- a/README.md +++ b/README.md @@ -97,11 +97,22 @@ Unfortunately, scripts in package.json can't be commented inline because the JSO Webpack serves your app in memory when you run `npm start`. No physical files are written. However, the web root is /src, so you can reference files under /src in index.html. When the app is built using `npm run build`, physical files are written to /dist and the app is served from /dist. ###How is Sass being converted into CSS and landing in the browser? -Magic! Okay, more specifically: Webpack handles it like this: +Magic! Okay, more specifically, we're handling it differently in dev (`npm start`) vs prod (`npm run build`) + +When you run `npm start`: 1. The sass-loader compiles Sass into CSS 2. Webpack bundles the compiled CSS into bundle.js. Sounds odd, but it works! - 3. Loads styles into the <head> of index.html via JavaScript. This is why you don't see a stylesheet reference in index.html. In fact, if you disable JavaScript in your browser, you'll see the styles don't load either. This process is performed for both dev (`npm start`) and production (`npm run build`). Oh, and since we're generating source maps, you can even see the original Sass source in [compatible browsers](http://thesassway.com/intermediate/using-source-maps-with-sass). + 3. bundle.js contains code that loads styles into the <head> of index.html via JavaScript. This is why you don't see a stylesheet reference in index.html. In fact, if you disable JavaScript in your browser, you'll see the styles don't load either. +The approach above supports hot reloading, which is great for development. However, it also create a flash of unstyled content on load because you have to wait for the JavaScript to parse and load styles before they're applied. So for the production build, we use a different approach: + +When you run `npm run build`: + 1. The sass-loader compiles Sass into CSS + 2. The [extract-text-webpack-plugin](https://github.com/webpack/extract-text-webpack-plugin) extracts the compiled Sass into styles.css + 3. buildHtml.js adds a reference to the stylesheet to the head of index.html. + +For both of the above methods, a separate sourcemap is generated for debugging Sass in [compatible browsers](http://thesassway.com/intermediate/using-source-maps-with-sass). + ###I don't like the magic you just described above. I simply want to use a CSS file. No problem. Reference your CSS file in index.html, and add a step to the build process to copy your CSS file over to the same relative location /dist as part of the build step. But be forwarned, you lose style hot reloading with this approach. diff --git a/package.json b/package.json index a822a6d3f..73a32f18d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-slingshot", - "version": "1.0.3", + "version": "1.1.0", "description": "Starter kit for creating apps with React and Redux", "scripts": { "prestart": "npm run remove-dist", @@ -40,6 +40,7 @@ "eslint": "1.10.3", "eslint-loader": "1.2.0", "eslint-plugin-react": "3.15.0", + "extract-text-webpack-plugin": "1.0.1", "file-loader": "0.8.5", "mocha": "2.3.4", "node-sass": "3.4.2", diff --git a/tools/buildHtml.js b/tools/buildHtml.js index d3a244003..44a2af7f1 100644 --- a/tools/buildHtml.js +++ b/tools/buildHtml.js @@ -14,22 +14,19 @@ var useTrackJs = true; //If you choose not to use TrackJS, just set this to fals var trackJsToken = ''; //If you choose to use TrackJS, insert your unique token here. To get a token, go to https://trackjs.com fs.readFile('src/index.html', 'utf8', function (err,data) { - if (err) { - return console.log(err); - } + if (err) return console.log(err); - var trackJsCode = ''; + var $ = cheerio.load(data); - if (useTrackJs) { - if (trackJsToken) { - trackJsCode = ""; - } else { - console.log('To track JavaScript errors, sign up for a free trial at TrackJS.com and enter your token in /tools/build.html on line 10.'.yellow); - } - } + //since a separate spreadsheet is only utilized for the production build, need to dynamically add this here. + $('head').prepend(''); - var $ = cheerio.load(data); - $('head').prepend(trackJsCode); //add TrackJS tracking code to the top of
+ if (useTrackJs && trackJsToken) { + var trackJsCode = ""; + $('head').prepend(trackJsCode); //add TrackJS tracking code to the top of + } else { + if (useTrackJs) console.log('To track JavaScript errors, sign up for a free trial at TrackJS.com and enter your token in /tools/build.html.'.yellow); + } fs.writeFile('dist/index.html', $.html(), 'utf8', function (err) { if (err) return console.log(err); diff --git a/webpack.config.js b/webpack.config.js index 323405738..c4e2296d9 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -3,6 +3,7 @@ // file generates a webpack config for the environment passed to the getConfig method. var webpack = require('webpack'); var path = require('path'); +var ExtractTextPlugin = require("extract-text-webpack-plugin"); var getPlugins = function(env) { var GLOBALS = { @@ -17,6 +18,7 @@ var getPlugins = function(env) { switch(env) { case 'production': + plugins.push(new ExtractTextPlugin('styles.css')); plugins.push(new webpack.optimize.DedupePlugin()); plugins.push(new webpack.optimize.UglifyJsPlugin({minimize: true, sourceMap: true})); break; @@ -40,19 +42,25 @@ var getEntry = function(env) { return entry; }; -var getLoaders = function () { - return [ - { - test: /\.js$/, +var getLoaders = function (env) { + var loaders = [{test: /\.js$/, include: path.join(__dirname, 'src'), loaders: ['babel', 'eslint']}]; + + if (env == 'production') { + //generate separate physical stylesheet for production build using ExtractTextPlugin. This provides separate caching and avoids a flash of unstyled content on load. + loaders.push({ + test: /(\.css|\.scss)$/, include: path.join(__dirname, 'src'), - loaders: ['babel', 'eslint'] - }, - { + loader: ExtractTextPlugin.extract("css?sourceMap!sass?sourceMap") + }); + } else { + loaders.push({ test: /(\.css|\.scss)$/, include: path.join(__dirname, 'src'), loaders: ['style', 'css?sourceMap', 'sass?sourceMap'] - } - ] + }); + } + + return loaders; }; module.exports = function getConfig(env) { @@ -69,7 +77,7 @@ module.exports = function getConfig(env) { }, plugins: getPlugins(env), module: { - loaders: getLoaders() + loaders: getLoaders(env) } }; };