├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── build.sh ├── content ├── blog │ ├── 2015-11-01-test-post.md │ └── index.md ├── index.md ├── robots.txt └── sitemap.xml ├── gulpfile.js ├── layouts ├── blog-post.html ├── blog.html ├── index.html ├── partials │ ├── default.html │ ├── footer.html │ └── header.html ├── robots.html └── sitemap.html ├── lib └── handlebars.js ├── package.json ├── public ├── scripts ├── app.js ├── functions.js ├── pages │ └── home.js └── util │ └── dom.js ├── site.js ├── sources └── favicon.ico └── styles ├── _variables.scss ├── app.scss ├── components └── _buttons.scss ├── layout ├── _container.scss ├── _content.scss ├── _footer.scss ├── _global.scss └── _header.scss └── pages └── _home.scss /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | [*.json] 14 | insert_final_newline = false 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | build 4 | sources/assets/*.js 5 | sources/assets/*.css 6 | sources/vendor 7 | .tmp 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Evocode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Metalsmith Base 2 | 3 | A metalsmith base starter kit used at [Evocode.com](http://evocode.com/). Some features: 4 | 5 | - [Metalsmith](http://metalsmith.io/) 6 | - [Gulp](http://gulpjs.com/) 7 | - [Bootstrap 4](https://github.com/twbs/bootstrap/tree/v4-dev) 8 | - [jQuery](https://github.com/jquery/jquery) 9 | - [Babel / ES6](https://babeljs.io/) 10 | - [Development Server](https://github.com/evocode/metalsmith-base/blob/master/gulpfile.js#L160) 11 | - [Static Site, Blog, Robots, Sitemap](https://github.com/evocode/metalsmith-base/tree/master/content) 12 | - [MIT license](https://github.com/evocode/metalsmith-base/blob/master/LICENSE) 13 | 14 | ## Install 15 | 16 | ``` 17 | mkdir newproject 18 | git clone git@github.com:evocode/metalsmith-base.git newproject 19 | cd newproject 20 | npm install 21 | ``` 22 | ## Develop 23 | 24 | This command will fully build a development version of the site, start the gulp watchers, and setup a development server. The command output will list the server address to open in your browser. 25 | 26 | ``` 27 | npm run start 28 | ``` 29 | 30 | ## Build 31 | 32 | This command will build a production version of the site and sync it with a git repository, ready to be comitted. 33 | 34 | To link the build process to your repository, you can do of the following options: 35 | 36 | 1. Create a repo dotfile: `echo "git@github.com:username/repository.git" > .buildrepo` 37 | 1. Edit `package.json` script section: `"build": "./node_modules/.bin/gulp --production --build && ./build.sh git@github.com:username/repository.git"` 38 | 39 | After the repository is setup, simply run: 40 | 41 | ``` 42 | npm run build 43 | ``` 44 | 45 | ## Commands 46 | 47 | 1. `npm run dev` - Run a development build 48 | 1. `npm run start` - Run a development build, start the development server and watchers 49 | 1. `npm run debug` - Run a development build in debug mode 50 | 1. `npm run production` - Run a production build, compiles assets and minifies 51 | 1. `npm run build` - Run a production build and sync with git 52 | 1. `npm run watch` - Start the gulp watchers 53 | 1. `npm run vendor` - Copies over any vendor files from node_modules to metalsmith assets 54 | 55 | All commands can be run directly with: `./node_modules/.bin/gulp` 56 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Build script - It will setup a git repository in the build directory. 3 | # 4 | 5 | REPO=$1 6 | HERE=$(pwd) 7 | #TMP_FOLDER=$(mktemp -d) 8 | TMP_FOLDER=.tmp 9 | 10 | if [ -z "$REPO" ]; then 11 | REPO=$(cat .buildrepo) 12 | fi 13 | 14 | if [ -z "$REPO" ]; then 15 | echo "GIT REPO required" 16 | exit 1 17 | fi 18 | 19 | mkdir $TMP_FOLDER 20 | cd $TMP_FOLDER 21 | git init 22 | git remote add origin $REPO 23 | git fetch 24 | git checkout master 25 | cd $HERE 26 | mv $TMP_FOLDER/.git build/.git 27 | rm -rf $TMP_FOLDER 28 | -------------------------------------------------------------------------------- /content/blog/2015-11-01-test-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Test Post 3 | url: test-post 4 | description: Test Post 5 | collection: blog 6 | paginate: blog 7 | layout: blog-post.html 8 | date: 2015-11-01 9 | draft: false 10 | --- 11 | 12 | # Test Post # 13 | 14 | Test Content 15 | -------------------------------------------------------------------------------- /content/blog/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Blog 3 | url: / 4 | description: Blog Page 5 | layout: blog.html 6 | permalink: false 7 | --- 8 | -------------------------------------------------------------------------------- /content/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Index 3 | url: / 4 | description: Index Page 5 | layout: index.html 6 | permalink: false 7 | function: home 8 | --- 9 | -------------------------------------------------------------------------------- /content/robots.txt: -------------------------------------------------------------------------------- 1 | --- 2 | layout: robots.html 3 | --- 4 | -------------------------------------------------------------------------------- /content/sitemap.xml: -------------------------------------------------------------------------------- 1 | --- 2 | layout: sitemap.html 3 | --- 4 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | // Common 2 | var path = require('path'); 3 | var argv = require('minimist')(process.argv.slice(2)); 4 | var gulp = require('gulp'); 5 | var Metalsmith = require('metalsmith'); 6 | 7 | // Assets 8 | var sass = require('gulp-sass'); 9 | var autoprefixer = require('gulp-autoprefixer'); 10 | var webpack = require('webpack'); 11 | 12 | // Site 13 | var site = require('./site'); 14 | 15 | // Handlebars 16 | var Handlebars = require('handlebars'); 17 | var HandlebarsLib = require('./lib/handlebars')(Handlebars); 18 | 19 | // Configuration 20 | var args = { 21 | build: !!argv.build, 22 | production: !!argv.production 23 | }; 24 | 25 | // Metalsmith 26 | function setupMetalsmith(callback) { 27 | var ms = new Metalsmith(process.cwd()); 28 | var msconfig = site.metalsmith || {}; 29 | var msplugins = msconfig.plugins || {}; 30 | 31 | ms.source(msconfig.config.contentRoot); 32 | ms.destination(msconfig.config.destRoot); 33 | ms.metadata(msconfig.metadata); 34 | 35 | Object.keys(msplugins).forEach(function(key) { 36 | var plugin = require(key); 37 | var options = msplugins[key]; 38 | 39 | if (options._metalsmith_if !== undefined) { 40 | var condition = false; 41 | if (options._metalsmith_if === "production") { 42 | condition = argv.production; 43 | } else if (options._metalsmith_if === "build") { 44 | condition = argv.build; 45 | } 46 | 47 | if (condition) { 48 | options._metalsmith_if = undefined; 49 | delete options._metalsmith_if; 50 | ms.use(plugin(options)); 51 | } 52 | } else { 53 | ms.use(plugin(options)); 54 | } 55 | }); 56 | 57 | ms.build(function(err) { 58 | if (err) { 59 | console.log(err); 60 | return callback(err); 61 | } 62 | 63 | callback(); 64 | }); 65 | } 66 | 67 | //Gulp tasks 68 | 69 | gulp.task('metalsmith', function(callback) { 70 | setupMetalsmith(callback); 71 | }); 72 | 73 | gulp.task('vendor', function() { 74 | return gulp.src(site.vendor) 75 | .pipe(gulp.dest(path.join(__dirname, site.metalsmith.config.assetRoot, 'vendor'))); 76 | }); 77 | 78 | gulp.task('styles', function() { 79 | return gulp.src(path.join(__dirname, site.metalsmith.config.styleRoot, 'app.scss')) 80 | .pipe(sass({ 81 | sourceComments: args.production ? false : true, 82 | outputStyle: args.production ? 'compressed' : 'expanded', 83 | includePaths: site.styles.include, 84 | errLogToConsole: true, 85 | onError: console.log 86 | })) 87 | .pipe(autoprefixer({ 88 | browsers: site.styles.prefix, 89 | cascade: false 90 | })) 91 | .pipe(gulp.dest(path.join(__dirname, site.metalsmith.config.assetRoot, 'assets'))); 92 | }); 93 | 94 | gulp.task('webpack', function(callback) { 95 | var webpackPlugins = [ 96 | new webpack.ProvidePlugin({ 97 | $: "jquery", 98 | jQuery: "jquery" 99 | }), 100 | new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js'), 101 | new webpack.DefinePlugin({ 102 | "process.env": { 103 | NODE_ENV: JSON.stringify(args.production ? 'production' : 'development'), 104 | }, 105 | }) 106 | ]; 107 | 108 | if (args.production) { 109 | webpackPlugins.push(new webpack.optimize.UglifyJsPlugin({minimize: true})); 110 | } 111 | 112 | var webpackConfig = { 113 | context: path.join(__dirname, site.metalsmith.config.scriptRoot), 114 | entry: { 115 | app: './app', 116 | vendor: ['jquery'] 117 | }, 118 | output: { 119 | path: path.join(__dirname, site.metalsmith.config.assetRoot, 'assets'), 120 | filename: '[name].js' 121 | }, 122 | resolveLoader: { 123 | root: path.join(__dirname, 'node_modules') 124 | }, 125 | module: { 126 | loaders: [ 127 | { 128 | test: /\.jsx?$/, 129 | exclude: /(node_modules|bower_components)/, 130 | loader: 'babel?optional[]=runtime&stage=0' 131 | } 132 | ] 133 | }, 134 | plugins: webpackPlugins 135 | }; 136 | 137 | webpack(webpackConfig, function(err, stats) { 138 | if (err) { 139 | return callback(err); 140 | } 141 | 142 | //console.log(stats.toString({})); 143 | callback(); 144 | }); 145 | }); 146 | 147 | gulp.task('scripts', ['webpack']); 148 | 149 | gulp.task('watch', ['default'], function() { 150 | gulp.watch(['gulpfile.js', 'site.js'], ['default']); 151 | gulp.watch([site.metalsmith.config.styleRoot+'/**/*'], ['styles']); 152 | gulp.watch([site.metalsmith.config.scriptRoot+'/**/*'], ['scripts']); 153 | gulp.watch([ 154 | site.metalsmith.config.contentRoot+'/**/*', 155 | site.metalsmith.config.layoutRoot+'/**/*', 156 | site.metalsmith.config.assetRoot+'/**/*' 157 | ], ['metalsmith']); 158 | }); 159 | 160 | gulp.task('server', ['default', 'watch'], function(callback) { 161 | var http = require('http'); 162 | var serveStatic = require('serve-static'); 163 | var finalhandler = require('finalhandler'); 164 | 165 | var serve = serveStatic(site.metalsmith.config.destRoot, { 166 | "index": ['index.html', 'index.htm'] 167 | }); 168 | 169 | var server = http.createServer(function(req, res){ 170 | var done = finalhandler(req, res); 171 | serve(req, res, done); 172 | }) 173 | 174 | var serverPort = Math.floor((Math.random() * 1000) + 3000); 175 | if (argv.port) { 176 | serverPort = parseInt(argv.port); 177 | } 178 | 179 | server.listen(serverPort, function() { 180 | console.log("Server: http://localhost:%s", serverPort); 181 | callback(); 182 | }); 183 | }); 184 | 185 | gulp.task('default', ['vendor', 'scripts', 'styles', 'metalsmith']); 186 | -------------------------------------------------------------------------------- /layouts/blog-post.html: -------------------------------------------------------------------------------- 1 | {{#extend "default"}} 2 | {{#content "main"}} 3 | 4 | {{{contents}}} 5 | 6 | {{/content}} 7 | {{/extend}} 8 | -------------------------------------------------------------------------------- /layouts/blog.html: -------------------------------------------------------------------------------- 1 | {{#extend "default"}} 2 | {{#content "main"}} 3 | 4 |