Skip to content

Instantly share code, notes, and snippets.

@juliocesar
Last active September 3, 2015 05:48
Show Gist options
  • Save juliocesar/433c0aef45ef4385c03b to your computer and use it in GitHub Desktop.
Save juliocesar/433c0aef45ef4385c03b to your computer and use it in GitHub Desktop.
Ok Build - a build system that's ok, as far as build systems go
{
"ecmaFeatures": {
"globalReturn": true,
"jsx": true,
"modules": true
},
"env": {
"browser": false,
"es6": true,
"node": true,
},
"globals": {
"document": false,
"escape": false,
"navigator": false,
"unescape": false,
"window": false
},
"plugins": [
"react"
],
"rules": {
"block-scoped-var": 0,
"brace-style": [2, "1tbs", { "allowSingleLine": true }],
"camelcase": 0,
"comma-dangle": [2, "never"],
"comma-spacing": [2, { "before": false, "after": true }],
"comma-style": [2, "last"],
"complexity": 0,
"consistent-return": 0,
"consistent-this": 0,
"curly": [2, "multi-line"],
"default-case": 0,
"dot-notation": 0,
"eol-last": 2,
"eqeqeq": [2, "allow-null"],
"func-names": 0,
"func-style": [0, "declaration"],
"generator-star": [2, "middle"],
"guard-for-in": 0,
"handle-callback-err": [2, "^(err|error|anySpecificError)$" ],
"indent": [2, 2],
"key-spacing": [2, { "beforeColon": false, "afterColon": true }],
"max-depth": 0,
"max-len": 0,
"max-nested-callbacks": 0,
"max-params": 0,
"max-statements": 0,
"new-cap": [2, { "newIsCap": true, "capIsNew": false }],
"new-parens": 2,
"no-alert": 2,
"no-array-constructor": 2,
"no-bitwise": 0,
"no-caller": 2,
"no-catch-shadow": 0,
"no-cond-assign": 2,
"no-console": 0,
"no-constant-condition": 0,
"no-control-regex": 2,
"no-debugger": 2,
"no-delete-var": 2,
"no-div-regex": 0,
"no-dupe-args": 2,
"no-dupe-keys": 2,
"no-duplicate-case": 2,
"no-else-return": 0,
"no-empty": 0,
"no-empty-class": 2,
"no-empty-label": 2,
"no-eq-null": 0,
"no-eval": 2,
"no-ex-assign": 2,
"no-extend-native": 2,
"no-extra-bind": 2,
"no-extra-boolean-cast": 2,
"no-extra-parens": 0,
"no-extra-semi": 0,
"no-extra-strict": 0,
"no-fallthrough": 2,
"no-floating-decimal": 2,
"no-func-assign": 2,
"no-implied-eval": 2,
"no-inline-comments": 0,
"no-inner-declarations": [2, "functions"],
"no-invalid-regexp": 2,
"no-irregular-whitespace": 2,
"no-iterator": 2,
"no-label-var": 2,
"no-labels": 2,
"no-lone-blocks": 0,
"no-lonely-if": 0,
"no-loop-func": 0,
"no-mixed-requires": [0, false],
"no-mixed-spaces-and-tabs": [2, false],
"no-multi-spaces": 2,
"no-multi-str": 2,
"no-multiple-empty-lines": [2, { "max": 1 }],
"no-native-reassign": 2,
"no-negated-in-lhs": 2,
"no-nested-ternary": 0,
"no-new": 2,
"no-new-func": 2,
"no-new-object": 2,
"no-new-require": 2,
"no-new-wrappers": 2,
"no-obj-calls": 2,
"no-octal": 2,
"no-octal-escape": 2,
"no-path-concat": 0,
"no-plusplus": 0,
"no-process-env": 0,
"no-process-exit": 0,
"no-proto": 2,
"no-redeclare": 2,
"no-regex-spaces": 2,
"no-reserved-keys": 0,
"no-restricted-modules": 0,
"no-return-assign": 2,
"no-script-url": 0,
"no-self-compare": 2,
"no-sequences": 2,
"no-shadow": 0,
"no-shadow-restricted-names": 2,
"no-spaced-func": 2,
"no-sparse-arrays": 2,
"no-sync": 0,
"no-ternary": 0,
"no-throw-literal": 2,
"no-trailing-spaces": 2,
"no-undef": 2,
"no-undef-init": 2,
"no-undefined": 0,
"no-underscore-dangle": 0,
"no-unreachable": 2,
"no-unused-expressions": 0,
"no-unused-vars": [2, { "vars": "all", "args": "none" }],
"no-use-before-define": 0,
"no-var": 0,
"no-void": 0,
"no-warning-comments": [0, { "terms": ["todo", "fixme", "xxx"], "location": "start" }],
"no-with": 2,
"no-wrap-func": 2,
"one-var": 0,
"operator-assignment": [0, "always"],
"padded-blocks": [2, "never"],
"quote-props": 0,
"quotes": [2, "single", "avoid-escape"],
"radix": 2,
"react/display-name": 0,
"react/jsx-boolean-value": 2,
"react/jsx-quotes": [2, "double", "avoid-escape"],
"react/jsx-no-undef": 2,
"react/jsx-sort-props": 0,
"react/jsx-uses-react": 2,
"react/jsx-uses-vars": 2,
"react/no-did-mount-set-state": 2,
"react/no-did-update-set-state": 2,
"react/no-multi-comp": 2,
"react/no-unknown-property": 2,
"react/prop-types": 2,
"react/react-in-jsx-scope": 2,
"react/self-closing-comp": 2,
"semi": [2, "never"],
"semi-spacing": 0,
"sort-vars": 0,
"space-after-keywords": [2, "always"],
"space-before-blocks": [2, "always"],
"space-in-brackets": 0,
"space-in-parens": [2, "never"],
"space-infix-ops": 2,
"space-return-throw-case": 2,
"space-unary-ops": [2, { "words": true, "nonwords": false }],
"spaced-line-comment": [2, "always"],
"strict": 0,
"use-isnan": 2,
"valid-jsdoc": 0,
"valid-typeof": 2,
"vars-on-top": 0,
"wrap-iife": [2, "any"],
"wrap-regex": 0,
"yoda": [2, "never"]
}
}
// Build tasks
// ===========
var gulp = require('gulp');
var utils = require('gulp-util');
// Testing
var jest = require('gulp-jest');
var packageJson = Object.create(require('./package.json'));
gulp.task('jest', function() {
return gulp.src(".")
.pipe(jest(packageJson.jest));
});
// Build configurations.
var path = require('path');
var Config = {
srcDir: path.resolve('./src'),
publicDir: path.resolve('./public')
};
// Environment detection
var currentEnv = process.env.NODE_ENV === 'production' ?
'production' : 'development';
utils.log(
'Environment', utils.colors.blue(currentEnv)
);
// Webpack build
var webpack = require('webpack');
var webpackConfig = Object.create(require('./webpack.config.js'));
var CompressionPlugin = require('compression-webpack-plugin');
gulp.task('webpack:build', function(callback) {
webpackConfig.output.path = Config.publicDir;
webpackConfig.devtool = '#source-map';
webpackConfig.progress = true;
if (currentEnv === 'production') {
webpackConfig.bail = true;
webpackConfig.debug = false;
webpackConfig.profile = false;
webpackConfig.entry = ['./src/boot'];
webpackConfig.output.pathInfo = false;
webpackConfig.plugins.push(
new webpack.DefinePlugin({
'process.env': currentEnv
}),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({
mangle: { except: ['require', 'export', 'import', '$super'] },
compress: {
sequences: true,
dead_code: true,
conditionals: true,
booleans: true,
unused: true,
if_return: true,
join_vars: true,
drop_console: true,
warnings: false
}
}),
new CompressionPlugin({
asset: "{file}.gz",
algorithm: "gzip",
threshold: 10240,
minRatio: 0.8
})
);
}
webpack(webpackConfig, function(err, stats) {
if (err) throw new utils.PluginError('webpack:build', err);
utils.log('Webpack', stats.toString({
colors: true,
chunks: false
}));
callback();
});
});
// Webpack server
var WebpackDevServer = require('webpack-dev-server');
var WebpackNotifier = require('webpack-notifier')
gulp.task('webpack:serve', function() {
webpackConfig.plugins.push(new WebpackNotifier({ title: 'Build' }));
var hostname = 'localhost';
var port = 4567;
var compiler = webpack(webpackConfig);
var server = new WebpackDevServer(compiler, {
contentBase: webpackConfig.contentBase,
publicPath: webpackConfig.output.publicPath,
historyApiFallback: true,
noInfo: true,
hot: true,
stats: {
colors: true,
chunks: false
}
});
server.listen(port, hostname, function(err) {
if (err) throw new utils.PluginError('webpack:serve', err);
utils.log("Starting", utils.colors.red("Webpack Dev Server"));
utils.log(
"Listening on",
utils.colors.red("http://" + hostname + ":" + port)
);
});
});
// ESLint. I can't figure out where gulp-eslint is trying to find the
// .eslintignore file, so I'm relying on gulp for exclusions for now. Excluding
// tests because otherwise it screams about Jest/Jasmine magic.
var eslint = require('gulp-eslint');
gulp.task('eslint', function() {
return gulp.src([Config.srcDir + '/**/*.js*', '!**/tests/**'])
.pipe(eslint())
.pipe(eslint.format())
});
// Watch.
gulp.task('watch', function() {
gulp.watch(Config.srcDir + '/**/*.js*', ['eslint', 'jest']);
});
gulp.task('build', ['eslint', 'webpack:build']);
gulp.task('default', ['webpack:serve', 'build', 'watch']);
// Sass index file
// ===============
//
// Because CSS load order matters, we can’t rely on simply bundling everything.
// So this manifest is still needed.
// Dependencies
// @import …
// Components
@import '../components/**/*';
{
"dependencies": {
"airwaves": "^0.3.0",
"classnames": "^2.1.3",
"lodash": "^3.10.0",
"rc-animate": "^1.1.0",
"react": "0.13.3",
"react-mixin": "^1.6.0",
"superagent": "^1.2.0",
"tinycolor2": "^1.1.2"
},
"scripts": {
"test": "BABEL_JEST_STAGE=1 jest"
},
"jest": {
"scriptPreprocessor": "node_modules/babel-jest",
"testDirectoryName": "tests",
"setupEnvScriptFile": "tests/setup.js",
"modulePathIgnorePatterns": [
"node_modules",
"tests/mocks",
"tests/setup.js"
],
"unmockedModulePathPatterns": [
"node_modules/react",
"node_modules/rosie",
"node_modules/moment",
"src/components",
"tests/mocks",
"object-assign",
"babel"
],
"moduleFileExtensions": [
"js",
"json",
"jsx"
],
"testFileExtensions": [
"js"
]
},
"devDependencies": {
"autoprefixer-loader": "^2.0.0",
"babel": "^5.8.3",
"babel-core": "^5.8.3",
"babel-eslint": "^3.1.26",
"babel-jest": "^5.3.0",
"babel-loader": "^5.3.2",
"babel-runtime": "^5.8.3",
"compression-webpack-plugin": "^0.2.0",
"css-loader": "^0.15.5",
"eslint": "^0.24.1",
"eslint-plugin-react": "^3.0.0",
"gulp": "^3.9.0",
"gulp-eslint": "^0.15.0",
"gulp-jest": "^0.4.0",
"gulp-util": "^3.0.6",
"jest-cli": "^0.4.16",
"jsx-loader": "^0.13.2",
"object-assign": "^3.0.0",
"react-hot-loader": "^1.2.8",
"react-tools": "0.13.3",
"ruby-sass-loader": "^0.2.0",
"style-loader": "^0.12.3",
"webpack": "^1.10.3",
"webpack-dev-server": "^1.10.1",
"webpack-notifier": "^1.2.1"
}
}
// Webpack configuration
// =====================
var path = require('path');
var webpack = require('webpack');
module.exports = {
contentBase: __dirname + '/public',
devtool: 'eval-source-map',
entry: [
'webpack-dev-server/client?http://localhost:4567',
'webpack/hot/dev-server',
'./src/boot'
],
output: {
pathInfo: true,
path: __dirname + '/public/',
publicPath: '',
filename: 'bundle.js'
},
module: {
loaders: [
{
test: /\.js[x]?$/,
exclude: /node_modules/,
loaders: ['react-hot', 'babel-loader?optional=runtime']
},
{
test: /\.scss$/,
exclude: /node_modules/,
loader: 'style!css!autoprefixer!ruby-sass?requires[]=sass-globbing'
}
]
},
resolve: {
extensions: ['', '.js', '.json', '.jsx']
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
]
};
@juliocesar
Copy link
Author

This is still incomplete. Assumptions:

  • All source goes in <rootdir>/src/.
  • All components go in <rootdir>/src/components. Everything is a component, whether it's a view, or something from the data layer, or a router.
  • Tests go in <rootdir>/tests/.
  • An individual component has a <rootdir>/src/components/foo/index.jsx(or just .js), and if it has styles, a corresponding index.scss in the same directory. The index file is the "base" file and can carry actual code in it. If a component has more files, name them appropriately under the same directory, then source it from the index file.
  • There's a <rootdir>/src/boot.jsx file which is the application bootstrap file, that initiates the router and connects the higher level components, including adding the top-level component to the DOM.
  • The index.scss file above should go in <rootdir>/stylesheets/.
  • The .eslintrc file above is the one from feross/standard, with a few modifications. I'll list them properly when I turn this into a repo, but they were minor annoyances, so no huge departures.
  1. Run npm install.
  2. Run gulp.
  3. Server will run on localhost:4567.

@lachlanhardy
Copy link

Thanks, brother. We'll futz with it and tell you what you think. Right @gon, @cazrin?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment