├── .eslintignore ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .nvmrc ├── .prettierignore ├── .remarkrc.js ├── .travis.yml ├── CHANGELOG.md ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── batfish-dark.png ├── batfish-ultra.png ├── bin ├── .eslintrc.js ├── batfish.js ├── example-batfish └── write-cli-doc.js ├── conf ├── eslint-base.json ├── eslint-browser.json └── eslint-node.json ├── docs ├── advanced-usage.md ├── batfish-modules.md ├── cli.md ├── configuration.md ├── node-api.md └── q-and-a.md ├── examples ├── .eslintrc ├── README.md ├── babelrc-for-tests │ ├── README.md │ ├── batfish.config.js │ ├── package.json │ └── src │ │ ├── __tests__ │ │ └── index.test.js │ │ └── pages │ │ └── index.js ├── basic │ ├── README.md │ ├── batfish.config.js │ ├── package.json │ └── src │ │ ├── components │ │ ├── markdown-wrapper.js │ │ └── page-shell.js │ │ ├── pages │ │ ├── index.js │ │ └── markdown.md │ │ └── style.css ├── fragment-urls │ ├── README.md │ ├── package.json │ └── src │ │ ├── page-shell.js │ │ └── pages │ │ ├── index.js │ │ └── two.js ├── inline-js │ ├── README.md │ ├── batfish.config.js │ ├── package.json │ └── src │ │ ├── js │ │ └── inline-me.js │ │ └── pages │ │ └── index.js ├── internal-routing │ ├── README.md │ ├── batfish.config.js │ ├── package.json │ └── src │ │ ├── pages │ │ ├── index.md │ │ ├── letters.js │ │ └── numbers.js │ │ └── wrapper.js ├── legacy │ ├── README.md │ ├── batfish.config.js │ ├── package.json │ └── src │ │ ├── components │ │ └── application-wrapper.js │ │ └── pages │ │ └── index.js ├── markdown-wrappers │ ├── README.md │ ├── batfish.config.js │ ├── package.json │ └── src │ │ ├── components │ │ ├── markdown-wrapper-a.js │ │ ├── markdown-wrapper-b.js │ │ └── page-wrapper.js │ │ └── pages │ │ ├── index.js │ │ ├── markdown-a.md │ │ ├── markdown-b.md │ │ ├── markdown-c.md │ │ └── markdown-fake-a.md ├── miscellany │ ├── README.md │ ├── batfish.config.js │ ├── lib │ │ └── selectors.js │ ├── package.json │ └── src │ │ ├── components │ │ ├── application-wrapper.js │ │ ├── holiday-image.js │ │ ├── holiday-wrapper.js │ │ ├── page-shell.js │ │ ├── sidebar-navigation.js │ │ └── story-wrapper.js │ │ ├── pages │ │ ├── 404.js │ │ ├── holidays │ │ │ ├── independence-day.js │ │ │ ├── index.js │ │ │ ├── labor-day.js │ │ │ └── memorial-day.js │ │ ├── index.js │ │ └── stories │ │ │ ├── five-white-mice.md │ │ │ ├── great-mistake.md │ │ │ ├── index.js │ │ │ ├── ominous-baby.md │ │ │ ├── open-boat.md │ │ │ └── wise-men.md │ │ └── utilities │ │ └── get-legible-date.js ├── no-config │ ├── README.md │ ├── package.json │ └── src │ │ └── pages │ │ └── index.md ├── optimizing-loaders │ ├── README.md │ ├── batfish.config.js │ ├── package.json │ └── src │ │ ├── img │ │ └── man-in-a-bottle.jpg │ │ └── pages │ │ └── index.js ├── page-specific-css │ ├── README.md │ ├── package.json │ └── src │ │ └── pages │ │ ├── another.css │ │ ├── another.md │ │ ├── index.css │ │ └── index.js ├── sitemap │ ├── README.md │ ├── batfish.config.js │ ├── ignore.js │ ├── package.json │ └── src │ │ └── pages │ │ ├── example │ │ └── simple-map.html │ │ └── index.js ├── spa-minimum-static-build │ ├── README.md │ ├── batfish.config.js │ ├── package.json │ └── src │ │ ├── app.js │ │ ├── pages │ │ └── index.js │ │ └── style.css ├── spa │ ├── README.md │ ├── batfish.config.js │ ├── package.json │ └── src │ │ └── pages │ │ └── index.js ├── static-files │ ├── README.md │ ├── batfish.config.js │ ├── package.json │ └── src │ │ └── pages │ │ ├── hippolyte.jpg │ │ ├── ignore-me.xyz │ │ ├── index.md │ │ ├── nonsense.json │ │ ├── star │ │ ├── ignore-me.txt │ │ ├── index.md │ │ └── star.jpg │ │ └── static │ │ ├── copy-me.xyz │ │ ├── hippos.jpg │ │ ├── ignore-me.txt │ │ ├── motorcycles │ │ └── wild-star.jpg │ │ ├── not-page.js │ │ └── not-page.md └── table-of-contents │ ├── README.md │ ├── batfish.config.js │ ├── package.json │ └── src │ ├── components │ └── markdown-wrapper.js │ └── pages │ └── index.md ├── flow-typed ├── chalk.js ├── defs.js ├── errors.js ├── lodash.js ├── modules.js ├── prop-types.js └── webpack.js ├── package-lock.json ├── package.json ├── src ├── node │ ├── .eslintrc.js │ ├── append-task-time.js │ ├── batfish-log.js │ ├── build-html.js │ ├── build.js │ ├── clean-up-temp-files.js │ ├── compile-stylesheets.js │ ├── constants.js │ ├── create-babel-config.js │ ├── create-webpack-config-base.js │ ├── create-webpack-config-client.js │ ├── create-webpack-config-static.js │ ├── create-webpack-stats-error.js │ ├── dev-server.js │ ├── error-types.js │ ├── generate-sitemap.js │ ├── get-env-browserslist.js │ ├── get-loggable-error-message.js │ ├── get-pages-data.js │ ├── get-port.js │ ├── get-postcss-plugins.js │ ├── get-webpack-asset-absolute-path.js │ ├── index.js │ ├── inline-css-worker.js │ ├── inline-css.js │ ├── join-url-parts.js │ ├── maybe-clear-output-directory.js │ ├── non-page-files.js │ ├── now.js │ ├── postcss-absolute-urls.js │ ├── react-helmet-postcss-loader.js │ ├── render-inline-js-scripts.js │ ├── render-pretty-error-stack.js │ ├── rethrow-postcss-error.js │ ├── serve-static.js │ ├── server-init-message.js │ ├── server-middleware │ │ ├── start-middleware.js │ │ ├── static-server-middleware.js │ │ └── strip-site-base-path.js │ ├── sitemap-static.js │ ├── start.js │ ├── static-stubs │ │ └── react-component.js │ ├── validate-config.js │ ├── watch-context.js │ ├── watch-css.js │ ├── watch-webpack.js │ ├── webpack-compile-promise.js │ ├── wrap-error.js │ ├── write-babelrc.js │ ├── write-context-module.js │ ├── write-data-modules.js │ ├── write-page-module.js │ └── write-webpack-stats.js └── webpack │ ├── .eslintrc.js │ ├── batfish-app.js │ ├── batfish-spa-app.js │ ├── change-page.js │ ├── default-not-found.js │ ├── empty-application-wrapper.js │ ├── find-matching-route.js │ ├── get-current-location.js │ ├── get-window.js │ ├── html-webpack-template.ejs │ ├── public │ ├── prefix-url.js │ ├── route-change-listeners.js │ ├── route-to.js │ └── with-location.js │ ├── render-app-into-dom.js │ ├── render-batfish-app.js │ ├── render-batfish-spa-app.js │ ├── render-html-page.js │ ├── router.js │ ├── scroll-to-fragment.js │ ├── static-html-page.js │ └── static-render-pages.js └── test ├── .eslintrc ├── __snapshots__ ├── build.test.js.snap ├── compile-stylesheets.test.js.snap ├── create-babel-config.test.js.snap ├── create-webpack-config-base.test.js.snap ├── create-webpack-config-client.test.js.snap ├── create-webpack-config-static.test.js.snap ├── postcss-absolute-urls.test.js.snap ├── render-html-page.test.js.snap ├── router.test.js.snap ├── validate-config.test.js.snap ├── write-babelrc.test.js.snap └── write-context-module.test.js.snap ├── build-html.test.js ├── build.test.js ├── change-page.test.js ├── compile-stylesheets.test.js ├── create-babel-config.test.js ├── create-webpack-config-base.test.js ├── create-webpack-config-client.test.js ├── create-webpack-config-static.test.js ├── examples.test.js ├── find-matching-route.test.js ├── fixtures ├── empty-component.js ├── get-pages-data-404-js │ ├── 404.js │ └── index.md ├── get-pages-data-404-md │ ├── 404.md │ └── index.md ├── get-pages-data-spa │ └── index.js ├── get-pages-data-unprocessed │ ├── is-not.js │ ├── is.js │ └── maybe │ │ ├── definitely-not.md │ │ └── yes.js ├── get-pages-data │ ├── about │ │ ├── index.js │ │ ├── security.md │ │ ├── style.css │ │ └── team │ │ │ └── index.md │ ├── index.js │ └── work │ │ └── animals │ │ └── horses │ │ └── ed.js ├── stylesheets │ ├── a.css │ ├── b.css │ ├── fonts │ │ ├── a.woff2 │ │ ├── c.woff2 │ │ └── e.woff2 │ ├── inner │ │ ├── c.css │ │ ├── d.css │ │ └── innermost │ │ │ └── e.css │ └── mapbox-gl.css └── write-page-module │ └── page-component-module.js ├── get-current-location.test.js ├── get-pages-data.test.js ├── get-webpack-asset-absolute-path.test.js ├── join-url-parts.test.js ├── maybe-clear-output-directory.test.js ├── non-page-files.test.js ├── postcss-absolute-urls.test.js ├── prefix-url.test.js ├── render-html-page.test.js ├── route-change-listeners.test.js ├── route-to.test.js ├── router-prefix-url.test.js ├── router.test.js ├── start.test.js ├── stress ├── .gitignore ├── README.md ├── index.js └── scripts │ └── generate-pages.js ├── test-util ├── jest-setup.js ├── node-modules-path-serializer.js ├── project-root-serializer.js └── raf.js ├── validate-config.test.js ├── watch-context.test.js ├── watch-css.test.js ├── watch-webpack.test.js ├── webpack-compile-promise.test.js ├── write-babelrc.test.js ├── write-context-module.test.js ├── write-data-modules.test.js └── write-page-module.test.js /.eslintignore: -------------------------------------------------------------------------------- 1 | babel-cache 2 | **/_batfish_site 3 | **/_batfish_tmp 4 | **/node_modules 5 | coverage 6 | modules 7 | dist 8 | flow-typed 9 | flow-coverage 10 | src/node/static-stubs 11 | vendor/* -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | .*/node_modules/fbjs/.* 3 | .*/node_modules/babel-plugin-transform-react-remove-prop-types/.* 4 | .*/node_modules/flow-coverage-report/.* 5 | .*/node_modules/immutable/.* 6 | .*/node_modules/bcryptjs/.* 7 | /examples/.*/node_modules/.* 8 | .*/node_modules/resolve/.* 9 | /dist/.* 10 | 11 | [include] 12 | 13 | [libs] 14 | 15 | [lints] 16 | 17 | [options] 18 | module.ignore_non_literal_requires=true 19 | module.name_mapper='^@mapbox/batfish/modules/route-to$' -> '/src/webpack/public/route-to.js' 20 | module.name_mapper='^@mapbox/batfish/modules/prefix-url$' -> '/src/webpack/public/prefix-url.js' 21 | module.name_mapper='^@mapbox/batfish/modules/route-change-listeners$' -> '/src/webpack/public/route-change-listeners.js' 22 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | CHANGELOG.md merge=union 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | .DS_Store 4 | babel-cache 5 | _batfish_site 6 | _batfish_tmp 7 | **/package-lock.json 8 | coverage 9 | modules 10 | dist 11 | flow-coverage 12 | examples/**/.babelrc 13 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 18 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .eslintignore -------------------------------------------------------------------------------- /.remarkrc.js: -------------------------------------------------------------------------------- 1 | // replaces remark-preset-davidtheclark 2 | 3 | const remarkFrontmatter =require('remark-frontmatter') 4 | const remarkValidateLinks =require('remark-validate-links') 5 | const remarkToc =require('remark-toc') 6 | const remarkLintBlockquoteIndentation =require('remark-lint-blockquote-indentation') 7 | const remarkLintFileExtension =require('remark-lint-file-extension') 8 | const remarkLintFinalDefinition =require('remark-lint-final-definition') 9 | const remarkLintNoDuplicateDefinitions =require('remark-lint-no-duplicate-definitions') 10 | const remarkLintNoMultipleToplevelHeadings =require('remark-lint-no-multiple-toplevel-headings') 11 | const remarkLintNoTabs =require('remark-lint-no-tabs') 12 | const remarkLintNoUndefinedReferences =require('remark-lint-no-undefined-references') 13 | 14 | exports.settings = { 15 | listItemIndent: 1, 16 | emphasis: '*', 17 | strong: '*', 18 | bullet: '-', 19 | fences: true 20 | }; 21 | 22 | exports.plugins = [ 23 | remarkFrontmatter, 24 | remarkValidateLinks, 25 | [remarkToc, { maxDepth: 3, tight: true }], 26 | [remarkLintBlockquoteIndentation, 2], 27 | [remarkLintFileExtension, 'md'], 28 | remarkLintFinalDefinition, 29 | remarkLintNoDuplicateDefinitions, 30 | remarkLintNoMultipleToplevelHeadings, 31 | remarkLintNoTabs, 32 | remarkLintNoUndefinedReferences, 33 | ]; 34 | 35 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: jammy 2 | language: node_js 3 | node_js: 4 | - 18 5 | cache: false 6 | install: 7 | - npm ci 8 | before_script: 9 | - npm run build 10 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @mapbox/docs 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. 6 | 7 | Examples of unacceptable behavior by participants include: 8 | 9 | - The use of sexualized language or imagery 10 | - Personal attacks 11 | - Trolling or insulting/derogatory comments 12 | - Public or private harassment 13 | - Publishing other's private information, such as physical or electronic addresses, without explicit permission 14 | - Other unethical or unprofessional conduct 15 | 16 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. 17 | 18 | This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 21 | 22 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017 Mapbox 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 4 | 5 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 6 | -------------------------------------------------------------------------------- /batfish-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/batfish/4230d75d5541954374d070ab94f6850a61a925e8/batfish-dark.png -------------------------------------------------------------------------------- /batfish-ultra.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/batfish/4230d75d5541954374d070ab94f6850a61a925e8/batfish-ultra.png -------------------------------------------------------------------------------- /bin/.eslintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: '../conf/eslint-node.json' 5 | }; 6 | -------------------------------------------------------------------------------- /bin/example-batfish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Examples run this script instead of batfish.js to ensure that the dist/ 4 | # directory is available before they run. 5 | 6 | cd "${0%/*}" 7 | npm run build 8 | cd - > /dev/null 9 | "${0%/*}"/batfish.js "$@" 10 | -------------------------------------------------------------------------------- /bin/write-cli-doc.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | const stripAnsi = require('strip-ansi'); 7 | const execSync = require('child_process').execSync; 8 | 9 | // Read the output of batfish --help and write it to a doc. 10 | 11 | const output = execSync( 12 | `${path.join(__dirname, 'batfish.js')} --help` 13 | ).toString(); 14 | 15 | const tidyOutput = stripAnsi( 16 | output.replace(/\n[ ]{2}/g, '\n').replace(/(^\r?\n+|\r?\n+$)/g, '') 17 | ); 18 | 19 | const docs = `# The Batfish CLI 20 | 21 | The following is output by \`batfish --help\`: 22 | 23 | \`\`\` 24 | ${tidyOutput} 25 | \`\`\` 26 | `; 27 | 28 | fs.writeFileSync(path.join(__dirname, '../docs/cli.md'), docs); 29 | -------------------------------------------------------------------------------- /conf/eslint-base.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "parser": "babel-eslint", 4 | "env": { 5 | "browser": true, 6 | "node": true, 7 | "es6": true 8 | }, 9 | "parserOptions": { 10 | "ecmaFeatures": { 11 | "jsx": true 12 | } 13 | }, 14 | "plugins": [ 15 | "filenames", 16 | "flowtype" 17 | ], 18 | "rules": { 19 | "strict": ["error", "global"], 20 | "filenames/match-regex": ["error", "^[0-9a-z-\\.]+?$"], 21 | "flowtype/define-flow-type": ["error"] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /conf/eslint-browser.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./eslint-base.json", 3 | "plugins": [ 4 | "react" 5 | ], 6 | "parserOptions": { 7 | "sourceType": "module" 8 | }, 9 | "rules": { 10 | "react/jsx-uses-vars": ["error"], 11 | "react/jsx-no-duplicate-props": ["error"], 12 | "react/jsx-uses-react": ["error"], 13 | "react/jsx-no-undef": ["error"], 14 | "react/no-unknown-property": ["error"], 15 | "react/react-in-jsx-scope": ["error"] 16 | }, 17 | "settings": { 18 | "react": { 19 | "version": "detect" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /conf/eslint-node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./eslint-base.json", 3 | "env": { 4 | "browser": false, 5 | "node": true, 6 | "es6": true 7 | }, 8 | "parserOptions": { 9 | "sourceType": "script" 10 | }, 11 | "plugins": [ 12 | "node" 13 | ], 14 | "rules": { 15 | "node/no-unsupported-features": ["error", {"version": 6}], 16 | "node/no-missing-require": ["error"] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /docs/cli.md: -------------------------------------------------------------------------------- 1 | # The Batfish CLI 2 | 3 | The following is output by `batfish --help`: 4 | 5 | ``` 6 | Build websites with batfish. 7 | 8 | Usage 9 | batfish [options] 10 | 11 | You must provide a batfish configuration module, either with 12 | batish.config.js in process.cwd() or with the --config option. 13 | 14 | Commands 15 | start Start a development server. 16 | build Build the static site. 17 | serve-static Serve the static site. 18 | write-babelrc Write a .babelrc file that other processes, 19 | like your test runner, can use. 20 | 21 | Shared options 22 | -c, --config Path to your configuration module. 23 | Default: batfish.config.js 24 | -V, --verbose Log extra stats. 25 | 26 | start options 27 | -p, --port Server port. Default: 8080. 28 | -i, --include Build only the specified page(s). Value 29 | is a glob relative to the root of your site. 30 | --production Build as though for production. 31 | --no-clear Do not clear the destination directory. 32 | -b, --browsers A comma-separated browserslist string 33 | specifying the browsers you want to support 34 | during this dev build. Or "false" if you 35 | want to support all your production browsers. 36 | 37 | build options 38 | -d, --debug Build for debugging, not for production. 39 | --no-clear Do not clear the destination directory. 40 | -s, --stats Generate Webpack statistics. 41 | 42 | serve-static options 43 | -p, --port Server port. Default: 8080. 44 | 45 | write-babelrc options 46 | --target "node" or "browser". Default: "node". 47 | --dir Directory where .babelrc should be written. 48 | Default: same directory as Batfish config. 49 | 50 | Examples 51 | No options are required for any command. 52 | batfish start 53 | batfish build 54 | batfish serve-static 55 | batfish write-babelrc 56 | Build with your Batfish config in a special place. 57 | batfish build -c conf/bf.js 58 | Start with an alternate port. 59 | batfish start -p 9966 60 | Start but only build the /about pages. 61 | batfish start -i about/** 62 | Start but only build the /about/history page. 63 | batfish start --include about/history 64 | Start and build only for Chrome 60+. 65 | batfish start --browsers "Chrome >= 60" 66 | ``` 67 | -------------------------------------------------------------------------------- /docs/node-api.md: -------------------------------------------------------------------------------- 1 | # Node API 2 | 3 | All of the functions accept two optional arguments: 4 | 5 | - `batfishConfig`: See [`docs/configuration.md`](./configuration.md). 6 | - `projectDirectory`: Absolute path to the root directory of your projects. 7 | This is used to establish some default values for the configuration. 8 | For example, the default [`pagesDirectory`] value is `{projectDirectory}/src/pages`. 9 | Defaults to `process.cwd()`. 10 | 11 | ## start 12 | 13 | ``` 14 | start(batfishConfig?: Object, projectDirectory?: string): EventEmitter 15 | ``` 16 | 17 | Start a development server. 18 | 19 | Returns an EventEmitter that emits the following events. 20 | 21 | - `notification`: The listener is passed a string message. 22 | These are the messages logged by the CLI. 23 | - `error`: The listener is passed the error. 24 | 25 | ## build 26 | 27 | ``` 28 | build(batfishConfig?: Object, projectDirectory?: string): EventEmitter 29 | ``` 30 | 31 | Build the static site. 32 | 33 | Returns an EventEmitter that emits the following events. 34 | 35 | - `done`: Emitted when the build is complete. 36 | - `notification`: The listener is passed a string message. 37 | These are the messages logged by the CLI. 38 | - `error`: The listener is passed the error. 39 | 40 | ## serveStatic 41 | 42 | ``` 43 | serveStatic(batfishConfig?: Object, projectDirectory?: string): EventEmitter 44 | ``` 45 | 46 | Serve the static site. 47 | 48 | Returns an EventEmitter that emits the following events. 49 | 50 | - `notification`: The listener is passed a string message. 51 | These are the messages logged by the CLI. 52 | - `error`: The listener is passed the error. 53 | 54 | ## writeBabelrc 55 | 56 | ``` 57 | writeBabelrc(batfishConfig?: Object, options?: { 58 | outputDirectory: string, 59 | target?: 'browser' | 'node' 60 | }): string 61 | ``` 62 | 63 | Write a `.babelrc` file based on Batfish's Babel defaults and your Batfish config file. 64 | This `.babelrc` file can be used for other processes that run Babel and want to understand the source files that you write for Batfish (which end up going fed through Webpack). 65 | For example, you may want to generate a `.babelrc` file before running Jest tests against your client-side JS, so Jest can understand the same files that Batfish & Webpack do. 66 | 67 | `options.outputDirectory` defaults to the directory of your Batfish configuration. 68 | 69 | `options.target` defaults to `'node'`. 70 | 71 | [`pagesdirectory`]: ./configuration.md#pagesdirectory 72 | -------------------------------------------------------------------------------- /examples/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | extends: "../conf/eslint-browser.json", 3 | "rules": { 4 | "no-console": "off" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | Each subdirectory in `examples/` is an example site, illustrating some subset of Batfish's features. 4 | 5 | ### Running examples 6 | 7 | - `cd` into the example's directory. 8 | - npm install`(or`yarn install\`) to get any dependencies of that example. 9 | - `npm run batfish -- start` (or `build` or `serve-static`). 10 | 11 | `npm run batfish` is just a shortcut script that examples should include. 12 | You can also use the Batfish CLI directly to run the examples: it lives in `bin/batfish.js`. 13 | You'll need to make sure you either run the command from the example's directory or else use the `--config` argument, so Batfish can find the example's configuration. 14 | 15 | Examples: 16 | 17 | ``` 18 | # From project root directory 19 | bin/batfish.js --config examples/initial-experiments/batfish.config.js start 20 | 21 | # From examples/initial-experiments/ 22 | ../../bin/batfish.js build && ../../bin/batfish.js serve-static 23 | ``` 24 | 25 | ## Creating a new example 26 | 27 | Create a new directory in `examples/`. 28 | Add the following `package.json`: 29 | 30 | ```json 31 | { 32 | "private": true, 33 | "scripts": { 34 | "batfish": "../../bin/example-batfish" 35 | }, 36 | "dependencies": {} 37 | } 38 | ``` 39 | 40 | Install dependencies as needed. 41 | 42 | Create a configuration file and some pages ... and go from there! 43 | -------------------------------------------------------------------------------- /examples/babelrc-for-tests/README.md: -------------------------------------------------------------------------------- 1 | # Generating a `.babelrc` for a test runner 2 | 3 | This example includes an additional Babel plugin (via the [`babelPlugins`] option) that provides syntax sugar that will cause a runtime error if the source file is not compiled correctly by Babel. 4 | It also include a Jes tests that reads the source file — so if Jest is not running Babel with the correct config, the test will fail. 5 | 6 | To make the Jest test work, this example uses `batfish write-babelrc` to generate a `.babelrc` file before running Jest (in its `npm test` script). 7 | 8 | For more information, read ["How can I expose the Babel configuration that Batfish generates?"](../../docs/q-and-a.md#how-can-i-expose-the-babel-configuration-that-batfish-generates). 9 | 10 | [`babelplugins`]: ../../docs/configuration.md#babelplugins 11 | -------------------------------------------------------------------------------- /examples/babelrc-for-tests/batfish.config.js: -------------------------------------------------------------------------------- 1 | module.exports = () => { 2 | return { 3 | babelPlugins: [ 4 | require.resolve('babel-plugin-transform-function-composition') 5 | ], 6 | babelExclude: /\/node_modules\// 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /examples/babelrc-for-tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "batfish": "NODE_OPTIONS=--openssl-legacy-provider ../../bin/example-batfish", 5 | "test": "npm run batfish -- write-babelrc && jest" 6 | }, 7 | "dependencies": {}, 8 | "devDependencies": { 9 | "babel-plugin-transform-function-composition": "^1.0.0", 10 | "jest": "^22.4.2" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/babelrc-for-tests/src/__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import React from 'react'; 3 | import ReactDOMServer from 'react-dom/server'; 4 | import IndexPage from '../pages/index'; 5 | 6 | describe('IndexPage', () => { 7 | test('is correctly transformed', () => { 8 | const rendered = ReactDOMServer.renderToStaticMarkup(); 9 | expect(rendered).toMatch(/0 === 0/); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/babelrc-for-tests/src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | // This page uses relies on the :: syntax sugar provided by 4 | // https://github.com/gajus/babel-plugin-transform-function-composition 5 | 6 | const add = (x, y) => x + y; 7 | const subtractFrom = (x, y) => x - y; 8 | 9 | export default class Home extends React.PureComponent { 10 | render() { 11 | return ( 12 |
13 |

