Skip to content

Instantly share code, notes, and snippets.

@aaronj1335
Created January 17, 2015 20:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aaronj1335/a8d7816ee28c316b3028 to your computer and use it in GitHub Desktop.
Save aaronj1335/a8d7816ee28c316b3028 to your computer and use it in GitHub Desktop.
{
"name": "admin-app",
"version": "0.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "true",
"dev": "./bin/dev.js",
"build": "./bin/build.js"
},
"author": "",
"license": "MIT",
"dependencies": {
"react": "~0.11.1",
"react-router": "0.7.0",
"backbone": "~1.1.2",
"when": "~3.4.4",
"lodash": "~2.4.1",
"suitcss": "~0.6.0"
},
"devDependencies": {
"webpack": "~1.3.3-beta2",
"webpack-dev-middleware": "~1.0.11",
"shelljs": "~0.3.0",
"connect": "~2.25.7",
"connect-logger": "0.0.1",
"proxy-middleware": "~0.5.0",
"webpack-traceur-loader": "~0.3.0",
"style-loader": "~0.8.1",
"file-loader": "~0.7.2",
"envify-loader": "~0.1.0",
"css-loader": "~0.9.0",
"postcss": "~2.2.5",
"postcss-calc": "~2.0.1",
"postcss-custom-media": "~1.2.0",
"postcss-custom-properties": "~0.4.0",
"postcss-loader": "~0.1.0",
"postcss-vars": "~0.1.0",
"resolve": "~1.0.0"
},
"optionalDependencies": {
"login": "git+ssh://git@github.com:WaterfallEngineering/login.git"
}
}
var fs = require('fs');
var join = require('path').join;
var resolve = require('resolve');
var extend = require('lodash').extend;
var postcss = require('postcss');
var dirname = require('path').dirname;
/**
* create maps of variables and custom media queries
*
* because we want to:
*
* - treat every css file as a separate webpack module
* - statically resolve css variables during the build
*
* we run into an issue where we're compiling a css library with variables that
* might be overridden by a later stylesheet. we solve this by resolving all
* variables up front (making a "variable map"), and then using this while
* actually compiling the css during the webpack build.
*
* the downside of this approach is that changing a variable value usually
* requires you to restart the webpack dev build.
*
* this takes a single css filename as an entry point and makes a map of all
* variables, including those defined in `import`'ed css files. it does the
* same for custom media queries.
*/
function makeVarMap(filename) {
var map = {vars: {}, media: {}};
function resolveImport(path, basedir) {
if (path[0] === '/')
return path;
if (path[0] === '.')
return join(basedir, path);
// webpack treats anything starting w/ ~ as a module name, which we're
// about to do below, so just remove leading tildes
path = path.replace(/^~/, '');
return resolve.sync(path, {
basedir: basedir,
packageFilter: function(package) {
var newPackage = extend({}, package);
if (newPackage.style != null)
newPackage.main = newPackage.style;
return newPackage;
}
});
}
function process(filename) {
var style = postcss().process(fs.readFileSync(filename, 'utf8'));
// recurse into each import. because we make the recursive call before
// extracting values (depth-first, post-order traversal), files that import
// libraries can re-define variable declarations, which more-closely
// matches the browser's behavior
style.root.eachAtRule(function(atRule) {
if (atRule.name !== 'import')
return;
var stripped = atRule.params.replace(/^["']/, '').replace(/['"]$/, '');
process(resolveImport(stripped, dirname(filename)));
});
// extract variable definitions
style.root.eachRule(function(rule) {
if (rule.type !== 'rule')
return;
// only variables declared for `:root` are supported for now
if (rule.selectors.length !== 1 ||
rule.selectors[0] !== ':root' ||
rule.parent.type !== 'root')
return;
rule.each(function(decl) {
var prop = decl.prop;
var value = decl.value;
if (prop && prop.indexOf('--') === 0)
map.vars[prop] = value;
});
});
// extract custom media declarations
style.root.eachAtRule(function(atRule) {
if (atRule.name !== 'custom-media')
return;
var name = atRule.params.split(/\s+/, 1)[0];
var nameRe = new RegExp('^' + name + '\\s+');
var rest = atRule.params.replace(nameRe, '');
map.media[name] = rest;
});
}
process(filename);
return map;
}
var map = makeVarMap('src/index.css');
/**
* prepend a tilde to css module imports
*
* webpack's css-loader [treats css imports as relative paths][url-to-req], not
* modules. the easiest way i've found to correct this prepending a `~` to each
* import to force webpack to use it's full module lookup machinery.
*
* [url-to-req]: https://github.com/webpack/css-loader/blob/7b50d4f569adcaf5bf185180c15435bde03f4de7/index.js#L37
*/
function prependTildesToImports(styles) {
styles.eachAtRule(function(atRule) {
if (atRule.name !== 'import')
return;
var stripped = atRule.params.replace(/^["']/, '').replace(/['"]$/, '');
if (stripped[0] !== '.' && stripped[0] !== '~' && stripped[0] !== '/')
atRule.params = '"~' + stripped + '"';
});
}
module.exports = {
entry: './src/index.es6',
resolve: {
packageMains: ['webpack', 'browser', 'web', 'style', 'main'],
extensions: ['', '.webpack.js', '.web.js', '.es6.js', '.js'],
alias: {
underscore: 'lodash',
jquery: 'noop',
debug: 'noop',
promise: 'when/es6-shim/Promise.browserify-es6'
}
},
output: {
path: join(__dirname, 'dist'),
filename: 'index.[hash].js'
},
module: {
loaders: [
{test: /\.es6\.js$/, loader: 'webpack-traceur?runtime'},
{test: /\.css$/, loader: 'style!css?importLoaders=1!postcss'},
{
test: /\.((png)|(eot)|(woff)|(ttf)|(svg))$/,
loader: 'file?name=/[hash].[ext]'
},
{test: /\.js$/, loader: 'envify-loader'}
]
},
postcss: [
prependTildesToImports,
require('postcss-custom-properties')({
variables: map.vars
}),
require('postcss-custom-media')({
extensions: map.media
}),
require('postcss-calc')()
]
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment