├── index.js ├── example ├── plugins │ └── develop-plugin │ │ ├── gatsby-node.js │ │ └── package.json ├── src │ ├── components │ │ ├── Footer.js │ │ └── Header.js │ ├── pages │ │ ├── about.js │ │ └── index.js │ ├── styles │ │ └── index.scss │ ├── layouts │ │ └── index.js │ └── html.js ├── .gitignore ├── gatsby-config.js └── package.json ├── .babelrc ├── src ├── fsAsync.js ├── getPathsWithExt.js ├── selectAndReplaceInFileFactory.js ├── prepareStyles.js └── index.js ├── webpack.config.babel.js ├── .npmignore ├── .gitignore ├── README.md ├── package.json └── yarn.lock /index.js: -------------------------------------------------------------------------------- 1 | // no-op 2 | -------------------------------------------------------------------------------- /example/plugins/develop-plugin/gatsby-node.js: -------------------------------------------------------------------------------- 1 | const { onPostBuild } = require('../../../gatsby-node') 2 | 3 | exports.onPostBuild = onPostBuild 4 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["env"], 3 | "plugins": [ 4 | "transform-object-rest-spread", 5 | "transform-async-to-generator" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /example/src/components/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Footer = () => ( 4 | 7 | ) 8 | 9 | export default Footer 10 | -------------------------------------------------------------------------------- /example/src/components/Header.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Header = ({pathname}) => ( 4 |
5 | My Header 6 |
7 | ) 8 | 9 | export default Header 10 | -------------------------------------------------------------------------------- /example/src/pages/about.js: -------------------------------------------------------------------------------- 1 | import React from 'React' 2 | 3 | const AboutPage = () => ( 4 |
5 |

about stuff

6 |
7 | ) 8 | 9 | export default AboutPage 10 | -------------------------------------------------------------------------------- /example/src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from 'React' 2 | 3 | const IndexPage = () => ( 4 |
5 |

hello world

6 |
7 | ) 8 | 9 | export default IndexPage 10 | -------------------------------------------------------------------------------- /src/fsAsync.js: -------------------------------------------------------------------------------- 1 | import { promisify } from 'bluebird' 2 | import { readFile as _readFile, writeFile as _writeFile } from 'fs' 3 | 4 | export const readFile = promisify(_readFile) 5 | export const writeFile = promisify(_writeFile) 6 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Project dependencies 2 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 3 | node_modules 4 | .cache/ 5 | # Build directory 6 | public/ 7 | .DS_Store 8 | yarn-error.log 9 | yarn.lock 10 | -------------------------------------------------------------------------------- /example/plugins/develop-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "develop-plugin", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC" 11 | } 12 | -------------------------------------------------------------------------------- /example/gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | // 'develop-plugin', 4 | 'gatsby-plugin-purify-css', 5 | { 6 | resolve: 'gatsby-plugin-postcss-sass', 7 | options: { 8 | postCssPlugins: [ 9 | require('postcss-import')(), 10 | require('autoprefixer')() 11 | ] 12 | } 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /example/src/styles/index.scss: -------------------------------------------------------------------------------- 1 | /* importing a library */ 2 | @import '~tachyons'; 3 | 4 | /* importing a local file */ 5 | @import 'react-perfect-scrollbar/dist/css/styles.css'; 6 | 7 | /* This class is used and will be included in production */ 8 | .used { 9 | color: #ff0000; 10 | } 11 | 12 | /* This class is unused and will not be included in production */ 13 | .unused { 14 | color: #0000ff; 15 | } 16 | -------------------------------------------------------------------------------- /src/getPathsWithExt.js: -------------------------------------------------------------------------------- 1 | import klaw from 'klaw' 2 | import { extname } from 'path' 3 | import filter from 'through2-filter' 4 | 5 | const filterByExt = ext => filter.obj(item => ( 6 | extname(item.path) === `.${ext}` 7 | )) 8 | 9 | export default (ext, dir = __dirname) => ( 10 | new Promise((resolve, reject) => { 11 | const results = [] 12 | klaw(dir) 13 | .pipe(filterByExt(ext)) 14 | .on('data', item => results.push(item.path)) 15 | .on('end', () => resolve(results)) 16 | }) 17 | ) 18 | -------------------------------------------------------------------------------- /src/selectAndReplaceInFileFactory.js: -------------------------------------------------------------------------------- 1 | import cheerio from 'cheerio' 2 | import { readFile, writeFile } from './fsAsync' 3 | 4 | export default (selector, textString) => async filePath => { 5 | const src = await readFile(filePath, { encoding: 'utf-8' }) 6 | 7 | // parse html file 8 | const $ = cheerio.load(src) 9 | 10 | // replace text inline 11 | $(selector).text(textString) 12 | const srcOverwrite = $.html() 13 | 14 | // overwrite html file 15 | await writeFile(filePath, srcOverwrite) 16 | return true 17 | } 18 | -------------------------------------------------------------------------------- /webpack.config.babel.js: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path' 2 | import makeRule from 'webpack-make-rule' 3 | import nodeExternals from 'webpack-node-externals' 4 | 5 | export default { 6 | target: 'node', 7 | externals: [nodeExternals()], 8 | entry: resolve(__dirname, './src/index.js'), 9 | output: { 10 | path: resolve(__dirname), 11 | filename: 'gatsby-node.js', 12 | library: 'onPostBuild', 13 | libraryTarget: 'commonjs', 14 | libraryExport: 'onPostBuild' 15 | }, 16 | module: { 17 | rules: [ makeRule(/\.jsx?$/, 'babel-loader') ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/prepareStyles.js: -------------------------------------------------------------------------------- 1 | import postcss from 'postcss' 2 | import dedupe from 'postcss-discard-duplicates' 3 | 4 | import { readFile } from './fsAsync' 5 | 6 | const concatFiles = async filePaths => { 7 | const fileTexts = [] 8 | for (let filePath of filePaths) { 9 | const text = await readFile(filePath, {encoding: 'utf-8'}) 10 | fileTexts.push(text) 11 | } 12 | return fileTexts.join('') 13 | } 14 | 15 | export default async cssFiles => { 16 | const css = await concatFiles(cssFiles) 17 | const result = await postcss([dedupe]).process(css) 18 | return result.css 19 | } 20 | -------------------------------------------------------------------------------- /example/src/layouts/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Scrollbar from 'react-perfect-scrollbar' 3 | 4 | import '../styles/index.scss' 5 | import Header from '../components/Header' 6 | import Footer from '../components/Footer' 7 | 8 | const Layout = ({ location: { pathname }, children }) => ( 9 | 10 |
11 |
12 |
13 | { children() } 14 |
15 |
17 |
18 | ) 19 | 20 | export default Layout 21 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "plugin-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "n/a", 6 | "scripts": { 7 | "build": "gatsby build", 8 | "develop": "gatsby develop", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "autoprefixer": "^7.1.4", 15 | "gatsby": "^1.9.38", 16 | "gatsby-link": "^1.6.16", 17 | "gatsby-plugin-postcss-sass": "^1.0.12", 18 | "gatsby-plugin-purify-css": "^2.1.0", 19 | "postcss-import": "^11.0.0", 20 | "react-perfect-scrollbar": "^0.2.2", 21 | "tachyons": "^4.8.1" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | *.un~ 29 | yarn.lock 30 | src 31 | example 32 | flow-typed 33 | coverage 34 | decls 35 | examples 36 | -------------------------------------------------------------------------------- /example/src/html.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | let styles 4 | if (process.env.NODE_ENV === 'production') { 5 | try { 6 | styles = require(`!raw-loader!../public/styles.css`) 7 | } catch (e) { 8 | console.log(e) 9 | } 10 | } 11 | 12 | const Html = ({ headComponents, body, postBodyComponents }) => ( 13 | 14 | 15 | { headComponents } 16 | { process.env.NODE_ENV === 'production' 17 | ?