├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── npmpublish.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── gatsby-node.js ├── index.js ├── package.json └── yarn.lock /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: luanbitar 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/workflows/npmpublish.yml: -------------------------------------------------------------------------------- 1 | name: NPM publish 2 | on: 3 | release: 4 | types: [created] 5 | 6 | jobs: 7 | publish-npm: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: actions/setup-node@v1 12 | with: 13 | node-version: 12 14 | registry-url: https://registry.npmjs.org/ 15 | - run: npm publish 16 | env: 17 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | farm.js -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | README.md 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": false, 4 | "tabWidth": 2, 5 | "useTabs": false 6 | } 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at 7@lbitar.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Version](https://img.shields.io/npm/v/gatsby-plugin-dynamic-routes.svg)](https://www.npmjs.com/package/gatsby-plugin-dynamic-routes) 2 | [![Downloads Total](https://img.shields.io/npm/dt/gatsby-plugin-dynamic-routes.svg)](https://www.npmjs.com/package/gatsby-plugin-dynamic-routes) 3 | 4 | # gatsby-plugin-dynamic-routes 5 | 6 | Use one file to declare your routes, provides to chose dynamic route paths based on your `BUILD_ENV` or `ROUTE_ENV` to your custom routing env. Also it's possible to only renaming routes on `pages/`, or use everything together. 7 | 8 | ## Install 9 | 10 | `$ npm i gatsby-plugin-dynamic-routes` 11 | 12 | or 13 | 14 | `$ yarn add gatsby-plugin-dynamic-routes` 15 | 16 | ## How to use 17 | 18 | Add the plugin to your `gatsby-config.js`. 19 | 20 | ```javascript 21 | module.exports = { 22 | plugins: [ 23 | `gatsby-plugin-dynamic-routes` 24 | ] 25 | } 26 | ``` 27 | 28 | Create your's `Routes.js` inside your `src/` folder 29 | 30 | ```bash 31 | project/ 32 | ├── src/ 33 | └── Routes.js 34 | ``` 35 | 36 | `Routes.js` 37 | 38 | ```javascript 39 | module.exports = { 40 | home: { 41 | path: `/casa`, 42 | component: `src/pages/Home.js` 43 | } 44 | } 45 | ``` 46 | 47 | Use in client-side, include globals comment 48 | 49 | `component/Example.js` 50 | 51 | ```javascript 52 | import { Link } from "gatsby" 53 | 54 | function Example() { 55 | return 56 | } 57 | ``` 58 | 59 | ## Dynamic routes 60 | 61 | `Routes.js` 62 | 63 | ```javascript 64 | module.exports = { 65 | development: { 66 | two: { 67 | path: `/2`, 68 | component: `src/pages/Two.js` 69 | } 70 | }, 71 | staging: { 72 | two: { 73 | path: `/dois`, 74 | component: `src/pages/Two.js` 75 | } 76 | }, 77 | home: { 78 | path: `/casa`, 79 | component: `src/pages/Home.js` 80 | } 81 | } 82 | ``` 83 | 84 | Run with your `BUILD_ENV` environment 85 | 86 | ```bash 87 | BUILD_ENV=staging yarn start 88 | ``` 89 | 90 | If you are using the plugin [Dynamic Environment Variables][1], what will happen is that your environments inside your `.env` and `.env.staging` will be loaded, and your routes inside `staging` key will go to root of the object that is exported of `Routes` and will be available in yours global environment variables. 91 | 92 | `component/Example.js` 93 | 94 | ```javascript 95 | import { Link } from "gatsby" 96 | /* globals ROUTES */ 97 | 98 | function Example() { 99 | return 100 | } 101 | ``` 102 | 103 | Note that you need to put `eslint globals comment` in each file that will use `ROUTES` global variable. 104 | 105 | You need to create an empty `.eslintrc` in root of your folder to remove this comments. 106 | 107 | If you are using eslint in your project, just update this key to your config: 108 | 109 | ```javascript 110 | { 111 | "rules": { 112 | "no-undef": "off" 113 | } 114 | } 115 | ``` 116 | 117 | You can pass more than `path` or `component` keys, these keys will be available in your component later 118 | 119 | ## Variations 120 | 121 | If you want to made variations of the same environment, but whit different routes, you can use `ROUTE_ENV` variable to chose your dynamic routes 122 | 123 | `example` 124 | 125 | ```bash 126 | ROUTE_ENV=organic BUILD_ENV=production yarn build 127 | ``` 128 | 129 | ## Options 130 | 131 | ### `routeFilePath` 132 | 133 | This options allows you to specify what's the path to your file with your Routes object 134 | 135 | Example: 136 | 137 | ```javascript 138 | module.exports = { 139 | plugins: [ 140 | { 141 | resolve: `gatsby-plugin-dynamic-routes`, 142 | options: { 143 | routeFilePath: `config/Routes.js` 144 | } 145 | } 146 | ] 147 | } 148 | ``` 149 | 150 | ```bash 151 | project/ 152 | ├── config/ 153 | └── Routes.js 154 | ``` 155 | 156 | If you want to put in root of your project, simply put the name of your file 157 | 158 | ## Ignoring gatsby default page creator 159 | 160 | By default, gatsby generates one route to each file inside `pages/` folder, to disable this feature, put in you `gatsby-config.js`: 161 | 162 | ```js 163 | { 164 | resolve: `gatsby-plugin-page-creator`, 165 | options: { 166 | path: `${__dirname}/src/pages`, 167 | ignore: { 168 | patterns: [`**/*`], 169 | }, 170 | }, 171 | }, 172 | ``` 173 | 174 | ## Recommended plugins 175 | 176 | Check out the [Dynamic Environment Variables][1] plugin that provides you to load different files based on your env variables 177 | 178 | [1]: https://github.com/luanbitar/gatsby-env-variables 179 | -------------------------------------------------------------------------------- /gatsby-node.js: -------------------------------------------------------------------------------- 1 | const path = require("path") 2 | 3 | function getDynamicRoutes(routeFilePath = `src/Routes`) { 4 | const routesFile = require(path.resolve(routeFilePath)) 5 | 6 | const routeKeys = Object.keys(routesFile) 7 | const staticRouteKeys = routeKeys.filter(route => { 8 | const childKeys = Object.keys(routesFile[route]) 9 | return childKeys.includes("path") 10 | }) 11 | const staticRoutes = staticRouteKeys.reduce( 12 | (acc, route) => ({ 13 | ...acc, 14 | [route]: routesFile[route] 15 | }), 16 | {} 17 | ) 18 | 19 | const { ROUTE_ENV, BUILD_ENV, NODE_ENV } = process.env 20 | const environment = ROUTE_ENV || BUILD_ENV || NODE_ENV || "development" 21 | 22 | const dynamicRoutes = routesFile[environment] || {} 23 | const routes = Object.assign({}, staticRoutes, dynamicRoutes) 24 | 25 | return { 26 | routes, 27 | environment 28 | } 29 | } 30 | 31 | exports.createPages = ({ actions, reporter }, { routeFilePath }) => { 32 | const { routes, environment } = getDynamicRoutes(routeFilePath) 33 | reporter.info( 34 | `Will use '${environment}' env and creating this route keys: ${Object.keys( 35 | routes 36 | )}` 37 | ) 38 | 39 | const activity = reporter.activityTimer(`Dynamic routes created`) 40 | activity.start() 41 | 42 | const { createPage } = actions 43 | Object.keys(routes).map(routeKey => { 44 | const route = routes[routeKey] 45 | reporter.info(`Creating route: ${route.path}`) 46 | createPage({ 47 | path: route.path, 48 | component: path.resolve(route.component), 49 | context: route.context ? route.context : {}, 50 | }) 51 | }) 52 | activity.end() 53 | } 54 | 55 | exports.onCreateWebpackConfig = ({ actions, plugins }, { routeFilePath }) => { 56 | const { routes } = getDynamicRoutes(routeFilePath) 57 | 58 | const ROUTES = Object.keys(routes).reduce((acc, routeKey) => { 59 | acc[routeKey] = routes[routeKey] 60 | return acc 61 | }, {}) 62 | 63 | actions.setWebpackConfig({ 64 | plugins: [plugins.define({ ROUTES: JSON.stringify(ROUTES) })] 65 | }) 66 | } 67 | 68 | exports.onCreatePage = ({ page, actions, reporter }, { routeFilePath }) => { 69 | const { deletePage } = actions 70 | 71 | const { routes } = getDynamicRoutes(routeFilePath) 72 | 73 | const existingRouteOnPageFolder = Object.values(routes).some( 74 | ({ component }) => { 75 | const isSomeRouteThatWillBeRenamed = 76 | path.resolve(component) === page.component 77 | return isSomeRouteThatWillBeRenamed 78 | } 79 | ) 80 | 81 | if (existingRouteOnPageFolder) { 82 | deletePage(page) 83 | reporter.info(`Preventing creation of route: ${page.path}`) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // no-op -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gatsby-plugin-dynamic-routes", 3 | "version": "1.0.2", 4 | "description": "Creating dynamic routes based on your environment and/or renaming existing routes", 5 | "main": "index.js", 6 | "repository": "git@github.com:luanbitar/gatsby-plugin-dynamic-routes.git", 7 | "author": "Luan Bitar <7@lbitar.com>", 8 | "license": "MIT", 9 | "keywords": [ 10 | "gatsby", 11 | "gatsby-plugin", 12 | "plugin", 13 | "routes", 14 | "routing", 15 | "dynamic", 16 | "renaming", 17 | "pages", 18 | "env", 19 | "environment", 20 | "renaming", 21 | "themes", 22 | "organic" 23 | ], 24 | "peerDependencies": { 25 | "gatsby": ">2.0.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | dotenv@^8.2.0: 6 | version "8.2.0" 7 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" 8 | integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== 9 | --------------------------------------------------------------------------------