Fancy syntax sugar!

14 |

15 | This should be true: 0 === {4::add(3)::subtractFrom(7)} 16 |

17 |
18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/basic/README.md: -------------------------------------------------------------------------------- 1 | # Some Basic Batfish 2 | 3 | A typical basic Batfish setup. 4 | 5 | - Includes two stylesheets via the [`stylesheets`] configuration option, one at an external URL and one local, within the project directory. 6 | - Defines a `PageShell` component, which translates each page's front matter into `` and `<meta>` tags, using [react-helmet]. 7 | - Specifies a `MarkdownWrapper` component that sends Markdown pages' front matter to the `PageShell` and wraps Markdown content in a class that applies typographic styles. This is configured with [`jsxtremeMarkdownOptions`]. 8 | - Exemplifies a JavaScript page and a Markdown page. 9 | - Shows both pages using their front matter via `props.frontMatter`. 10 | 11 | [`sitebasepath`]: ../../docs/configuration.md#sitebasepath 12 | 13 | [`stylesheets`]: ../../docs/configuration.md#stylesheets 14 | 15 | [`applicationwrapperpath`]: ../../docs/configuration.md#applicationwrapperpath 16 | 17 | [`jsxtrememarkdownoptions`]: ../../docs/configuration.md#jsxtrememarkdownoptions 18 | 19 | [react-helmet]: https://github.com/nfl/react-helmet 20 | 21 | [`prefixurl`]: ../../README.md#prefixing-urls 22 | -------------------------------------------------------------------------------- /examples/basic/batfish.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = () => { 4 | return { 5 | siteOrigin: 'https://www.batfish-basic.com', 6 | stylesheets: [ 7 | 'https://api.mapbox.com/mapbox-assembly/v0.17.0/assembly.css', 8 | path.join(__dirname, './src/style.css') 9 | ], 10 | jsxtremeMarkdownOptions: { 11 | wrapper: path.join(__dirname, './src/components/markdown-wrapper.js') 12 | } 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /examples/basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "batfish": "NODE_OPTIONS=--openssl-legacy-provider ../../bin/example-batfish" 5 | }, 6 | "dependencies": {} 7 | } 8 | -------------------------------------------------------------------------------- /examples/basic/src/components/markdown-wrapper.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PageShell from './page-shell'; 3 | 4 | export default class MarkdownWrapper extends React.Component { 5 | render() { 6 | return ( 7 | <PageShell frontMatter={this.props.frontMatter}> 8 | <div className="prose">{this.props.children}</div> 9 | </PageShell> 10 | ); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/basic/src/components/page-shell.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Helmet } from 'react-helmet'; 4 | 5 | export default class PageShell extends React.Component { 6 | render() { 7 | const { props } = this; 8 | const title = `${props.frontMatter.title} | Basic`; 9 | return ( 10 | <div> 11 | <Helmet> 12 | <html lang="en" /> 13 | <meta charSet="utf-8" /> 14 | <meta name="viewport" content="width=device-width, initial-scale=1" /> 15 | <title>{title} 16 | 17 | 18 |
{props.children}
19 | 20 | ); 21 | } 22 | } 23 | 24 | PageShell.propTypes = { 25 | frontMatter: PropTypes.shape({ 26 | title: PropTypes.string.isRequired, 27 | description: PropTypes.string.isRequired 28 | }).isRequired, 29 | children: PropTypes.node.isRequired 30 | }; 31 | -------------------------------------------------------------------------------- /examples/basic/src/pages/index.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | title: JavaScript page 3 | description: A basic Batfish example. 4 | ---*/ 5 | 6 | import React from 'react'; 7 | import PageShell from '../components/page-shell'; 8 | 9 | export default class Home extends React.PureComponent { 10 | render() { 11 | const { props } = this; 12 | return ( 13 | 14 |

{props.frontMatter.title}

15 |

This is a basic Batfish JavaScript page.

16 |

17 | 18 | Go to the Markdown page. 19 | 20 |

21 |
22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/basic/src/pages/markdown.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown page 3 | description: Another basic Batfish example. 4 | --- 5 | 6 | # {{ props.frontMatter.title }} 7 | 8 | This is a basic Batfish **Markdown** page. 9 | 10 | [Go to the JavaScript page.](/) 11 | -------------------------------------------------------------------------------- /examples/basic/src/style.css: -------------------------------------------------------------------------------- 1 | .customHeading { 2 | font-weight: bold; 3 | padding-bottom: 12px; 4 | font-size: 2em; 5 | border-bottom: 1px solid #ccc; 6 | } 7 | -------------------------------------------------------------------------------- /examples/fragment-urls/README.md: -------------------------------------------------------------------------------- 1 | # Fragment URLs 2 | 3 | - Demonstrates how fragment URLs work on initial page and dynamic linking, for both the development server and the static build. 4 | -------------------------------------------------------------------------------- /examples/fragment-urls/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "batfish": "NODE_OPTIONS=--openssl-legacy-provider ../../bin/example-batfish" 5 | }, 6 | "dependencies": {} 7 | } 8 | -------------------------------------------------------------------------------- /examples/fragment-urls/src/page-shell.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class PageShell extends React.Component { 4 | render() { 5 | return ( 6 |
7 |
    8 |
  • 9 | one 10 |
  • 11 |
  • 12 | two 13 |
  • 14 |
15 | {this.props.children} 16 |
17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/inline-js/README.md: -------------------------------------------------------------------------------- 1 | # Running JS in ` 10 | 11 | If the inlined script has executed, the following text will recommend an 12 | outfit for you: {global.specialText} 13 | 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/internal-routing/README.md: -------------------------------------------------------------------------------- 1 | # Internal routing within Batfish pages 2 | 3 | - Pages with `internalRouting: true` front matter use [react-router] for additional client-side routing *within the Batfish page*. 4 | 5 | [react-router]: https://github.com/ReactTraining/react-router/ 6 | -------------------------------------------------------------------------------- /examples/internal-routing/batfish.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = () => { 4 | return { 5 | applicationWrapperPath: path.join(__dirname, './src/wrapper.js') 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /examples/internal-routing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "batfish": "NODE_OPTIONS=--openssl-legacy-provider ../../bin/example-batfish" 5 | }, 6 | "dependencies": { 7 | "react-router-dom": "^4.2.2" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/internal-routing/src/pages/index.md: -------------------------------------------------------------------------------- 1 | Just a homepage. 2 | -------------------------------------------------------------------------------- /examples/internal-routing/src/pages/letters.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | internalRouting: true 3 | ---*/ 4 | 5 | const React = require('react'); 6 | const ReactRouter = require('react-router-dom'); 7 | 8 | class ShownLetter extends React.PureComponent { 9 | render() { 10 | return ( 11 |
12 | {this.props.match.params.id} 13 |
14 | ); 15 | } 16 | } 17 | 18 | class Letters extends React.PureComponent { 19 | constructor() { 20 | super(); 21 | this.state = { 22 | mounted: false 23 | }; 24 | } 25 | 26 | componentDidMount() { 27 | this.setState({ mounted: true }); 28 | } 29 | 30 | render() { 31 | if (!this.state.mounted) return null; 32 | 33 | const letterLinks = []; 34 | for (let i = 65; i < 75; i++) { 35 | const letter = String.fromCharCode(i); 36 | letterLinks.push( 37 |
  • 38 | Show {letter} 39 |
  • 40 | ); 41 | } 42 | 43 | return ( 44 | 45 |
    46 |

    There are many numbers to choose from.

    47 | 48 |
      {letterLinks}
    49 |
    50 |
    51 | ); 52 | } 53 | } 54 | 55 | module.exports = Letters; 56 | -------------------------------------------------------------------------------- /examples/internal-routing/src/pages/numbers.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | internalRouting: true 3 | ---*/ 4 | 5 | const React = require('react'); 6 | const ReactRouter = require('react-router-dom'); 7 | 8 | class ShownNumber extends React.PureComponent { 9 | render() { 10 | return ( 11 |
    12 | {this.props.match.params.id} 13 |
    14 | ); 15 | } 16 | } 17 | 18 | class Numbers extends React.PureComponent { 19 | constructor() { 20 | super(); 21 | this.state = { 22 | mounted: false 23 | }; 24 | } 25 | 26 | componentDidMount() { 27 | this.setState({ mounted: true }); 28 | } 29 | 30 | render() { 31 | if (!this.state.mounted) return null; 32 | 33 | const numberLinks = []; 34 | for (let i = 0; i < 11; i++) { 35 | numberLinks.push( 36 |
  • 37 | 38 | Show {i} 39 | 40 |
  • 41 | ); 42 | } 43 | 44 | return ( 45 | 46 |
    47 |

    There are many numbers to choose from.

    48 | 49 |
      {numberLinks}
    50 |
    51 |
    52 | ); 53 | } 54 | } 55 | 56 | module.exports = Numbers; 57 | -------------------------------------------------------------------------------- /examples/internal-routing/src/wrapper.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class Wrapper extends React.PureComponent { 4 | render() { 5 | return ( 6 |
    7 | 21 | {this.props.children} 22 |
    23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/legacy/README.md: -------------------------------------------------------------------------------- 1 | # Not-so-fancy JavaScript 2 | 3 | - Uses create-react-class to create React components, instead of ES2015 `class`. 4 | - Uses CommonJS module syntax, instead of ES2015 `import` and `export`. 5 | -------------------------------------------------------------------------------- /examples/legacy/batfish.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = () => { 4 | return { 5 | applicationWrapperPath: path.join( 6 | __dirname, 7 | './src/components/application-wrapper.js' 8 | ) 9 | }; 10 | }; 11 | -------------------------------------------------------------------------------- /examples/legacy/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "batfish": "NODE_OPTIONS=--openssl-legacy-provider ../../bin/example-batfish" 5 | }, 6 | "dependencies": { 7 | "create-react-class": "^15.6.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/legacy/src/components/application-wrapper.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/display-name */ 2 | var React = require('react'); 3 | var PropTypes = require('prop-types'); 4 | var createClass = require('create-react-class'); 5 | 6 | var ApplicationWrapper = createClass({ 7 | propTypes: { 8 | children: PropTypes.node.isRequired 9 | }, 10 | render: function () { 11 | return ( 12 |
    13 |

    CommonJS module syntax works

    14 | {this.props.children} 15 |
    16 | ); 17 | } 18 | }); 19 | 20 | module.exports = ApplicationWrapper; 21 | -------------------------------------------------------------------------------- /examples/legacy/src/pages/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/display-name */ 2 | var React = require('react'); 3 | var createClass = require('create-react-class'); 4 | 5 | var Legacy = createClass({ 6 | render: function () { 7 | return
    This page has rendered.
    ; 8 | } 9 | }); 10 | 11 | module.exports = Legacy; 12 | -------------------------------------------------------------------------------- /examples/markdown-wrappers/README.md: -------------------------------------------------------------------------------- 1 | # Markdown wrappers 2 | 3 | - Provides a function to [`jsxtremeMarkdownOptions.getWrapper`], exemplifying how you can apply different Markdown wrappers to different files, without having to manually specify the wrapper in the front matter of each file. 4 | 5 | [`jsxtrememarkdownoptions.getwrapper`]: ../../docs/configuration.md#jsxtrememarkdownoptions 6 | -------------------------------------------------------------------------------- /examples/markdown-wrappers/batfish.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = () => { 4 | return { 5 | jsxtremeMarkdownOptions: { 6 | getWrapper: (resource) => { 7 | if (/-a\.md$/.test(resource)) { 8 | return path.join(__dirname, './src/components/markdown-wrapper-a.js'); 9 | } 10 | return path.join(__dirname, './src/components/markdown-wrapper-b.js'); 11 | } 12 | } 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /examples/markdown-wrappers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "batfish": "NODE_OPTIONS=--openssl-legacy-provider ../../bin/example-batfish" 5 | }, 6 | "dependencies": {} 7 | } 8 | -------------------------------------------------------------------------------- /examples/markdown-wrappers/src/components/markdown-wrapper-a.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PageWrapper from './page-wrapper'; 3 | 4 | export default class MarkdownWrapperA extends React.Component { 5 | render() { 6 | return ( 7 | 8 |

    Markdown Wrapper A

    9 |
    {this.props.children}
    10 |
    11 | ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/markdown-wrappers/src/components/markdown-wrapper-b.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PageWrapper from './page-wrapper'; 3 | 4 | export default class MarkdownWrapperB extends React.Component { 5 | render() { 6 | return ( 7 | 8 |

    Markdown Wrapper B

    9 |
    {this.props.children}
    10 |
    11 | ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/markdown-wrappers/src/components/page-wrapper.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class PageWrapper extends React.PureComponent { 4 | render() { 5 | return ( 6 |
    7 | 29 | {this.props.children} 30 |
    31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/markdown-wrappers/src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PageWrapper from '../components/page-wrapper'; 3 | 4 | export default class Home extends React.Component { 5 | render() { 6 | return Home page. Click a link.; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/markdown-wrappers/src/pages/markdown-a.md: -------------------------------------------------------------------------------- 1 | This page should be using markdown wrapper **A**. 2 | -------------------------------------------------------------------------------- /examples/markdown-wrappers/src/pages/markdown-b.md: -------------------------------------------------------------------------------- 1 | This page should be using markdown wrapper **B**. 2 | -------------------------------------------------------------------------------- /examples/markdown-wrappers/src/pages/markdown-c.md: -------------------------------------------------------------------------------- 1 | --- 2 | wrapper: '../components/markdown-wrapper-a' 3 | --- 4 | 5 | This page explicitly requests markdown wrapper A. 6 | -------------------------------------------------------------------------------- /examples/markdown-wrappers/src/pages/markdown-fake-a.md: -------------------------------------------------------------------------------- 1 | --- 2 | wrapper: '../components/markdown-wrapper-b' 3 | --- 4 | 5 | This page explicitly requests markdown wrapper B. 6 | -------------------------------------------------------------------------------- /examples/miscellany/README.md: -------------------------------------------------------------------------------- 1 | # A miscellany exemplifying miscellaneous features 2 | 3 | - Uses the [`dataSelectors`] configuration property to create navigation and indexes. 4 | - Uses `@mapbox/batfish/modules/md` to compile jsxtreme-markdown at build time within React components. 5 | - Configuration includes a [`siteBasePath`], so `@mapbox/batfish/modules/prefix-url` is used to appropriately prefix URLs for links. 6 | - Includes Facebook `` tags in its generic page shell. 7 | - Uses the [`siteOrigin`] configuration property so a `sitemap.xml` file is generated. 8 | - Uses [jsxtreme-markdown-loader's `getWrapper` option](https://github.com/mapbox/jsxtreme-markdown/tree/master/packages/jsxtreme-markdown-loader#getwrapper) to determine the Markdown page wrapper component based on its path. 9 | - Exemplifies some conventions you might consider as your site grows: 10 | - Isolates [`dataSelectors`] in their own module. 11 | - Implements wrapper components for specific content types, which wrap the generic page shell. 12 | 13 | [`dataselectors`]: ../../docs/configuration.md#dataselectors 14 | 15 | [`sitebasepath`]: ../../docs/configuration.md#sitebasepath 16 | 17 | [`siteorigin`]: ../../docs/configuration.md#siteorigin 18 | -------------------------------------------------------------------------------- /examples/miscellany/batfish.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const selectors = require('./lib/selectors'); 3 | 4 | module.exports = () => { 5 | return { 6 | siteBasePath: '/miscellany', 7 | siteOrigin: 'https://www.your-batfish-site.com', 8 | applicationWrapperPath: path.join( 9 | __dirname, 10 | './src/components/application-wrapper.js' 11 | ), 12 | stylesheets: [ 13 | 'https://api.mapbox.com/mapbox-assembly/v0.17.0/assembly.min.css' 14 | ], 15 | jsxtremeMarkdownOptions: { 16 | getWrapper: (resource) => { 17 | if (/\/stories\//.test(resource)) { 18 | return path.join(__dirname, './src/components/story-wrapper.js'); 19 | } 20 | } 21 | }, 22 | dataSelectors: selectors 23 | }; 24 | }; 25 | -------------------------------------------------------------------------------- /examples/miscellany/lib/selectors.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | 3 | const selectors = {}; 4 | 5 | selectors.holidaysData = (data) => { 6 | const holidays = data.pages.filter((page) => 7 | /\/holidays\/.+/.test(page.path) 8 | ); 9 | return _.sortBy(holidays, (holiday) => holiday.frontMatter.month); 10 | }; 11 | 12 | selectors.storiesData = (data) => { 13 | const stories = data.pages.filter((page) => /\/stories\/.+/.test(page.path)); 14 | return _.sortBy(stories, (post) => post.frontMatter.title); 15 | }; 16 | 17 | module.exports = selectors; 18 | -------------------------------------------------------------------------------- /examples/miscellany/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "batfish": "NODE_OPTIONS=--openssl-legacy-provider ../../bin/example-batfish" 5 | }, 6 | "dependencies": { 7 | "lodash": "^4.17.4" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/miscellany/src/components/application-wrapper.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class ApplicationWrapper extends React.Component { 4 | render() { 5 | return
    {this.props.children}
    ; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/miscellany/src/components/holiday-image.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | export default class HolidayImage extends React.PureComponent { 5 | render() { 6 | const { props } = this; 7 | const style = props.style; 8 | if (style.maxWidth === undefined) { 9 | style.maxWidth = '100%'; 10 | } 11 | return ( 12 |
    13 | 14 |
    15 | ); 16 | } 17 | } 18 | 19 | HolidayImage.propTypes = { 20 | src: PropTypes.string.isRequired, 21 | style: PropTypes.object 22 | }; 23 | 24 | HolidayImage.defaultProps = { 25 | style: {} 26 | }; 27 | -------------------------------------------------------------------------------- /examples/miscellany/src/components/holiday-wrapper.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import holidaysData from '@mapbox/batfish/data/holidays-data'; 3 | import PageShell from './page-shell'; 4 | import SidebarNavigation from './sidebar-navigation'; 5 | 6 | const sidebarItems = holidaysData.map((holiday) => { 7 | return { 8 | content: ( 9 |
    10 | {holiday.frontMatter.title} 11 |
    ({holiday.frontMatter.date})
    12 |
    13 | ), 14 | url: holiday.path 15 | }; 16 | }); 17 | 18 | export default class HolidayWrapper extends React.Component { 19 | render() { 20 | const { props } = this; 21 | 22 | return ( 23 | 24 |
    25 |
    26 | 27 |
    28 |
    29 |

    {props.frontMatter.title}

    30 |
    31 | {props.frontMatter.date} 32 |
    33 |
    {props.children}
    34 |
    35 |
    36 |
    37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/miscellany/src/components/page-shell.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Helmet } from 'react-helmet'; 4 | import { prefixUrl } from '@mapbox/batfish/modules/prefix-url'; 5 | 6 | export default class PageShell extends React.Component { 7 | render() { 8 | const { props } = this; 9 | const title = `${props.frontMatter.title} | Miscellany`; 10 | return ( 11 |
    12 | 13 | 14 | 15 | 16 | {title} 17 | 18 | {/* Facebook tags */} 19 | 20 | 21 | 22 | 26 | 27 |
    28 | 48 | {props.children} 49 |
    50 |
    51 | ); 52 | } 53 | } 54 | 55 | PageShell.propTypes = { 56 | location: PropTypes.shape({ 57 | pathname: PropTypes.string.isRequired 58 | }).isRequired, 59 | frontMatter: PropTypes.shape({ 60 | title: PropTypes.string.isRequired, 61 | description: PropTypes.string.isRequired 62 | }).isRequired, 63 | children: PropTypes.node.isRequired 64 | }; 65 | -------------------------------------------------------------------------------- /examples/miscellany/src/components/sidebar-navigation.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | export default class SidebarNavigation extends React.PureComponent { 5 | render() { 6 | const { props } = this; 7 | 8 | const itemElements = props.items.map((item) => { 9 | let linkClasses = 'link block py6 border-b border--gray-light'; 10 | return ( 11 |
  • 12 | 13 | {item.content} 14 | 15 |
  • 16 | ); 17 | }); 18 | 19 | return ( 20 |
    21 |
    {props.title}
    22 |
      {itemElements}
    23 |
    24 | ); 25 | } 26 | } 27 | 28 | SidebarNavigation.propTypes = { 29 | title: PropTypes.string.isRequired, 30 | items: PropTypes.arrayOf( 31 | PropTypes.shape({ 32 | content: PropTypes.node.isRequired, 33 | url: PropTypes.string.isRequired 34 | }) 35 | ).isRequired 36 | }; 37 | -------------------------------------------------------------------------------- /examples/miscellany/src/components/story-wrapper.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import storiesData from '@mapbox/batfish/data/stories-data'; 3 | import PageShell from './page-shell'; 4 | import SidebarNavigation from './sidebar-navigation'; 5 | import getLegibleDate from '../utilities/get-legible-date'; 6 | 7 | const sidebarItems = storiesData.map((story) => { 8 | return { 9 | content: story.frontMatter.title, 10 | url: story.path 11 | }; 12 | }); 13 | 14 | export default class StoryWrapper extends React.Component { 15 | render() { 16 | const { props } = this; 17 | 18 | let subtitleElement =
    ; 19 | if (props.frontMatter.subtitle) { 20 | subtitleElement = ( 21 |
    {props.frontMatter.subtitle}
    22 | ); 23 | } 24 | 25 | return ( 26 | 27 |
    28 |
    29 | 30 |
    31 |
    32 |

    {props.frontMatter.title}

    33 | {subtitleElement} 34 |
    {props.children}
    35 |
    36 | Posted {getLegibleDate(props.frontMatter.date)} 37 |
    38 |
    39 |
    40 |
    41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/miscellany/src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class NotFound extends React.Component { 4 | render() { 5 | return ( 6 |
    7 |
    404: Page not found
    8 |
    9 | ); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/miscellany/src/pages/holidays/independence-day.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | title: Independence Day 3 | description: Description of Independence Day. 4 | date: "4th of July" 5 | month: 07 6 | ---*/ 7 | 8 | import React from 'react'; 9 | import md from '@mapbox/batfish/modules/md'; 10 | import HolidayWrapper from '../../components/holiday-wrapper'; 11 | import HolidayImage from '../../components/holiday-image'; 12 | 13 | export default class IndependenceDay extends React.Component { 14 | render() { 15 | const { props } = this; 16 | return ( 17 | 18 | 22 | {md` 23 | **Independence Day**, also referred to as the Fourth of July or July Fourth, is a federal holiday in the United States commemorating the adoption of the [Declaration of Independence](https://en.wikipedia.org/wiki/United_States_Declaration_of_Independence) on July 4, 1776. The Continental Congress declared that the thirteen American colonies regarded themselves as a new nation, the United States of America, and were no longer part of the British Empire. The Congress actually voted to declare independence two days earlier, on July 2. 24 | 25 | **Independence Day** is commonly associated with fireworks, parades, barbecues, carnivals, fairs, picnics, concerts, baseball games, family reunions, and political speeches and ceremonies, in addition to various other public and private events celebrating the history, government, and traditions of the United States. **Independence Day** is the National Day of the United States. 26 | 27 | **[Learn more about Independence Day.]()** 28 | `} 29 | 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/miscellany/src/pages/holidays/index.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | title: Holidays 3 | description: A collection of articles about holidays. 4 | ---*/ 5 | 6 | import React from 'react'; 7 | import holidaysData from '@mapbox/batfish/data/holidays-data'; 8 | import PageShell from '../../components/page-shell'; 9 | 10 | export default class Holidays extends React.Component { 11 | render() { 12 | const { props } = this; 13 | 14 | const holidayItems = holidaysData.map((holiday) => { 15 | return ( 16 | 21 |
    22 | {holiday.frontMatter.title} 23 |
    24 |
    ({holiday.frontMatter.date})
    25 |
    26 | ); 27 | }); 28 | 29 | return ( 30 | 31 |

    Holidays!

    32 | {holidayItems} 33 |
    34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/miscellany/src/pages/holidays/labor-day.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | title: Labor Day 3 | description: Description of Labor Day. 4 | date: First Monday of September 5 | month: 09 6 | ---*/ 7 | 8 | import React from 'react'; 9 | import md from '@mapbox/batfish/modules/md'; 10 | import HolidayWrapper from '../../components/holiday-wrapper'; 11 | import HolidayImage from '../../components/holiday-image'; 12 | 13 | export default class LaborDay extends React.Component { 14 | render() { 15 | const { props } = this; 16 | return ( 17 | 18 | 19 | {md` 20 | **Labor Day** in the United States is a public holiday celebrated on the first Monday in September. It honors the [American labor movement](https://en.wikipedia.org/wiki/Labor_history_of_the_United_States) and the contributions that workers have made to the strength, prosperity, laws and well-being of the country. It is the Monday of the long weekend known as **Labor Day** Weekend and it is considered the unofficial end of summer in the United States. The holiday is also a federal holiday. 21 | 22 | Beginning in the late 19th century, as the trade union and labor movements grew, trade unionists proposed that a day be set aside to celebrate labor. "**Labor Day**" was promoted by the Central Labor Union and the Knights of Labor, which organized the first parade in New York City. In 1887, Oregon was the first state of the United States to make it an official public holiday. By the time it became an official federal holiday in 1894, thirty U.S. states officially celebrated **Labor Day**. 23 | 24 | **[Learn more about Labor Day.]()** 25 | `} 26 | 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/miscellany/src/pages/holidays/memorial-day.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | title: Memorial Day 3 | description: Description of Memorial Day. 4 | date: Last Monday of May 5 | month: 05 6 | ---*/ 7 | 8 | import React from 'react'; 9 | import md from '@mapbox/batfish/modules/md'; 10 | import HolidayWrapper from '../../components/holiday-wrapper'; 11 | import HolidayImage from '../../components/holiday-image'; // eslint-disable-line no-unused-vars 12 | 13 | export default class MemorialDay extends React.Component { 14 | render() { 15 | const { props } = this; 16 | return ( 17 | 18 | {md` 19 | {{ 20 | 24 | }} 25 | 26 | **Memorial Day** is a federal holiday in the United States for remembering the people who died while serving in the [country's armed forces](https://en.wikipedia.org/wiki/United_States_Armed_Forces). The holiday, which is currently observed every year on the last Monday of May, was held on May 29, 2017. The holiday was held on May 30 from 1868-1970. It marks the start of the unofficial summer vacation season, while Labor Day marks its end. 27 | 28 | Many people visit cemeteries and memorials, particularly to honor those who have died in military service. Many volunteers place an American flag on each grave in national cemeteries. 29 | 30 | {{ 31 | 34 | }} 35 | 36 | **Memorial Day** is not to be confused with Veterans Day; **Memorial Day** is a day of remembering the men and women who died while serving, while Veterans Day celebrates the service of all U.S. military veterans. 37 | 38 | **[Learn more about Memorial Day.]()** 39 | `} 40 | 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/miscellany/src/pages/index.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | title: Home 3 | description: The home page of my miscellany. 4 | ---*/ 5 | 6 | import React from 'react'; 7 | import { prefixUrl } from '@mapbox/batfish/modules/prefix-url'; 8 | import PageShell from '../components/page-shell'; 9 | 10 | export default class Home extends React.Component { 11 | render() { 12 | const { props } = this; 13 | 14 | return ( 15 | 16 |

    The Batfish Miscellany

    17 | 25 | 30 |
    31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/miscellany/src/pages/stories/index.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | title: Stories 3 | description: A collection of stories by Stephen Crane. 4 | ---*/ 5 | 6 | import React from 'react'; 7 | import storiesData from '@mapbox/batfish/data/stories-data'; 8 | import PageShell from '../../components/page-shell'; 9 | 10 | export default class Stories extends React.Component { 11 | render() { 12 | const { props } = this; 13 | 14 | const storyItems = storiesData.map((story) => { 15 | return ( 16 | 21 |
    {story.frontMatter.title}
    22 |
    {story.frontMatter.subtitle}
    23 |
    24 | ); 25 | }); 26 | 27 | return ( 28 | 29 |

    Stories!

    30 |
    All by Stephen Crane.
    31 | {storyItems} 32 |
    33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/miscellany/src/pages/stories/ominous-baby.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: An Ominous Baby 3 | description: "Stephen Crane's story of an ominous baby." 4 | date: "2014-11-12" 5 | --- 6 | 7 | A baby was wandering in a strange country. He was a tattered child with a frowsled wealth of yellow hair. His dress, of a checked stuff, was soiled, and showed the marks of many conflicts, like the chain-shirt of a warrior. His sun-tanned knees shone above wrinkled stockings, which he pulled up occasionally with an impatient movement when they entangled his feet. From a gaping shoe there appeared an array of tiny toes. 8 | 9 | He was toddling along an avenue between rows of stolid brown houses. He went slowly, with a look of absorbed interest on his small flushed face. His blue eyes stared curiously. Carriages went with a musical rumble over the smooth asphalt. A man with a chrysanthemum was going up steps. Two nursery maids chatted as they walked slowly, while their charges hobnobbed amiably between perambulators. A truck wagon roared thunderously in the distance. 10 | 11 | The child from the poor district made his way along the brown street filled with dull grey shadows. High up, near the roofs, glancing sun-rays changed cornices to blazing gold and silvered the fronts of windows. The wandering baby stopped and stared at the two children laughing and playing in their carriages among the heaps of rugs and cushions. He braced his legs apart in an attitude of earnest attention. His lower jaw fell, and disclosed his small, even teeth. As they moved on, he followed the carriages with awe in his face as if contemplating a pageant. Once one of the babies, with twittering laughter, shook a gorgeous rattle at him. He smiled jovially in return. 12 | 13 | Finally a nursery maid ceased conversation and, turning, made a gesture of annoyance. 14 | 15 | "Go 'way, little boy," she said to him. "Go 'way. You're all dirty." 16 | 17 | He gazed at her with infant tranquillity for a moment, and then went slowly off dragging behind him a bit of rope he had acquired in another street. He continued to investigate the new scenes. The people and houses struck him with interest as would flowers and trees. Passengers had to avoid the small, absorbed figure in the middle of the sidewalk. They glanced at the intent baby face covered with scratches and dust as with scars and with powder smoke. 18 | 19 | ... 20 | 21 | **[Read the rest of this story on Project Gutenberg.](https://www.gutenberg.org/files/45524/45524-h/45524-h.htm#An-Ominous-Baby)** 22 | -------------------------------------------------------------------------------- /examples/miscellany/src/utilities/get-legible-date.js: -------------------------------------------------------------------------------- 1 | export default function getLegibleDate(machineDate) { 2 | const splitString = new Date(machineDate).toString().split(' '); 3 | return splitString.slice(1, 3).join(' ') + ', ' + splitString[3]; 4 | } 5 | -------------------------------------------------------------------------------- /examples/no-config/README.md: -------------------------------------------------------------------------------- 1 | # The no-configuration Batfish example 2 | 3 | - No configuration necessary. 4 | -------------------------------------------------------------------------------- /examples/no-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "batfish": "NODE_OPTIONS=--openssl-legacy-provider ../../bin/example-batfish" 5 | }, 6 | "dependencies": {} 7 | } 8 | -------------------------------------------------------------------------------- /examples/no-config/src/pages/index.md: -------------------------------------------------------------------------------- 1 | Look ma no config. 2 | -------------------------------------------------------------------------------- /examples/optimizing-loaders/README.md: -------------------------------------------------------------------------------- 1 | # Custom Webpack and Babel stuff 2 | 3 | - Uses [image-webpack-loader] to optimize images. 4 | To accomplish this, takes advantage of the [`fileLoaderExtensions`] and [`webpackLoaders`] configuration options. 5 | - Uses a minimal bundle of Lodash, enabled by [babel-plugin-lodash] and [lodash-webpack-plugin]. 6 | To accomplish this, takes advantage of the [`webpackPlugins`] and [`babelPlugins`] configuration options. 7 | 8 | [image-webpack-loader]: https://github.com/tcoopman/image-webpack-loader 9 | 10 | [`fileloaderextensions`]: ../../docs/configuration.md#fileloaderextensions 11 | 12 | [`webpackloaders`]: ../../docs/configuration.md#webpackloaders 13 | 14 | [`webpackplugins`]: ../../docs/configuration.md#webpackplugins 15 | 16 | [`babelplugins`]: ../../docs/configuration.md#babelplugins 17 | 18 | [babel-plugin-lodash]: https://github.com/lodash/babel-plugin-lodash 19 | 20 | [lodash-webpack-plugin]: https://github.com/lodash/lodash-webpack-plugin 21 | -------------------------------------------------------------------------------- /examples/optimizing-loaders/batfish.config.js: -------------------------------------------------------------------------------- 1 | const batfish = require('../../dist/node'); 2 | const LodashModuleReplacementPlugin = require('lodash-webpack-plugin'); 3 | 4 | module.exports = () => { 5 | return { 6 | fileLoaderExtensions: ['webp', 'mp4', 'webm', 'woff', 'woff2'], 7 | webpackLoaders: [ 8 | { 9 | test: /\.(jpe?g|png|gif)$/, 10 | use: [ 11 | { 12 | loader: 'file-loader', 13 | options: { 14 | hash: 'sha512', 15 | digest: 'hex', 16 | name: '[name]-[hash].[ext]' 17 | } 18 | }, 19 | { loader: 'image-webpack-loader' } 20 | ] 21 | } 22 | ], 23 | webpackPlugins: [ 24 | new LodashModuleReplacementPlugin(), 25 | new batfish.webpack.DefinePlugin({ 26 | DEFINED: '"yes"' 27 | }) 28 | ], 29 | babelPlugins: [require('babel-plugin-lodash')] 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /examples/optimizing-loaders/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "batfish": "NODE_OPTIONS=--openssl-legacy-provider ../../bin/example-batfish" 5 | }, 6 | "dependencies": { 7 | "babel-plugin-lodash": "^3.3.4", 8 | "image-webpack-loader": "^6.0.0", 9 | "lodash-webpack-plugin": "^0.11.5" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/optimizing-loaders/src/img/man-in-a-bottle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/batfish/4230d75d5541954374d070ab94f6850a61a925e8/examples/optimizing-loaders/src/img/man-in-a-bottle.jpg -------------------------------------------------------------------------------- /examples/optimizing-loaders/src/pages/index.js: -------------------------------------------------------------------------------- 1 | /* globals DEFINED */ 2 | import React from 'react'; 3 | import _ from 'lodash'; 4 | export default class Home extends React.PureComponent { 5 | render() { 6 | const nestedNumber = { 7 | foo: { 8 | bar: { 9 | baz: 3, 10 | bap: 4 11 | } 12 | } 13 | }; 14 | 15 | return ( 16 |
    17 |

    Optimization loaders and plugins

    18 | Did the DefinePlugin work?{' '} 19 | 20 | {DEFINED === 'yes' ? 'Yes!' : 'No!'} 21 | 22 |
    23 | 24 |
    25 |
    26 | The Lodash plugin works if the following does not say "3":{' '} 27 | 28 | {_.get(nestedNumber, 'foo.bar.baz', '☉_☉')} 29 | 30 |
    31 |
    32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/page-specific-css/README.md: -------------------------------------------------------------------------------- 1 | # Page-specific CSS 2 | 3 | - Shows how you can import and mount [page-specific CSS](../../docs/advanced-usage.md#page-specific-css). 4 | -------------------------------------------------------------------------------- /examples/page-specific-css/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "batfish": "NODE_OPTIONS=--openssl-legacy-provider ../../bin/example-batfish" 5 | }, 6 | "dependencies": {} 7 | } 8 | -------------------------------------------------------------------------------- /examples/page-specific-css/src/pages/another.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: pink; 3 | color: gray; 4 | } 5 | -------------------------------------------------------------------------------- /examples/page-specific-css/src/pages/another.md: -------------------------------------------------------------------------------- 1 | --- 2 | prependJs: 3 | - "import AnotherCss from './another.css'" 4 | --- 5 | 6 | {{ }} 7 | 8 | This is another page. 9 | 10 | Go to [the home page](/). 11 | -------------------------------------------------------------------------------- /examples/page-specific-css/src/pages/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: lightblue; 3 | color: red; 4 | } 5 | -------------------------------------------------------------------------------- /examples/page-specific-css/src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import HomeCss from './index.css'; 3 | 4 | export default class Home extends React.Component { 5 | render() { 6 | return ( 7 |
    8 | 9 |
    10 |

    This is the home page.

    11 |

    12 | Go to another page. 13 |

    14 |
    15 |
    16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/sitemap/README.md: -------------------------------------------------------------------------------- 1 | # Customize the sitemap 2 | 3 | This example customizes the sitemap by using the `ignoreFile` option to remove some files from the sitemap. 4 | 5 | Since Batfish only generates the sitemap on build, run: 6 | 7 | ``` 8 | npm run batfish -- build && npm run batfish -- serve-static 9 | ``` -------------------------------------------------------------------------------- /examples/sitemap/batfish.config.js: -------------------------------------------------------------------------------- 1 | module.exports = () => { 2 | return { 3 | siteOrigin: 'https://www.batfish-basic.com', 4 | webpackLoaders: [ 5 | { 6 | test: /\.html$/, 7 | /* simulates a process where an html file is transformed and then saved to assets folder */ 8 | use: [ 9 | 'file-loader?name=[name]-demo.[ext]', 10 | 'extract-loader', 11 | { 12 | loader: 'html-loader', 13 | options: { 14 | minimize: true 15 | } 16 | } 17 | ] 18 | } 19 | ], 20 | ignoreWithinPagesDirectory: ['example/*.html'], 21 | sitemap: { 22 | ignoreFile: 'ignore.js' 23 | } 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /examples/sitemap/ignore.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | `${process.cwd()}/_batfish_site/assets/` // prevent any pages from the assets folder from being added to the sitemap 3 | ]; 4 | -------------------------------------------------------------------------------- /examples/sitemap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "batfish": "NODE_OPTIONS=--openssl-legacy-provider ../../bin/example-batfish" 5 | }, 6 | "dependencies": { 7 | "extract-loader": "^5.1.0", 8 | "html-loader": "^1.3.2" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/sitemap/src/pages/example/simple-map.html: -------------------------------------------------------------------------------- 1 |

    I am a code demo that should not be indexed by web crawlers!

    -------------------------------------------------------------------------------- /examples/sitemap/src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import iframe from './example/simple-map.html'; 3 | export default class Home extends React.PureComponent { 4 | render() { 5 | return ( 6 |
    7 |

    Sitemap demo

    8 |

    9 | The url{' '} 10 | 11 | https://www.batfish-basic.com{iframe.replace('.html', '')} 12 | {' '} 13 | should not appear in the sitemap. 14 |

    15 |