├── commitlint.config.js ├── example ├── static │ ├── favicon.ico │ └── README.md ├── components │ ├── README.md │ └── Logo.vue ├── .editorconfig ├── layouts │ ├── README.md │ └── default.vue ├── pages │ ├── README.md │ └── index.vue ├── assets │ └── README.md ├── plugins │ └── README.md ├── middleware │ └── README.md ├── store │ └── README.md ├── README.md ├── package.json ├── .gitignore └── nuxt.config.js ├── .npmignore ├── CODE_OF_CONDUCT.md ├── .github ├── ISSUE_TEMPLATE │ ├── support_request.md │ ├── feature_request.md │ └── bug_report.md ├── stale.yml ├── workflows │ ├── build.yml │ └── test.yml └── config.yml ├── ISSUE_TEMPLATE.md ├── renovate.json ├── .editorconfig ├── CONTRIBUTING.md ├── lib ├── redirects.js ├── headers.js ├── constants.js ├── utils.js └── index.js ├── .eslintrc.js ├── test ├── __snapshots__ │ ├── file-redirects.test.js.snap │ ├── headers.test.js.snap │ └── file-headers.test.js.snap ├── headers.test.js ├── file-redirects.test.js ├── file-headers.test.js └── redirects.test.js ├── LICENSE ├── docs ├── license.md ├── es │ ├── license.md │ ├── README.md │ ├── contributing.md │ ├── usage.md │ └── configuration.md ├── README.md ├── contributing.md ├── usage.md └── configuration.md ├── package.json ├── CHANGELOG.md ├── .gitignore └── README.md /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'] 3 | } 4 | -------------------------------------------------------------------------------- /example/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juliomrqz/nuxt-netlify/HEAD/example/static/favicon.ico -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | example 3 | test 4 | docs 5 | greenkeeper.json 6 | coverage 7 | .github 8 | yarn.lock 9 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | By participating in this project, you agree to abide by the 4 | [Code of Conduct][tb-coc]. 5 | 6 | [tb-coc]: https://www.contributor-covenant.org/version/2/0/code_of_conduct/ 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/support_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: ⛔️ Questions 3 | about: For questions, please go to https://spectrum.chat/bazzite/open-source 4 | --- 5 | 6 | 7 | -------------------------------------------------------------------------------- /example/components/README.md: -------------------------------------------------------------------------------- 1 | # COMPONENTS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | The components directory contains your Vue.js Components. 6 | 7 | _Nuxt.js doesn't supercharge these components._ 8 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@nuxtjs" 4 | ], 5 | "schedule": [ 6 | "after 10pm every weekday", 7 | "before 6am every weekday", 8 | "every weekend" 9 | ], 10 | "lockFileMaintenance": { 11 | "enabled": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /example/.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /example/layouts/README.md: -------------------------------------------------------------------------------- 1 | # LAYOUTS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your Application Layouts. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/views#layouts). 8 | -------------------------------------------------------------------------------- /example/pages/README.md: -------------------------------------------------------------------------------- 1 | # PAGES 2 | 3 | This directory contains your Application Views and Routes. 4 | The framework reads all the `*.vue` files inside this directory and creates the router of your application. 5 | 6 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing). 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guide 2 | 3 | :+1: First of all, thank you for taking the time to contribute! :+1: 4 | 5 | Please make sure to read the [Nuxt Netlify][link] before making a contribution. 6 | 7 | [link]: https://marquez.co/docs/nuxt-netlify/contributing?utm_source=github&utm_medium=contributing&utm_campaign=nuxt-netlify 8 | -------------------------------------------------------------------------------- /lib/redirects.js: -------------------------------------------------------------------------------- 1 | const { FILE_COMMENT } = require('./constants') 2 | const { createRedirectContent } = require('./utils') 3 | 4 | module.exports = (options) => { 5 | let content = FILE_COMMENT 6 | 7 | options.redirects.forEach(r => { 8 | content += createRedirectContent(r) 9 | }) 10 | 11 | return content 12 | } 13 | -------------------------------------------------------------------------------- /example/assets/README.md: -------------------------------------------------------------------------------- 1 | # ASSETS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your un-compiled assets such as LESS, SASS, or JavaScript. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#webpacked). 8 | -------------------------------------------------------------------------------- /example/plugins/README.md: -------------------------------------------------------------------------------- 1 | # PLUGINS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains Javascript plugins that you want to run before mounting the root Vue.js application. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/plugins). 8 | -------------------------------------------------------------------------------- /example/middleware/README.md: -------------------------------------------------------------------------------- 1 | # MIDDLEWARE 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your application middleware. 6 | Middleware let you define custom functions that can be run before rendering either a page or a group of pages. 7 | 8 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing#middleware). 9 | -------------------------------------------------------------------------------- /example/store/README.md: -------------------------------------------------------------------------------- 1 | # STORE 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your Vuex Store files. 6 | Vuex Store option is implemented in the Nuxt.js framework. 7 | 8 | Creating a file in this directory automatically activates the option in the framework. 9 | 10 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store). 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | > My mind-blowing Nuxt.js project 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | $ yarn install 10 | 11 | # serve with hot reload at localhost:3000 12 | $ yarn run dev 13 | 14 | # build for production and launch server 15 | $ yarn run build 16 | $ yarn start 17 | 18 | # generate static project 19 | $ yarn run generate 20 | ``` 21 | 22 | For detailed explanation on how things work, checkout [Nuxt.js docs](https://nuxtjs.org). 23 | -------------------------------------------------------------------------------- /example/static/README.md: -------------------------------------------------------------------------------- 1 | # STATIC 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your static files. 6 | Each file inside this directory is mapped to `/`. 7 | Thus you'd want to delete this README.md before deploying to production. 8 | 9 | Example: `/static/robots.txt` is mapped as `/robots.txt`. 10 | 11 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#static). 12 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@aceforth/nuxt-netlify-example", 3 | "version": "1.0.0", 4 | "description": "My mind-blowing Nuxt.js project", 5 | "author": "Julio Marquez ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "nuxt", 9 | "build": "nuxt build", 10 | "start": "nuxt start", 11 | "generate": "nuxt generate" 12 | }, 13 | "dependencies": { 14 | "cross-env": "7.0.3", 15 | "nuxt": "2.15.2" 16 | }, 17 | "devDependencies": { 18 | "nodemon": "2.0.7" 19 | }, 20 | "engines": { 21 | "node": ">=v10.24.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | sourceType: 'module' 5 | }, 6 | env: { 7 | browser: true, 8 | node: true, 9 | jest: true 10 | }, 11 | extends: 'standard', 12 | plugins: [ 13 | 'jest', 14 | 'vue' 15 | ], 16 | rules: { 17 | // Allow paren-less arrow functions 18 | 'arrow-parens': 0, 19 | // Allow async-await 20 | 'generator-star-spacing': 0, 21 | // Allow debugger during development 22 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 23 | // Do not allow console.logs etc... 24 | 'no-console': 0 25 | }, 26 | globals: { 27 | 'jest/globals': true, 28 | jasmine: true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 14 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: wontfix 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false 18 | -------------------------------------------------------------------------------- /test/__snapshots__/file-redirects.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`file _redirects can generate an empty file 1`] = ` 4 | "## Created with https://github.com/juliomrqz/nuxt-netlify 5 | " 6 | `; 7 | 8 | exports[`file _redirects can generate multiple redirects 1`] = ` 9 | "## Created with https://github.com/juliomrqz/nuxt-netlify 10 | /google https://www.google.com 301 11 | /my-redirect / 302 12 | http://blog.yoursite.com/* https://www.yoursite.com/blog/:splat 301! 13 | http://blog.yoursite.com/* https://www.yoursite.com/blog/:splat 302! 14 | /articles id=:id tag=:tag /posts/:tag/:id 301 15 | " 16 | `; 17 | 18 | exports[`file _redirects can generate one redirect 1`] = ` 19 | "## Created with https://github.com/juliomrqz/nuxt-netlify 20 | /google https://www.google.com 301 21 | " 22 | `; 23 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /lib/headers.js: -------------------------------------------------------------------------------- 1 | const { SECURITY_HEADERS, CACHING_HEADERS, FILE_COMMENT } = require('./constants') 2 | const { createHeadersContent, appendHeaders, isUrl } = require('./utils') 3 | 4 | module.exports = (options) => { 5 | const { transformHeaders, publicPath } = options 6 | let content = FILE_COMMENT 7 | 8 | if (options.mergeSecurityHeaders) { 9 | options.headers = appendHeaders(options.headers, '/*', SECURITY_HEADERS['/*']) 10 | } 11 | 12 | if (options.mergeCachingHeaders) { 13 | // public path 14 | if (!isUrl(publicPath)) { 15 | options.headers = appendHeaders(options.headers, 16 | `${publicPath}*`, 17 | CACHING_HEADERS['/_nuxt/*']) 18 | } 19 | 20 | // sw.js 21 | options.headers = appendHeaders(options.headers, '/sw.js', CACHING_HEADERS['/sw.js']) 22 | } 23 | 24 | // transform and generate headers content 25 | content += Object.keys(options.headers) 26 | .map(k => createHeadersContent(transformHeaders(options.headers[k], k), k)) 27 | .join('') 28 | 29 | return content 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Julio Marquez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push] 4 | 5 | jobs: 6 | generate-example: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | node: ["10", "12", "14"] 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v2 14 | with: 15 | ref: ${{ github.head_ref }} 16 | 17 | - name: Setup node ${{ matrix.node }} 18 | uses: actions/setup-node@v2 19 | with: 20 | node-version: ${{ matrix.node }} 21 | 22 | - name: Get yarn cache directory path 23 | id: yarn-cache-dir-path 24 | run: echo "::set-output name=dir::$(yarn cache dir)" 25 | 26 | - name: Cache node modules 27 | id: yarn-cache 28 | uses: actions/cache@v2 29 | with: 30 | path: | 31 | ${{ steps.yarn-cache-dir-path.outputs.dir }} 32 | node_modules 33 | */*/node_modules 34 | key: oracle-node-modules-${{ runner.os }}-node-${{ matrix.node }}-build-${{ hashFiles('**/yarn.lock') }} 35 | 36 | - name: Install node modules 37 | run: yarn install 38 | 39 | - name: Generate Example 40 | run: cd example && yarn && yarn generate 41 | -------------------------------------------------------------------------------- /.github/config.yml: -------------------------------------------------------------------------------- 1 | updateDocsWhiteList: 2 | - BUG 3 | - Chore 4 | - minor 5 | 6 | updateDocsComment: > 7 | Thanks for opening this pull request! The maintainers of this repository would appreciate it if you would update some of our documentation based on your changes. 8 | requestInfoReplyComment: > 9 | We would appreciate it if you could provide us with more info about this issue/pr! 10 | requestInfoLabelToAdd: request-more-info 11 | 12 | newPRWelcomeComment: > 13 | Thanks so much for opening your first pull request! Please check out our contributing guidelines. 14 | firstPRMergeComment: > 15 | Congrats on merging your first pull request here! :tada: 16 | newIssueWelcomeComment: > 17 | Thanks for opening this issue, a maintainer will get back to you shortly! Be sure to follow the issue template! 🤓 18 | sentimentBotToxicityThreshold: .7 19 | 20 | sentimentBotReplyComment: > 21 | Please be sure to review the code of conduct and be respectful of other users. cc/ @juliomrqz @patriciajumper 22 | lockThreads: 23 | toxicityThreshold: .7 24 | numComments: 2 25 | setTimeInHours: 72 26 | replyComment: > 27 | This thread is being locked due to exceeding the toxicity minimums. cc/ @juliomrqz @patriciajumper 28 | -------------------------------------------------------------------------------- /example/layouts/default.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 56 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [push] 4 | 5 | jobs: 6 | test-format-check: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | node: ["10", "12", "14"] 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v2 14 | with: 15 | ref: ${{ github.head_ref }} 16 | 17 | - name: Setup node ${{ matrix.node }} 18 | uses: actions/setup-node@v2 19 | with: 20 | node-version: ${{ matrix.node }} 21 | 22 | - name: Get yarn cache directory path 23 | id: yarn-cache-dir-path 24 | run: echo "::set-output name=dir::$(yarn cache dir)" 25 | 26 | - name: Cache node modules 27 | id: yarn-cache 28 | uses: actions/cache@v2 29 | with: 30 | path: | 31 | ${{ steps.yarn-cache-dir-path.outputs.dir }} 32 | node_modules 33 | */*/node_modules 34 | key: oracle-node-modules-${{ runner.os }}-node-${{ matrix.node }}-build-${{ hashFiles('**/yarn.lock') }} 35 | 36 | - name: Install node modules 37 | run: yarn install 38 | 39 | - name: Format check 40 | run: yarn run lint 41 | 42 | - name: Test check 43 | run: yarn run test 44 | -------------------------------------------------------------------------------- /lib/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Plugin values 3 | */ 4 | const DEFAULT_CONFIG = { 5 | // add more headers 6 | headers: {}, 7 | // turn off the default security headers 8 | mergeSecurityHeaders: true, 9 | // turn off the default caching headers 10 | mergeCachingHeaders: true, 11 | // optional transform for manipulating headers under each path (e.g.sorting), etc. 12 | transformHeaders: (headers, path) => headers, 13 | // add redirects 14 | redirects: [] 15 | } 16 | 17 | const DEFAULT_HEADER_VALUES = { 18 | from: null, 19 | to: null, 20 | status: 301, 21 | force: false, 22 | query: {}, 23 | conditions: {} 24 | } 25 | 26 | const SECURITY_HEADERS = { 27 | '/*': [ 28 | 'Referrer-Policy: origin', 29 | 'X-Content-Type-Options: nosniff', 30 | 'X-Frame-Options: DENY', 31 | 'X-XSS-Protection: 1; mode=block' 32 | ] 33 | } 34 | 35 | const CACHING_HEADERS = { 36 | '/_nuxt/*': ['Cache-Control: public, max-age=31536000, immutable'], 37 | '/sw.js': ['Cache-Control: no-cache'] 38 | } 39 | 40 | const FILE_COMMENT = '## Created with https://github.com/juliomrqz/nuxt-netlify\n' 41 | 42 | module.exports = { 43 | DEFAULT_CONFIG, 44 | DEFAULT_HEADER_VALUES, 45 | SECURITY_HEADERS, 46 | CACHING_HEADERS, 47 | FILE_COMMENT 48 | } 49 | -------------------------------------------------------------------------------- /docs/license.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "License" 3 | description: "License of Nuxt Optimized Images" 4 | createdAt: "2019-03-06T15:43:56Z" 5 | publishedAt: "2019-03-06T15:43:56Z" 6 | updatedAt: "2020-07-17T20:01:04Z" 7 | position: 5 8 | category: "Getting started" 9 | --- 10 | 11 | ``` 12 | MIT License 13 | 14 | Copyright (c) 2020 Julio Marquez 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining a copy 17 | of this software and associated documentation files (the "Software"), to deal 18 | in the Software without restriction, including without limitation the rights 19 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 | copies of the Software, and to permit persons to whom the Software is 21 | furnished to do so, subject to the following conditions: 22 | 23 | The above copyright notice and this permission notice shall be included in all 24 | copies or substantial portions of the Software. 25 | 26 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | SOFTWARE. 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/es/license.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Licencia" 3 | description: "Licencia para Nuxt Netlify" 4 | createdAt: "2019-03-06T15:43:56Z" 5 | publishedAt: "2019-03-06T15:43:56Z" 6 | updatedAt: "2020-07-17T20:01:04Z" 7 | position: 5 8 | category: "Primeros Pasos" 9 | --- 10 | 11 | 12 | 13 | Esta página sólo está disponible en inglés. 14 | 15 | 16 | 17 | ``` 18 | MIT License 19 | 20 | Copyright (c) 2020 Julio Marquez 21 | 22 | Permission is hereby granted, free of charge, to any person obtaining a copy 23 | of this software and associated documentation files (the "Software"), to deal 24 | in the Software without restriction, including without limitation the rights 25 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 26 | copies of the Software, and to permit persons to whom the Software is 27 | furnished to do so, subject to the following conditions: 28 | 29 | The above copyright notice and this permission notice shall be included in all 30 | copies or substantial portions of the Software. 31 | 32 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 33 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 34 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 35 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 36 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 37 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 38 | SOFTWARE. 39 | ``` 40 | -------------------------------------------------------------------------------- /example/pages/index.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 36 | 37 | 69 | -------------------------------------------------------------------------------- /test/__snapshots__/headers.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`headers can append headers 1`] = ` 4 | Object { 5 | "/*": Array [ 6 | "X-Frame-Options: DENY", 7 | "X-XSS-Protection: 1; mode=block", 8 | "X-Content-Type-Options: nosniff", 9 | "X-UA-Compatible: ie=edge", 10 | "Access-Control-Allow-Origin: *", 11 | "Referrer-Policy: origin", 12 | ], 13 | } 14 | `; 15 | 16 | exports[`headers can append headers 2`] = ` 17 | Object { 18 | "/*": Array [ 19 | "X-Frame-Options: DENY", 20 | "X-XSS-Protection: 1; mode=block", 21 | "X-Content-Type-Options: nosniff", 22 | "X-UA-Compatible: ie=edge", 23 | "Access-Control-Allow-Origin: *", 24 | "Referrer-Policy: origin", 25 | "X-Frame-Options: SAMEORIGIN", 26 | ], 27 | } 28 | `; 29 | 30 | exports[`headers can create header content 1`] = ` 31 | "/static/* 32 | Cache-Control: public, max-age=31536000, immutable 33 | 34 | " 35 | `; 36 | 37 | exports[`headers can create header content 2`] = ` 38 | "/templates/index.html 39 | X-Frame-Options: DENY 40 | X-XSS-Protection: 1; mode=block 41 | 42 | " 43 | `; 44 | 45 | exports[`headers can create header content 3`] = ` 46 | "/something/* 47 | Basic-Auth: someuser:somepassword anotheruser:anotherpassword 48 | 49 | " 50 | `; 51 | 52 | exports[`headers can create header content 4`] = ` 53 | "/* 54 | Link: ; rel=preload; as=style 55 | Link: ; rel=preload; as=script 56 | Link: ; rel=preload; as=image 57 | 58 | " 59 | `; 60 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Node template 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (https://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # TypeScript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | # parcel-bundler cache (https://parceljs.org/) 63 | .cache 64 | 65 | # next.js build output 66 | .next 67 | 68 | # nuxt.js build output 69 | .nuxt 70 | 71 | # Nuxt generate 72 | dist 73 | 74 | # vuepress build output 75 | .vuepress/dist 76 | 77 | # Serverless directories 78 | .serverless 79 | 80 | # IDE 81 | .idea 82 | 83 | # Service worker 84 | sw.* 85 | -------------------------------------------------------------------------------- /example/components/Logo.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 80 | -------------------------------------------------------------------------------- /test/headers.test.js: -------------------------------------------------------------------------------- 1 | const { appendHeaders, createHeadersContent } = require('../lib/utils') 2 | 3 | describe('headers', () => { 4 | it('can append headers', () => { 5 | const headers1 = { 6 | '/*': [ 7 | 'X-Frame-Options: DENY', 8 | 'X-XSS-Protection: 1; mode=block', 9 | 'X-Content-Type-Options: nosniff' 10 | ] 11 | } 12 | 13 | const headers2 = { 14 | '/*': [ 15 | 'X-UA-Compatible: ie=edge', 16 | 'Access-Control-Allow-Origin: *', 17 | 'Referrer-Policy: origin' 18 | ] 19 | } 20 | 21 | const headers3 = { 22 | '/*': [ 23 | 'X-Frame-Options: SAMEORIGIN' 24 | ] 25 | } 26 | 27 | expect(appendHeaders(headers1, '/*', headers2['/*'])).toMatchSnapshot() 28 | expect(appendHeaders(headers1, '/*', headers3['/*'])).toMatchSnapshot() 29 | }) 30 | 31 | it('can create header content', () => { 32 | const headers1 = [ 33 | 'Cache-Control: public, max-age=31536000, immutable' 34 | ] 35 | 36 | const headers2 = [ 37 | 'X-Frame-Options: DENY', 38 | 'X-XSS-Protection: 1; mode=block' 39 | ] 40 | 41 | const headers3 = [ 42 | 'Basic-Auth: someuser:somepassword anotheruser:anotherpassword' 43 | ] 44 | 45 | const headers4 = [ 46 | 'Link: ; rel=preload; as=style', 47 | 'Link: ; rel=preload; as=script', 48 | 'Link: ; rel=preload; as=image' 49 | ] 50 | 51 | expect(appendHeaders(createHeadersContent(headers1, '/static/*'))).toMatchSnapshot() 52 | expect(appendHeaders(createHeadersContent(headers2, '/templates/index.html'))).toMatchSnapshot() 53 | expect(appendHeaders(createHeadersContent(headers3, '/something/*'))).toMatchSnapshot() 54 | expect(appendHeaders(createHeadersContent(headers4, '/*'))).toMatchSnapshot() 55 | }) 56 | }) 57 | -------------------------------------------------------------------------------- /test/file-redirects.test.js: -------------------------------------------------------------------------------- 1 | const { Map } = require('immutable') 2 | 3 | const { DEFAULT_CONFIG } = require('../lib/constants') 4 | const generateRedirects = require('../lib/redirects') 5 | 6 | const defaultOptions = Map(Object.assign({}, DEFAULT_CONFIG, { publicPath: '/_nuxt/' })) 7 | 8 | describe('file _redirects', () => { 9 | it('can generate an empty file', () => { 10 | const options = defaultOptions.toJS() 11 | const content = generateRedirects(options) 12 | expect(content).toMatchSnapshot() 13 | }) 14 | 15 | it('can generate one redirect', () => { 16 | const redirects = [ 17 | { 18 | from: '/google', 19 | to: 'https://www.google.com' 20 | } 21 | ] 22 | const options = defaultOptions.set('redirects', redirects).toJS() 23 | const content = generateRedirects(options) 24 | expect(content).toMatchSnapshot() 25 | }) 26 | 27 | it('can generate multiple redirects', () => { 28 | const redirects = [ 29 | { 30 | from: '/google', 31 | to: 'https://www.google.com' 32 | }, 33 | { 34 | from: '/my-redirect', 35 | to: '/', 36 | status: 302 37 | }, 38 | { 39 | from: 'http://blog.yoursite.com/*', 40 | to: 'https://www.yoursite.com/blog/:splat', 41 | force: true 42 | }, 43 | { 44 | from: 'http://blog.yoursite.com/*', 45 | to: 'https://www.yoursite.com/blog/:splat', 46 | status: 302, 47 | force: true 48 | }, 49 | { 50 | from: '/articles', 51 | to: '/posts/:tag/:id', 52 | query: { 53 | id: ':id', 54 | tag: ':tag' 55 | } 56 | } 57 | ] 58 | const options = defaultOptions.set('redirects', redirects).toJS() 59 | const content = generateRedirects(options) 60 | expect(content).toMatchSnapshot() 61 | }) 62 | }) 63 | -------------------------------------------------------------------------------- /example/nuxt.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const pkg = require('./package') 3 | 4 | module.exports = { 5 | mode: 'universal', 6 | 7 | /* 8 | ** Headers of the page 9 | */ 10 | head: { 11 | title: pkg.name, 12 | meta: [ 13 | { charset: 'utf-8' }, 14 | { name: 'viewport', content: 'width=device-width, initial-scale=1' }, 15 | { hid: 'description', name: 'description', content: pkg.description } 16 | ], 17 | link: [ 18 | { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' } 19 | ] 20 | }, 21 | 22 | /* 23 | ** Customize the progress-bar color 24 | */ 25 | loading: { color: '#fff' }, 26 | 27 | /* 28 | ** Global CSS 29 | */ 30 | css: [ 31 | ], 32 | 33 | /* 34 | ** Plugins to load before mounting the App 35 | */ 36 | plugins: [ 37 | ], 38 | 39 | /* 40 | ** Nuxt.js modules 41 | */ 42 | modules: [ 43 | path.resolve('../lib/index.js') 44 | ], 45 | 46 | /* 47 | ** Build configuration 48 | */ 49 | build: { 50 | /* 51 | ** You can extend webpack config here 52 | */ 53 | extend(config, ctx) { 54 | 55 | } 56 | }, 57 | netlify: { 58 | redirects: [ 59 | { 60 | from: 'https://example.com/temp/*', 61 | to: 'https://example.com/:splat*' 62 | }, 63 | { 64 | from: '/en/*', 65 | to: '/en/404.html', 66 | status: 404 67 | }, 68 | { 69 | from: '/articles', 70 | to: '/posts/:tag/:id', 71 | status: 301, 72 | force: true, 73 | query: { 74 | id: ':id', 75 | tag: ':tag', 76 | } 77 | }, 78 | { 79 | from: '/china/*', 80 | to: '/china/zh-cn/:splat', 81 | status: 302, 82 | conditions: { 83 | Language: 'zh', 84 | Country: 'cn,hk,tw', 85 | } 86 | } 87 | ] 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Overview" 3 | description: "Dynamically generate _headers and _redirects files for Netlify in your Nuxt.js projects" 4 | createdAt: "2019-03-06T15:43:56Z" 5 | publishedAt: "2019-03-06T15:43:56Z" 6 | updatedAt: "2020-07-17T20:01:04Z" 7 | position: 1 8 | category: "Getting started" 9 | --- 10 | 11 | # Nuxt Netlify 12 | 13 | Dynamically generate `_headers` and `_redirects` files for Netlify in your Nuxt.js projects. 14 | 15 | This module supports the creation of [**redirects**][netlify-redirects] and [**header**][netlify-headers-and-basic-auth] rules for your Netlify site: you can easily configure custom headers, basic auth, redirect instructions and rewrite rules from your _nuxt config file_. 16 | 17 | 18 | ## Installation 19 | 20 | 21 | 22 | `node >= 10` and `nuxt >= 2` are required. 23 | 24 | 25 | 26 | 27 | 28 | 29 | ```bash 30 | yarn add --dev @aceforth/nuxt-netlify 31 | ``` 32 | 33 | 34 | 35 | 36 | ```bash 37 | npm install --save-dev @aceforth/nuxt-netlify 38 | ``` 39 | 40 | 41 | 42 | 43 | 44 | Add `@aceforth/nuxt-netlify` to the `buildModules` section of `nuxt.config.js`: 45 | 46 | 47 | 48 | If you are using Nuxt `< 2.9.0`, use `modules` instead. 49 | 50 | 51 | 52 | ```js 53 | { 54 | buildModules: [ 55 | '@aceforth/nuxt-netlify', 56 | ], 57 | 58 | netlify: { 59 | // configuration 60 | } 61 | } 62 | ``` 63 | 64 | or 65 | 66 | 67 | ```js 68 | { 69 | buildModules: [ 70 | [ 71 | '@aceforth/nuxt-netlify', { 72 | // configuration 73 | } 74 | ] 75 | ] 76 | } 77 | ``` 78 | 79 | [netlify-headers-and-basic-auth]: https://www.netlify.com/docs/headers-and-basic-auth/ 80 | [netlify-redirects]: https://www.netlify.com/docs/redirects/ 81 | -------------------------------------------------------------------------------- /docs/es/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Primeros Pasos" 3 | description: "Genera dinámicamente archivos _headers y _redirects para Netlify en tus proyectos de Nuxt.js" 4 | createdAt: "2019-03-06T15:43:56Z" 5 | publishedAt: "2019-03-06T15:43:56Z" 6 | updatedAt: "2020-07-17T20:01:04Z" 7 | position: 1 8 | category: "Primeros Pasos" 9 | --- 10 | 11 | # Nuxt Netlify 12 | 13 | Genera dinámicamente archivos `_headers` y `_redirects` para Netlify en tus proyectos de Nuxt.js. 14 | 15 | Este módulo soporta la creación de reglas de [**redirecciones**][netlify-redirects] y [**cabecera**][netlify-headers-and-basic-auth] para tu sitio Netlify: puedes configurar fácilmente cabeceras personalizadas, autenticación básica, instrucciones de redirección y reglas de reescritura desde su archivo de configuración nuxt. 16 | 17 | ## Instalación 18 | 19 | 20 | 21 | `node >= 10` y `nuxt >= 2` son requeridos. 22 | 23 | 24 | 25 | 26 | 27 | 28 | ```bash 29 | yarn add --dev @aceforth/nuxt-netlify 30 | ``` 31 | 32 | 33 | 34 | 35 | ```bash 36 | npm install --save-dev @aceforth/nuxt-netlify 37 | ``` 38 | 39 | 40 | 41 | 42 | Añade `@aceforth/nuxt-netlify` a la sección `buildModules` de `nuxt.config.js`: 43 | 44 | 45 | 46 | Si estás usando Nuxt `< 2.9.0`, usa `modules` en su lugar. 47 | 48 | 49 | 50 | ```js 51 | { 52 | buildModules: [ 53 | '@aceforth/nuxt-netlify', 54 | ], 55 | 56 | netlify: { 57 | // configuración 58 | } 59 | } 60 | ``` 61 | 62 | o 63 | 64 | ```js 65 | { 66 | buildModules: [ 67 | [ 68 | '@aceforth/nuxt-netlify', { 69 | // configuración 70 | } 71 | ] 72 | ] 73 | } 74 | ``` 75 | 76 | [netlify-headers-and-basic-auth]: https://www.netlify.com/docs/headers-and-basic-auth/ 77 | [netlify-redirects]: https://www.netlify.com/docs/redirects/ 78 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@aceforth/nuxt-netlify", 3 | "version": "1.1.0", 4 | "description": "Dynamically generate _headers and _redirects files for Netlify in your Nuxt.js projects.", 5 | "main": "lib/index.js", 6 | "directories": { 7 | "example": "example" 8 | }, 9 | "scripts": { 10 | "test": "yarn lint && jest", 11 | "lint": "eslint --ext .js lib test", 12 | "changelog": "conventional-changelog -p angular -r 2 -i CHANGELOG.md -s" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/juliomrqz/nuxt-netlify.git" 17 | }, 18 | "author": "Julio Marquez ", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/juliomrqz/nuxt-netlify/issues" 22 | }, 23 | "homepage": "https://marquez.co/docs/nuxt-netlify/?utm_source=npm&utm_medium=readme&utm_campaign=nuxt-netlify", 24 | "dependencies": { 25 | "consola": "^2.15.3", 26 | "fs-extra": "^9.1.0", 27 | "lodash.template": "^4.5.0" 28 | }, 29 | "devDependencies": { 30 | "@commitlint/cli": "11.0.0", 31 | "@commitlint/config-conventional": "11.0.0", 32 | "conventional-changelog-cli": "2.1.1", 33 | "eslint": "7.21.0", 34 | "eslint-config-dev": "2.0.0", 35 | "eslint-config-standard": "16.0.2", 36 | "eslint-plugin-import": "2.22.1", 37 | "eslint-plugin-jest": "24.1.5", 38 | "eslint-plugin-node": "11.1.0", 39 | "eslint-plugin-promise": "4.3.1", 40 | "eslint-plugin-standard": "5.0.0", 41 | "eslint-plugin-vue": "7.6.0", 42 | "husky": "4.3.8", 43 | "immutable": "4.0.0-rc.12", 44 | "jest": "26.6.3", 45 | "sharp": "0.27.2", 46 | "upath": "2.0.1" 47 | }, 48 | "husky": { 49 | "hooks": { 50 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS", 51 | "precommit": "lint-staged" 52 | } 53 | }, 54 | "jest": { 55 | "testEnvironment": "node", 56 | "coverageDirectory": "./coverage/", 57 | "collectCoverage": true 58 | }, 59 | "engines": { 60 | "node": ">=v10.24.0" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | const { DEFAULT_HEADER_VALUES } = require('./constants') 3 | 4 | const isEmptyObject = input => Object.keys(input).length === 0 5 | 6 | const createFile = async (filePath, content) => { 7 | if (await fs.exists(filePath)) { 8 | await fs.appendFile(filePath, `\n\n${content}`) 9 | } else { 10 | await fs.ensureFile(filePath) 11 | await fs.writeFile(filePath, content) 12 | } 13 | } 14 | 15 | const createHeadersContent = (headers, path) => { 16 | let content = `${path}\n` 17 | 18 | headers.forEach(h => { 19 | content += ` ${h}\n` 20 | }) 21 | 22 | return `${content}\n` 23 | } 24 | 25 | const appendHeaders = (headersList, key, headers) => { 26 | if (headersList[key]) { 27 | headersList[key].push(...headers) 28 | } else { 29 | headersList[key] = headers 30 | } 31 | 32 | headersList[key] = Array.from(new Set(headersList[key])) 33 | 34 | return headersList 35 | } 36 | 37 | const isUrl = (url) => { 38 | return ['http', '//'].some(str => url.startsWith(str)) 39 | } 40 | 41 | const createRedirectContent = r => { 42 | const redirect = Object.assign({}, DEFAULT_HEADER_VALUES, r) 43 | const divider = ' ' 44 | 45 | // from 46 | let content = `${redirect.from}${divider}` 47 | 48 | // query params 49 | if (redirect.query && !isEmptyObject(redirect.query)) { 50 | content += Object.keys(redirect.query) 51 | .map(k => `${k}=${redirect.query[k]}`) 52 | .join(' ') 53 | content += divider 54 | } 55 | 56 | // to 57 | if (redirect.to) { 58 | content += `${redirect.to}${divider}` 59 | } 60 | 61 | // status 62 | content += `${redirect.status}${redirect.force ? '!' : ''}` 63 | 64 | // conditions 65 | if (redirect.conditions && !isEmptyObject(redirect.conditions)) { 66 | content += divider 67 | content += Object.keys(redirect.conditions) 68 | .map(k => `${k}=${redirect.conditions[k]}`) 69 | .join(' ') 70 | } 71 | 72 | return `${content}\n` 73 | } 74 | 75 | module.exports = { 76 | createFile, 77 | createHeadersContent, 78 | appendHeaders, 79 | isUrl, 80 | createRedirectContent 81 | } 82 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020, Julio Marquez 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | const path = require('path') 9 | const consola = require('consola') 10 | 11 | const { DEFAULT_CONFIG } = require('./constants') 12 | const generateHeaders = require('./headers') 13 | const generateRedirects = require('./redirects') 14 | const { createFile } = require('./utils') 15 | 16 | const logger = consola.withScope('nuxt:@aceforth/nuxt-netlify') 17 | 18 | function nuxtOptimizedImages (moduleOptions) { 19 | const { rootDir, generate, build } = this.options 20 | const options = Object.assign({}, DEFAULT_CONFIG, this.options.netlify, moduleOptions) 21 | options.publicPath = build.publicPath 22 | 23 | // validate options 24 | if (typeof options.headers !== 'object') { 25 | logger.fatal('The `headers` property must be an object') 26 | } else if (!Array.isArray(options.redirects)) { 27 | logger.fatal('The `redirects` property must be an array') 28 | } else if (typeof options.transformHeaders !== 'function') { 29 | logger.fatal('The `transformHeaders` property must be a function') 30 | } 31 | 32 | // Generate headers and redirects in dist 33 | this.nuxt.hook('generate:done', async () => { 34 | // generate headers 35 | try { 36 | const headersPath = path.resolve(rootDir, generate.dir, '_headers') 37 | const headersContent = generateHeaders(options) 38 | await createFile(headersPath, headersContent) 39 | logger.success('Generated /_headers') 40 | } catch (error) { 41 | logger.error(error) 42 | } 43 | 44 | // generate redirects 45 | try { 46 | const redirectsPath = path.resolve(rootDir, generate.dir, '_redirects') 47 | const redirectsContent = generateRedirects(options) 48 | await createFile(redirectsPath, redirectsContent) 49 | logger.success('Generated /_redirects') 50 | } catch (error) { 51 | logger.error(error) 52 | } 53 | }) 54 | } 55 | 56 | module.exports = nuxtOptimizedImages 57 | module.exports.meta = require('../package.json') 58 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [1.1.0](https://github.com/juliomrqz/nuxt-netlify/compare/v1.0.0...v1.1.0) (2020-07-19) 2 | 3 | 4 | * dependencies updates 5 | 6 | ### Refactor 7 | 8 | * update layout of docs articles ([08ea91a](https://github.com/juliomrqz/nuxt-optimized-images/commit/08ea91a4472654d764d83f01d52d7a16ff2ac82b)) 9 | * update project owner ([18216ad](https://github.com/juliomrqz/nuxt-optimized-images/commit/18216ad0cb2592770db6f4cb08f0d41815e8d154)) 10 | 11 | 12 | # [1.0.0](https://github.com/juliomrqz/nuxt-netlify/compare/v0.2.0...v1.0.0) (2020-04-12) 13 | 14 | 15 | * refactor!: update parent company ([3a93e72](https://github.com/juliomrqz/nuxt-netlify/commit/3a93e72a4df48b266e1fe23f3762485fa7d1331b)) 16 | 17 | 18 | ### BREAKING CHANGES 19 | 20 | * **The package has been renamed from `@bazzite/nuxt-netlify` to `@aceforth/nuxt-netlify`.** 21 | 22 | To upgrade 23 | 24 | 1. `npm install --save-dev @aceforth/nuxt-netlify` 25 | 26 | or `yarn add --dev @aceforth/nuxt-netlify` 27 | 28 | 2. `npm uninstall @bazzite/nuxt-netlify` 29 | 30 | or `yarn remove @bazzite/nuxt-netlify` 31 | 32 | 3. replace: 33 | 34 | ```js 35 | { 36 | buildModules: [ 37 | '@bazzite/nuxt-netlify', 38 | ], 39 | } 40 | ``` 41 | 42 | with 43 | 44 | ```js 45 | { 46 | buildModules: [ 47 | '@aceforth/nuxt-netlify', 48 | ], 49 | } 50 | ``` 51 | 52 | 53 | That’s it, there are no functional changes compared to `@bazzite/nuxt-netlify@0.2.0`. 54 | 55 | 56 | 57 | # [0.2.0](https://github.com/juliomrqz/nuxt-netlify/compare/v0.1.1...v0.2.0) (2020-03-31) 58 | 59 | 60 | ### Bug Fixes 61 | 62 | * **docs:** update Installation instructions ([d0fbe6f](https://github.com/juliomrqz/nuxt-netlify/commit/d0fbe6fb1b41ac861ca43f4930b62b7c1c6d9f24)) 63 | 64 | 65 | * refactor!: drop support for Node.js 8 ([34075b7](https://github.com/juliomrqz/nuxt-netlify/commit/34075b7b54dd0a71b5756ce7ecc9a9a9e0c5cd1d)) 66 | 67 | 68 | ### Features 69 | 70 | * add support for node v12 on travis tests ([21b43c0](https://github.com/juliomrqz/nuxt-netlify/commit/21b43c03e3ceb78a6667374841bb23a6c6620c2d)) 71 | 72 | 73 | ### BREAKING CHANGES 74 | 75 | * minimum required Node.js version is 10.x 76 | 77 | 78 | 79 | ## [0.1.1](https://github.com/juliomrqz/nuxt-netlify/compare/v0.1.0...v0.1.1) (2019-06-12) 80 | 81 | * **docs:** extend the description of the project ([21f5e09](https://github.com/juliomrqz/nuxt-netlify/commit/21f5e09)) 82 | 83 | 84 | # 0.1.0 (2019-03-14) 85 | 86 | First stable release 87 | -------------------------------------------------------------------------------- /test/file-headers.test.js: -------------------------------------------------------------------------------- 1 | const { Map } = require('immutable') 2 | 3 | const { DEFAULT_CONFIG } = require('../lib/constants') 4 | const generateHeaders = require('../lib/headers') 5 | 6 | const defaultOptions = Map(Object.assign({}, DEFAULT_CONFIG, { publicPath: '/_nuxt/' })) 7 | const extraHeaders = { 8 | '/templates/index.html': [ 9 | 'X-Frame-Options: DENY', 10 | 'X-XSS-Protection: 1; mode=block' 11 | ], 12 | '/templates/index2.html': [ 13 | 'X-Frame-Options: SAMEORIGIN' 14 | ], 15 | '/something/*': [ 16 | 'Basic-Auth: someuser:somepassword anotheruser:anotherpassword' 17 | ] 18 | } 19 | 20 | describe('file _headers', () => { 21 | it('can generate default file', () => { 22 | const options = defaultOptions.toJS() 23 | const content = generateHeaders(options) 24 | expect(content).toMatchSnapshot() 25 | }) 26 | 27 | it('can generate default file with a public path as url', () => { 28 | const options = defaultOptions.set('publicPath', 'https://cdn.example.com').toJS() 29 | const content = generateHeaders(options) 30 | expect(content).toMatchSnapshot() 31 | }) 32 | 33 | it('can disable security headers', () => { 34 | const options = defaultOptions.set('mergeSecurityHeaders', false).toJS() 35 | const content = generateHeaders(options) 36 | 37 | expect(content).toMatchSnapshot() 38 | }) 39 | 40 | it('can disable caching headers', () => { 41 | const options = defaultOptions.set('mergeCachingHeaders', false).toJS() 42 | const content = generateHeaders(options) 43 | 44 | expect(content).toMatchSnapshot() 45 | }) 46 | 47 | it('can disable security & caching headers', () => { 48 | const options = defaultOptions 49 | .set('mergeSecurityHeaders', false) 50 | .set('mergeCachingHeaders', false) 51 | .toJS() 52 | const content = generateHeaders(options) 53 | 54 | expect(content).toMatchSnapshot() 55 | }) 56 | 57 | it('can sort headers alphabetically', () => { 58 | const options = defaultOptions 59 | .set('transformHeaders', (headers, path) => headers.reverse()) 60 | .toJS() 61 | const content = generateHeaders(options) 62 | 63 | expect(content).toMatchSnapshot() 64 | }) 65 | 66 | it('can add extra headers', () => { 67 | const options = defaultOptions 68 | .set('headers', extraHeaders) 69 | .toJS() 70 | const content = generateHeaders(options) 71 | 72 | expect(content).toMatchSnapshot() 73 | }) 74 | 75 | it('can add extra headers with no defaults', () => { 76 | const options = defaultOptions 77 | .set('mergeSecurityHeaders', false) 78 | .set('mergeCachingHeaders', false) 79 | .set('headers', extraHeaders) 80 | .toJS() 81 | const content = generateHeaders(options) 82 | 83 | expect(content).toMatchSnapshot() 84 | }) 85 | }) 86 | -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Contributing" 3 | description: "Steps for easier development and debugging purposes of Nuxt Netlify." 4 | createdAt: "2019-03-06T15:43:56Z" 5 | publishedAt: "2019-03-06T15:43:56Z" 6 | updatedAt: "2020-07-17T20:01:04Z" 7 | position: 4 8 | category: "Getting started" 9 | --- 10 | 11 | Please make sure to read this **Contributing Guide** before making a contribution. 12 | 13 | ## Development setup 14 | 15 | 1. Fork and clone the repo `https://github.com/juliomrqz/nuxt-netlify` 16 | 2. Run `npm install` to install dependencies 17 | 3. Run `npm test` to run validation 18 | 4. Create a branch for your PR with `git checkout -b pr/your-branch-name` 19 | 20 | ### Commonly used NPM scripts 21 | 22 | **Watch and serve the examples with hot reload** 23 | 24 | ```shell 25 | npm run start 26 | ``` 27 | 28 | **Lint source codes** 29 | ```shell 30 | npm run lint 31 | ``` 32 | 33 | **Run unit tests** 34 | ```shell 35 | npm run test 36 | ``` 37 | 38 | ## Issue Reporting Guidelines 39 | 40 | - The [issue list][issues-link] of this project is **exclusively** for bug reports and feature requests. Non-conforming issues will be closed immediately. 41 | 42 | - Try to search for your issue, it may have already been answered or even fixed in the development branch. 43 | 44 | - Check if the issue is reproducible with the latest stable version of Vue. If you are using a pre-release, please indicate the specific version you are using. 45 | 46 | - It is **required** that you clearly describe the steps necessary to reproduce the issue you are running into. Issues with no clear repro steps will not be triaged. If an issue labeled "request-more-info" receives no further input from the issue author for more than 5 days, it will be closed. 47 | 48 | - For bugs that involves build setups, you can create a reproduction repository with steps in the README. 49 | 50 | - If your issue is resolved but still open, don't hesitate to close it. In case you found a solution by yourself, it could be helpful to explain how you fixed it. 51 | 52 | ## Pull Request Guidelines 53 | 54 | - The `master` branch is basically just a snapshot of the latest stable release. All development should be done in dedicated branches. **Do not submit PRs against the `master` branch.** 55 | 56 | - Checkout a topic branch from the relevant branch, e.g. `develop`, and merge back against that branch. 57 | 58 | - Work in the `lib` an `examples` folders and **DO NOT** checkin `dist` in the commits. 59 | 60 | - It's OK to have multiple small commits as you work on the PR - we will let GitHub automatically squash it before merging. 61 | 62 | - Make sure `npm run lint` and `npm run test` passes. 63 | 64 | - If adding new feature: 65 | - Add accompanying test case. 66 | - Provide convincing reason to add this feature. Ideally you should open a suggestion issue first and have it greenlighted before working on it. 67 | 68 | - If fixing a bug: 69 | - Provide detailed description of the bug in the PR. Live demo preferred. 70 | 71 | 72 | [issues-link]: https://github.com/juliomrqz/nuxt-netlify/issues 73 | -------------------------------------------------------------------------------- /test/__snapshots__/file-headers.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`file _headers can add extra headers 1`] = ` 4 | "## Created with https://github.com/juliomrqz/nuxt-netlify 5 | /templates/index.html 6 | X-Frame-Options: DENY 7 | X-XSS-Protection: 1; mode=block 8 | 9 | /templates/index2.html 10 | X-Frame-Options: SAMEORIGIN 11 | 12 | /something/* 13 | Basic-Auth: someuser:somepassword anotheruser:anotherpassword 14 | 15 | /* 16 | Referrer-Policy: origin 17 | X-Content-Type-Options: nosniff 18 | X-Frame-Options: DENY 19 | X-XSS-Protection: 1; mode=block 20 | 21 | /_nuxt/* 22 | Cache-Control: public, max-age=31536000, immutable 23 | 24 | /sw.js 25 | Cache-Control: no-cache 26 | 27 | " 28 | `; 29 | 30 | exports[`file _headers can add extra headers with no defaults 1`] = ` 31 | "## Created with https://github.com/juliomrqz/nuxt-netlify 32 | /templates/index.html 33 | X-Frame-Options: DENY 34 | X-XSS-Protection: 1; mode=block 35 | 36 | /templates/index2.html 37 | X-Frame-Options: SAMEORIGIN 38 | 39 | /something/* 40 | Basic-Auth: someuser:somepassword anotheruser:anotherpassword 41 | 42 | " 43 | `; 44 | 45 | exports[`file _headers can disable caching headers 1`] = ` 46 | "## Created with https://github.com/juliomrqz/nuxt-netlify 47 | /* 48 | Referrer-Policy: origin 49 | X-Content-Type-Options: nosniff 50 | X-Frame-Options: DENY 51 | X-XSS-Protection: 1; mode=block 52 | 53 | " 54 | `; 55 | 56 | exports[`file _headers can disable security & caching headers 1`] = ` 57 | "## Created with https://github.com/juliomrqz/nuxt-netlify 58 | " 59 | `; 60 | 61 | exports[`file _headers can disable security headers 1`] = ` 62 | "## Created with https://github.com/juliomrqz/nuxt-netlify 63 | /_nuxt/* 64 | Cache-Control: public, max-age=31536000, immutable 65 | 66 | /sw.js 67 | Cache-Control: no-cache 68 | 69 | " 70 | `; 71 | 72 | exports[`file _headers can generate default file 1`] = ` 73 | "## Created with https://github.com/juliomrqz/nuxt-netlify 74 | /* 75 | Referrer-Policy: origin 76 | X-Content-Type-Options: nosniff 77 | X-Frame-Options: DENY 78 | X-XSS-Protection: 1; mode=block 79 | 80 | /_nuxt/* 81 | Cache-Control: public, max-age=31536000, immutable 82 | 83 | /sw.js 84 | Cache-Control: no-cache 85 | 86 | " 87 | `; 88 | 89 | exports[`file _headers can generate default file with a public path as url 1`] = ` 90 | "## Created with https://github.com/juliomrqz/nuxt-netlify 91 | /* 92 | Referrer-Policy: origin 93 | X-Content-Type-Options: nosniff 94 | X-Frame-Options: DENY 95 | X-XSS-Protection: 1; mode=block 96 | 97 | /sw.js 98 | Cache-Control: no-cache 99 | 100 | " 101 | `; 102 | 103 | exports[`file _headers can sort headers alphabetically 1`] = ` 104 | "## Created with https://github.com/juliomrqz/nuxt-netlify 105 | /* 106 | X-XSS-Protection: 1; mode=block 107 | X-Frame-Options: DENY 108 | X-Content-Type-Options: nosniff 109 | Referrer-Policy: origin 110 | 111 | /_nuxt/* 112 | Cache-Control: public, max-age=31536000, immutable 113 | 114 | /sw.js 115 | Cache-Control: no-cache 116 | 117 | " 118 | `; 119 | -------------------------------------------------------------------------------- /docs/es/contributing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Contribución" 3 | description: "Pasos para facilitar el desarrollo y la depuración de Nuxt Netlify." 4 | createdAt: "2019-03-06T15:43:56Z" 5 | publishedAt: "2019-03-06T15:43:56Z" 6 | updatedAt: "2020-07-17T20:01:04Z" 7 | position: 4 8 | category: "Primeros Pasos" 9 | --- 10 | 11 | Asegúrese de leer esta **Guía de contribución** antes de hacer una contribución. 12 | 13 | ## Configuración de desarrollo 14 | 15 | 1. Haz un Fork y clona el repositorio `https://github.com/juliomrqz/nuxt-netlify` 16 | 2. Ejecuta `npm install` para instalar dependencias 17 | 3. Ejecuta `npm test` para ejecutar la validación 18 | 4. Crea una rama para tu PR con `git checkout -b pr/your-branch-name` 19 | 20 | ### Scripts de NPM comúnmente utilizados 21 | 22 | **Observa y sirve los ejemplos con recarga instántanea** 23 | 24 | ```shell 25 | npm run start 26 | ``` 27 | 28 | **Verifica el formato del código** 29 | ```shell 30 | npm run lint 31 | ``` 32 | 33 | **Ejecuta las pruebas unitarias** 34 | ```shell 35 | npm run test 36 | ``` 37 | 38 | ## Guía para el Reporte de Problemas (Issues) 39 | 40 | - La [lista de problemas (issues)][issues-link] de este proyecto es **exclusivamente** para informes de errores y solicitudes de funciones. Los problemas no conformes se cerrarán de inmediato. 41 | 42 | - Intenta buscar tu problema, puede haber sido respondido o incluso corregido en la rama de desarrollo. 43 | 44 | - Comprueba si el problema es reproducible con la última versión estable de Vue. Si estás utilizando una versión preliminar, indica la versión específica que estás utilizando. 45 | 46 | - Es **obligatorio** que describas claramente los pasos necesarios para reproducir el problema que se está ejecutando. Los problemas que no tengan pasos de reprografía claros no serán evaluados. Si un problema etiquetado como "request-more-info" no recibe más información del autor del problema durante más de 5 días, se cerrará. 47 | 48 | - Para los errores que involucran configuraciones de compilación, puede crear un repositorio de reproducción con pasos en el archivo README. 49 | 50 | - Si tu problema está resuelto pero aún abierto, no dudes en cerrarlo. En caso de que encuentres una solución tu mismo, podría ser útil explicar cómo lo solucionaste. 51 | 52 | ## Guía para los "Pull Request" 53 | 54 | - La rama `master` básicamente representa el estado de la última versión estable. Todo el desarrollo se debe hacer en ramas dedicadas. **No envíes PRs a la rama `master`.** 55 | 56 | - Verifica un tópico de la rama relevante, p.ej. `develop`, y haz un merge hacia esa rama. 57 | 58 | - Trabaja en las carpetas `lib` y `examples` y **NO** registres la carpeta `dist` en los commits. 59 | 60 | - Está bien tener múltiples commits pequeños mientras trabajas en el PR. Dejaremos que GitHub haga un squash automáticamente antes de un *merge*. 61 | 62 | - Asegúrarte que pasen `npm run lint` y `npm run test`. 63 | 64 | - Si agregas una nueva característica: 65 | - Agrega las pruebas que la acompaña. 66 | - Proporciona una razón convincente para agregar esta característica. Lo ideal sería que primero abrieras un tema de sugerencia y se validara antes de trabajar en él. 67 | 68 | - Si corriges un error: 69 | - Proporciona una descripción detallada del error en el PR. Demo en vivo preferido. 70 | 71 | 72 | [issues-link]: https://github.com/juliomrqz/nuxt-netlify/issues 73 | -------------------------------------------------------------------------------- /docs/usage.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Usage" 3 | description: "The default configuration will generate an empty `_redirects` file and a `_headers` file with some caching and security headers" 4 | createdAt: "2019-03-06T15:43:56Z" 5 | publishedAt: "2019-03-06T15:43:56Z" 6 | updatedAt: "2020-07-17T20:01:04Z" 7 | position: 2 8 | category: "Getting started" 9 | --- 10 | 11 | The default configuration will generate an empty `_redirects` file and a `_headers` file with some caching and security headers: 12 | 13 | ```text 14 | # _headers 15 | 16 | /* 17 | Referrer-Policy: origin 18 | X-Content-Type-Options: nosniff 19 | X-Frame-Options: DENY 20 | X-XSS-Protection: 1; mode=block 21 | 22 | /_nuxt/* 23 | Cache-Control: public, max-age=31536000, immutable 24 | 25 | /sw.js 26 | Cache-Control: no-cache 27 | ``` 28 | 29 | 30 | 31 | 32 | The `/_nuxt/*` reference automatically changes with the value of [`build.publicPath`][nuxt-docs-build-publicPath]. 33 | 34 | 35 | 36 | ## Headers 37 | 38 | The headers object represents a JS version of the [Netlify `_headers` file format][netlify-headers-and-basic-auth]. You should pass in a object with string keys (representing the paths) and an array of strings for each header. For example: 39 | 40 | ```js 41 | const pkg = require('./package.json') 42 | 43 | { 44 | netlify: { 45 | headers: { 46 | '/*': [ 47 | 'Access-Control-Allow-Origin: *', 48 | `X-Build: ${pkg.version}` 49 | ], 50 | '/favicon.ico': [ 51 | 'Cache-Control: public, max-age=86400' 52 | ] 53 | } 54 | } 55 | } 56 | ``` 57 | 58 | that will generate: 59 | 60 | ```text 61 | # _headers 62 | 63 | /* 64 | Referrer-Policy: origin 65 | X-Content-Type-Options: nosniff 66 | X-Frame-Options: DENY 67 | X-XSS-Protection: 1; mode=block 68 | Access-Control-Allow-Origin: * 69 | X-Build: 1.0.1 70 | 71 | /_nuxt/* 72 | Cache-Control: public, max-age=31536000, immutable 73 | 74 | /sw.js 75 | Cache-Control: no-cache 76 | 77 | /favicon.ico 78 | Cache-Control: public, max-age=86400 79 | ``` 80 | 81 | ## Redirects 82 | 83 | You can also add redirects, as many as you like. You should pass in an array of objects with the redirection attributes. For example: 84 | 85 | 86 | ```js 87 | { 88 | netlify: { 89 | redirects: [ 90 | { 91 | from: '/home', 92 | to: '/' 93 | }, 94 | { 95 | from: '/my-redirect', 96 | to: '/', 97 | status: 302, 98 | force: true 99 | }, 100 | { 101 | from: '/en/*', 102 | to: '/en/404.html', 103 | status: 404 104 | }, 105 | { 106 | from: '/*', 107 | to: '/index.html', 108 | status: 200 109 | }, 110 | { 111 | from: '/store', 112 | to: '/blog/:id', 113 | query: { 114 | id: ':id' 115 | } 116 | }, 117 | { 118 | from: '/', 119 | to: '/china', 120 | status: 302, 121 | conditions: { 122 | Country: 'cn,hk,tw' 123 | } 124 | } 125 | ] 126 | } 127 | } 128 | ``` 129 | 130 | will generate: 131 | 132 | ```text 133 | # _redirects 134 | 135 | /home / 301 136 | /my-redirect / 302! 137 | /en/* /en/404.html 404 138 | /* /index.html 200 139 | /store id=:id /blog/:id 301 140 | / /china 302 Country=cn,hk,tw 141 | ``` 142 | 143 | 144 | See the [configuration](/docs/nuxt-netlify/configuration) section for all available options. 145 | 146 | 147 | 148 | [nuxt-docs-build-publicPath]: https://nuxtjs.org/api/configuration-build#publicPath 149 | [netlify-headers-and-basic-auth]: https://www.netlify.com/docs/headers-and-basic-auth/ 150 | -------------------------------------------------------------------------------- /docs/es/usage.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Uso" 3 | description: "La configuración por defecto generará un archivo `_redirects` vacío y un archivos `_headers` con algunos headers de securidad y cache" 4 | createdAt: "2019-03-06T15:43:56Z" 5 | publishedAt: "2019-03-06T15:43:56Z" 6 | updatedAt: "2020-07-17T20:01:04Z" 7 | position: 2 8 | category: "Primeros Pasos" 9 | --- 10 | 11 | La configuración por defecto generará un archivo `_redirects` vacío y un archivo `_headers` con algunas cabeceras de securidad y caché: 12 | 13 | ```text 14 | # _headers 15 | 16 | /* 17 | Referrer-Policy: origin 18 | X-Content-Type-Options: nosniff 19 | X-Frame-Options: DENY 20 | X-XSS-Protection: 1; mode=block 21 | 22 | /_nuxt/* 23 | Cache-Control: public, max-age=31536000, immutable 24 | 25 | /sw.js 26 | Cache-Control: no-cache 27 | ``` 28 | 29 | 30 | 31 | 32 | La referencia `/_nuxt/*` automáticamente cambia con el valor de [`build.publicPath`][nuxt-docs-build-publicPath]. 33 | 34 | 35 | 36 | ## Cabeceras 37 | 38 | El objeto cabecera representa una versión en JS del [formato de archivos de Netlify `_headers`][netlify-headers-and-basic-auth]. Debes pasar un objecto con índices de texto (representando las rutas) y un arreglo de textos para cada cabecera. Por ejemplo: 39 | 40 | ```js 41 | const pkg = require('./package.json') 42 | 43 | { 44 | netlify: { 45 | headers: { 46 | '/*': [ 47 | 'Access-Control-Allow-Origin: *', 48 | `X-Build: ${pkg.version}` 49 | ], 50 | '/favicon.ico': [ 51 | 'Cache-Control: public, max-age=86400' 52 | ] 53 | } 54 | } 55 | } 56 | ``` 57 | 58 | esto generará lo siguiente: 59 | 60 | ```text 61 | # _headers 62 | 63 | /* 64 | Referrer-Policy: origin 65 | X-Content-Type-Options: nosniff 66 | X-Frame-Options: DENY 67 | X-XSS-Protection: 1; mode=block 68 | Access-Control-Allow-Origin: * 69 | X-Build: 1.0.1 70 | 71 | /_nuxt/* 72 | Cache-Control: public, max-age=31536000, immutable 73 | 74 | /sw.js 75 | Cache-Control: no-cache 76 | 77 | /favicon.ico 78 | Cache-Control: public, max-age=86400 79 | ``` 80 | 81 | ## Redirecciones 82 | 83 | También puedes añadar redirecciones, tantas como desees. Debes pasar un arreglo de objetos con los atributos de redirección. Por ejemplo: 84 | 85 | 86 | ```js 87 | { 88 | netlify: { 89 | redirects: [ 90 | { 91 | from: '/home', 92 | to: '/' 93 | }, 94 | { 95 | from: '/my-redirect', 96 | to: '/', 97 | status: 302, 98 | force: true 99 | }, 100 | { 101 | from: '/en/*', 102 | to: '/en/404.html', 103 | status: 404 104 | }, 105 | { 106 | from: '/*', 107 | to: '/index.html', 108 | status: 200 109 | }, 110 | { 111 | from: '/store', 112 | to: '/blog/:id', 113 | query: { 114 | id: ':id' 115 | } 116 | }, 117 | { 118 | from: '/', 119 | to: '/china', 120 | status: 302, 121 | conditions: { 122 | Country: 'cn,hk,tw' 123 | } 124 | } 125 | ] 126 | } 127 | } 128 | ``` 129 | 130 | que generará: 131 | 132 | ```text 133 | # _redirects 134 | 135 | /home / 301 136 | /my-redirect / 302! 137 | /en/* /en/404.html 404 138 | /* /index.html 200 139 | /store id=:id /blog/:id 301 140 | / /china 302 Country=cn,hk,tw 141 | ``` 142 | 143 | 144 | Ve la sección de [configuración](/es/docs/nuxt-netlify/configuration) para todas las opciones disponibles. 145 | 146 | 147 | 148 | [nuxt-docs-build-publicPath]: https://nuxtjs.org/api/configuration-build#publicPath 149 | [netlify-headers-and-basic-auth]: https://www.netlify.com/docs/headers-and-basic-auth/ 150 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/node,macos,linux,windows 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,linux,windows 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### macOS ### 20 | # General 21 | .DS_Store 22 | .AppleDouble 23 | .LSOverride 24 | 25 | # Icon must end with two \r 26 | Icon 27 | 28 | 29 | # Thumbnails 30 | ._* 31 | 32 | # Files that might appear in the root of a volume 33 | .DocumentRevisions-V100 34 | .fseventsd 35 | .Spotlight-V100 36 | .TemporaryItems 37 | .Trashes 38 | .VolumeIcon.icns 39 | .com.apple.timemachine.donotpresent 40 | 41 | # Directories potentially created on remote AFP share 42 | .AppleDB 43 | .AppleDesktop 44 | Network Trash Folder 45 | Temporary Items 46 | .apdisk 47 | 48 | ### Node ### 49 | # Logs 50 | logs 51 | *.log 52 | npm-debug.log* 53 | yarn-debug.log* 54 | yarn-error.log* 55 | lerna-debug.log* 56 | 57 | # Diagnostic reports (https://nodejs.org/api/report.html) 58 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 59 | 60 | # Runtime data 61 | pids 62 | *.pid 63 | *.seed 64 | *.pid.lock 65 | 66 | # Directory for instrumented libs generated by jscoverage/JSCover 67 | lib-cov 68 | 69 | # Coverage directory used by tools like istanbul 70 | coverage 71 | *.lcov 72 | 73 | # nyc test coverage 74 | .nyc_output 75 | 76 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 77 | .grunt 78 | 79 | # Bower dependency directory (https://bower.io/) 80 | bower_components 81 | 82 | # node-waf configuration 83 | .lock-wscript 84 | 85 | # Compiled binary addons (https://nodejs.org/api/addons.html) 86 | build/Release 87 | 88 | # Dependency directories 89 | node_modules/ 90 | jspm_packages/ 91 | 92 | # TypeScript v1 declaration files 93 | typings/ 94 | 95 | # TypeScript cache 96 | *.tsbuildinfo 97 | 98 | # Optional npm cache directory 99 | .npm 100 | 101 | # Optional eslint cache 102 | .eslintcache 103 | 104 | # Microbundle cache 105 | .rpt2_cache/ 106 | .rts2_cache_cjs/ 107 | .rts2_cache_es/ 108 | .rts2_cache_umd/ 109 | 110 | # Optional REPL history 111 | .node_repl_history 112 | 113 | # Output of 'npm pack' 114 | *.tgz 115 | 116 | # Yarn Integrity file 117 | .yarn-integrity 118 | 119 | # dotenv environment variables file 120 | .env 121 | .env.test 122 | .env*.local 123 | 124 | # parcel-bundler cache (https://parceljs.org/) 125 | .cache 126 | .parcel-cache 127 | 128 | # Next.js build output 129 | .next 130 | 131 | # Nuxt.js build / generate output 132 | .nuxt 133 | dist 134 | 135 | # Gatsby files 136 | .cache/ 137 | # Comment in the public line in if your project uses Gatsby and not Next.js 138 | # https://nextjs.org/blog/next-9-1#public-directory-support 139 | # public 140 | 141 | # vuepress build output 142 | .vuepress/dist 143 | 144 | # Serverless directories 145 | .serverless/ 146 | 147 | # FuseBox cache 148 | .fusebox/ 149 | 150 | # DynamoDB Local files 151 | .dynamodb/ 152 | 153 | # TernJS port file 154 | .tern-port 155 | 156 | # Stores VSCode versions used for testing VSCode extensions 157 | .vscode-test 158 | 159 | ### Windows ### 160 | # Windows thumbnail cache files 161 | Thumbs.db 162 | Thumbs.db:encryptable 163 | ehthumbs.db 164 | ehthumbs_vista.db 165 | 166 | # Dump file 167 | *.stackdump 168 | 169 | # Folder config file 170 | [Dd]esktop.ini 171 | 172 | # Recycle Bin used on file shares 173 | $RECYCLE.BIN/ 174 | 175 | # Windows Installer files 176 | *.cab 177 | *.msi 178 | *.msix 179 | *.msm 180 | *.msp 181 | 182 | # Windows shortcuts 183 | *.lnk 184 | 185 | # End of https://www.toptal.com/developers/gitignore/api/node,macos,linux,windows 186 | -------------------------------------------------------------------------------- /docs/configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Configuration" 3 | description: "The default options could be enough, but you can overwrite every available option if you want to." 4 | createdAt: "2019-03-06T15:43:56Z" 5 | publishedAt: "2019-03-06T15:43:56Z" 6 | updatedAt: "2020-07-17T20:01:04Z" 7 | position: 3 8 | category: "Getting started" 9 | --- 10 | 11 | The default options could be enough, but you can overwrite every available option if you want to. 12 | 13 | ## headers 14 | 15 | - Type: `object` 16 | - Default: `{}` 17 | 18 | Adds extra headers. 19 | 20 | You should pass in a object with string keys (representing the paths) and an array of strings for each header. 21 | 22 | ```js 23 | { 24 | netlify: { 25 | headers: { 26 | '/*': [ 27 | 'Access-Control-Allow-Origin: *' 28 | ], 29 | '/favicon.ico': [ 30 | 'Cache-Control: public, max-age=86400' 31 | ] 32 | } 33 | } 34 | } 35 | ``` 36 | 37 | ## redirects 38 | 39 | - Type: `array` 40 | - Default: `[]` 41 | 42 | Adds extra redirects. 43 | 44 | You should pass in an array of objects with the redirection attributes. The available attributes for each redirect are: 45 | 46 | - **from** (required): the path you want to redirect. 47 | - **to** (required): the URL or path you want to redirect to. 48 | - **status**: the HTTP status code you want to use in that redirect (default: `301`). 49 | - **force**: whether to override any existing content in the path or not (default: `false`). 50 | - **query**: the query string parameters required to match the redirect. You can read more about [Query Params here][netlify-redirects-query-params]. 51 | - **conditions**: conditions to match the redirect, like [Geo-IP][netlify-redirects-geo-ip] and [Role][netlify-redirects-role] conditions. 52 | 53 | 54 | Example: 55 | 56 | ```js 57 | { 58 | netlify: { 59 | redirects: [ 60 | { 61 | from: '/home', 62 | to: '/' 63 | }, 64 | { 65 | from: '/my-redirect', 66 | to: '/', 67 | status: 302, 68 | force: true 69 | }, 70 | { 71 | from: '/store', 72 | to: '/blog/:id', 73 | query: { 74 | id: ':id' 75 | } 76 | }, 77 | { 78 | from: '/', 79 | to: '/china', 80 | status: 302, 81 | conditions: { 82 | Country: 'cn,hk,tw' 83 | } 84 | } 85 | ] 86 | } 87 | } 88 | ``` 89 | 90 | 91 | 92 | ## mergeSecurityHeaders 93 | 94 | - Type: `boolean` 95 | - Default: `true` 96 | 97 | Merge the default security headers in `_headers`: 98 | 99 | ```text 100 | /* 101 | Referrer-Policy: origin 102 | X-Content-Type-Options: nosniff 103 | X-Frame-Options: DENY 104 | X-XSS-Protection: 1; mode=block 105 | ``` 106 | 107 | ## mergeCachingHeaders 108 | 109 | - Type: `boolean` 110 | - Default: `true` 111 | 112 | Merge the default caching headers in `_headers`: 113 | 114 | ```text 115 | /_nuxt/* 116 | Cache-Control: public, max-age=31536000, immutable 117 | 118 | /sw.js 119 | Cache-Control: no-cache 120 | ``` 121 | 122 | 123 | 124 | The `/_nuxt/*` reference automatically changes with the value of [`build.publicPath`][nuxt-docs-build-publicPath]. 125 | 126 | 127 | 128 | 129 | ## transformHeaders 130 | 131 | - Type: `function` 132 | - Default: `(headers, path) => headers` 133 | 134 | Optional transform for manipulating headers under each path (e.g.sorting), etc. Example: 135 | 136 | ```js 137 | { 138 | netlify: { 139 | transformHeaders: (headers, path) => headers.sort() 140 | } 141 | } 142 | 143 | ``` 144 | 145 | [netlify-redirects-query-params]: https://www.netlify.com/docs/redirects/#query-params 146 | [netlify-redirects-geo-ip]: https://www.netlify.com/docs/redirects/#geoip-and-language-based-redirects 147 | [netlify-redirects-role]: https://www.netlify.com/docs/redirects/#role-based-redirect-rules 148 | [nuxt-docs-build-publicPath]: https://nuxtjs.org/api/configuration-build#publicPath 149 | -------------------------------------------------------------------------------- /test/redirects.test.js: -------------------------------------------------------------------------------- 1 | const { createRedirectContent } = require('../lib/utils') 2 | 3 | describe('redirects', () => { 4 | it('can generate a simple redirect', () => { 5 | expect(createRedirectContent({ 6 | from: '/home', 7 | to: '/' 8 | })).toEqual('/home / 301\n') 9 | 10 | expect(createRedirectContent({ 11 | from: '/blog/my-post.php', 12 | to: '/blog/my-post' 13 | })).toEqual('/blog/my-post.php /blog/my-post 301\n') 14 | 15 | expect(createRedirectContent({ 16 | from: '/google', 17 | to: 'https://www.google.com' 18 | })).toEqual('/google https://www.google.com 301\n') 19 | 20 | expect(createRedirectContent({ 21 | from: '/news/*', 22 | to: '/blog/:splat' 23 | })).toEqual('/news/* /blog/:splat 301\n') 24 | }) 25 | 26 | it('can generate a redirect with a different status code', () => { 27 | expect(createRedirectContent({ 28 | from: '/my-redirect', 29 | to: '/', 30 | status: 302 31 | })).toEqual('/my-redirect / 302\n') 32 | 33 | expect(createRedirectContent({ 34 | from: '/pass-through', 35 | to: '/index.html', 36 | status: 200 37 | })).toEqual('/pass-through /index.html 200\n') 38 | 39 | expect(createRedirectContent({ 40 | from: '/ecommerce', 41 | to: '/store-closed', 42 | status: 404 43 | })).toEqual('/ecommerce /store-closed 404\n') 44 | 45 | expect(createRedirectContent({ 46 | from: '/en/*', 47 | to: '/en/404.html', 48 | status: 404 49 | })).toEqual('/en/* /en/404.html 404\n') 50 | 51 | expect(createRedirectContent({ 52 | from: '/*', 53 | to: '/index.html', 54 | status: 200 55 | })).toEqual('/* /index.html 200\n') 56 | }) 57 | 58 | it('can force redirection', () => { 59 | expect(createRedirectContent({ 60 | from: 'http://blog.yoursite.com/*', 61 | to: 'https://www.yoursite.com/blog/:splat', 62 | force: true 63 | })).toEqual('http://blog.yoursite.com/* https://www.yoursite.com/blog/:splat 301!\n') 64 | 65 | expect(createRedirectContent({ 66 | from: 'http://blog.yoursite.com/*', 67 | to: 'https://www.yoursite.com/blog/:splat', 68 | status: 302, 69 | force: true 70 | })).toEqual('http://blog.yoursite.com/* https://www.yoursite.com/blog/:splat 302!\n') 71 | }) 72 | 73 | it('can generate a redirect with query params', () => { 74 | expect(createRedirectContent({ 75 | from: '/store', 76 | to: '/blog/:id', 77 | query: { 78 | id: ':id' 79 | } 80 | })).toEqual('/store id=:id /blog/:id 301\n') 81 | 82 | expect(createRedirectContent({ 83 | from: '/articles', 84 | to: '/posts/:tag/:id', 85 | query: { 86 | id: ':id', 87 | tag: ':tag' 88 | } 89 | })).toEqual('/articles id=:id tag=:tag /posts/:tag/:id 301\n') 90 | }) 91 | 92 | it('can generate a redirect with conditons', () => { 93 | expect(createRedirectContent({ 94 | from: '/', 95 | to: '/china', 96 | status: 302, 97 | conditions: { 98 | Country: 'cn,hk,tw' 99 | } 100 | })).toEqual('/ /china 302 Country=cn,hk,tw\n') 101 | 102 | expect(createRedirectContent({ 103 | from: '/', 104 | to: '/israel', 105 | status: 302, 106 | conditions: { 107 | Country: 'il' 108 | } 109 | })).toEqual('/ /israel 302 Country=il\n') 110 | 111 | expect(createRedirectContent({ 112 | from: '/admin/*', 113 | status: 200, 114 | force: true, 115 | conditions: { 116 | Role: 'admin' 117 | } 118 | })).toEqual('/admin/* 200! Role=admin\n') 119 | 120 | expect(createRedirectContent({ 121 | from: '/private/*', 122 | status: 200, 123 | force: true, 124 | conditions: { 125 | Role: 'editor,admin' 126 | } 127 | })).toEqual('/private/* 200! Role=editor,admin\n') 128 | }) 129 | }) 130 | -------------------------------------------------------------------------------- /docs/es/configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Configuración" 3 | description: "Las opciones por defecto podrían ser suficiente, pero puedes cambiar cada una de las opciones disponibles si así los deseas." 4 | createdAt: "2019-03-06T15:43:56Z" 5 | publishedAt: "2019-03-06T15:43:56Z" 6 | updatedAt: "2020-07-17T20:01:04Z" 7 | position: 3 8 | category: "Primeros Pasos" 9 | --- 10 | 11 | Las opciones por defecto podrían ser suficiente, pero puedes cambiar cada una de las opciones disponibles si así los deseas. 12 | 13 | ## headers 14 | 15 | - Type: `object` 16 | - Default: `{}` 17 | 18 | Añade cabeceras extras. 19 | 20 | Debes pasar un objecto con índices de texto (representando las rutas) y un arreglo de textos para cada cabecera. 21 | 22 | ```js 23 | { 24 | netlify: { 25 | headers: { 26 | '/*': [ 27 | 'Access-Control-Allow-Origin: *' 28 | ], 29 | '/favicon.ico': [ 30 | 'Cache-Control: public, max-age=86400' 31 | ] 32 | } 33 | } 34 | } 35 | ``` 36 | 37 | ## redirects 38 | 39 | - Type: `array` 40 | - Default: `[]` 41 | 42 | Añade redireciones extras. 43 | 44 | Debes pasar un arreglo de objetos con los atributos de redirección. Los atributos disponibles para cada redirección son: 45 | 46 | - **from** (requerido): la ruta que quieres redireccionar. 47 | - **to** (requerido): la URL o ruta a dodne quieres redireccionar. 48 | - **status**: el código de estado HTTP que quieres usar en esa redirección (por defecto: `301`). 49 | - **force**: sobreescribir o no cualquier contenido existente en la ruta (por defecto: `false`). 50 | - **query**: los parámetros de consulta requerido que coinciden con la redirección. Puedes leer más sobre los [Parámetros de Consulta aquí][netlify-redirects-query-params]. 51 | - **conditions**: las condiciones que coinciden con la redirección, como las condiciones [Geo-IP][netlify-redirects-geo-ip] o [Role][netlify-redirects-role]. 52 | 53 | 54 | Ejemplo: 55 | 56 | ```js 57 | { 58 | netlify: { 59 | redirects: [ 60 | { 61 | from: '/home', 62 | to: '/' 63 | }, 64 | { 65 | from: '/my-redirect', 66 | to: '/', 67 | status: 302, 68 | force: true 69 | }, 70 | { 71 | from: '/store', 72 | to: '/blog/:id', 73 | query: { 74 | id: ':id' 75 | } 76 | }, 77 | { 78 | from: '/', 79 | to: '/china', 80 | status: 302, 81 | conditions: { 82 | Country: 'cn,hk,tw' 83 | } 84 | } 85 | ] 86 | } 87 | } 88 | ``` 89 | 90 | ## mergeSecurityHeaders 91 | 92 | - Type: `boolean` 93 | - Default: `true` 94 | 95 | Une las cabeceras por defecto de seguridad en `_headers`: 96 | 97 | ```text 98 | /* 99 | Referrer-Policy: origin 100 | X-Content-Type-Options: nosniff 101 | X-Frame-Options: DENY 102 | X-XSS-Protection: 1; mode=block 103 | ``` 104 | 105 | ## mergeCachingHeaders 106 | 107 | - Type: `boolean` 108 | - Default: `true` 109 | 110 | Une las cabeceras por defecto de seguridad caché en `_headers`: 111 | 112 | ```text 113 | /_nuxt/* 114 | Cache-Control: public, max-age=31536000, immutable 115 | 116 | /sw.js 117 | Cache-Control: no-cache 118 | ``` 119 | 120 | 121 | 122 | La referencia `/_nuxt/*` automáticamente cambia con el valor de [`build.publicPath`][nuxt-docs-build-publicPath]. 123 | 124 | 125 | 126 | 127 | ## transformHeaders 128 | 129 | - Type: `function` 130 | - Default: `(headers, path) => headers` 131 | 132 | Transformador opcional para la manipulación de las cabeceras bajo cada ruta (p.ej. ordenar alfabéticamente). Ejemplo: 133 | 134 | ```js 135 | { 136 | netlify: { 137 | transformHeaders: (headers, path) => headers.sort() 138 | } 139 | } 140 | 141 | ``` 142 | 143 | [netlify-redirects-query-params]: https://www.netlify.com/docs/redirects/#query-params 144 | [netlify-redirects-geo-ip]: https://www.netlify.com/docs/redirects/#geoip-and-language-based-redirects 145 | [netlify-redirects-role]: https://www.netlify.com/docs/redirects/#role-based-redirect-rules 146 | [nuxt-docs-build-publicPath]: https://nuxtjs.org/api/configuration-build#publicPath 147 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a55402d7c89b4084882c3362427132d8)](https://www.codacy.com/app/juliomrqz/nuxt-netlify?utm_source=github.com&utm_medium=referral&utm_content=juliomrqz/nuxt-netlify&utm_campaign=Badge_Grade) 2 | [![Travis](https://img.shields.io/travis/juliomrqz/nuxt-netlify.svg)](https://travis-ci.org/juliomrqz/nuxt-netlify) 3 | [![David](https://img.shields.io/david/peer/juliomrqz/nuxt-netlify.svg)](https://david-dm.org/juliomrqz/nuxt-netlify?type=peer) 4 | [![David](https://img.shields.io/david/dev/juliomrqz/nuxt-netlify.svg)](https://david-dm.org/juliomrqz/nuxt-netlify?type=dev) 5 | [![version](https://img.shields.io/npm/v/@aceforth/nuxt-netlify.svg)](https://www.npmjs.com/package/@aceforth/nuxt-netlify) 6 | [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/juliomrqz/nuxt-netlify/develop/LICENSE) 7 | 8 | # Nuxt Netlify 9 | 10 | Dynamically generate `_headers` and `_redirects` files for Netlify in your Nuxt.js projects. 11 | 12 | This module supports the creation of [**redirects**][netlify-redirects] and [**header**][netlify-headers-and-basic-auth] rules for your Netlify site: you can easily configure custom headers, basic auth, redirect instructions and rewrite rules from your _nuxt config file_. 13 | 14 | *Read this in other languages: [English][docs], [Español][docs-es]* 15 | 16 | 17 | ## Installation 18 | 19 | :warning: `node >= 10` and `nuxt >= 2` are required. 20 | 21 | 22 | ```bash 23 | npm install --save-dev @aceforth/nuxt-netlify 24 | ``` 25 | 26 | or 27 | 28 | ```bash 29 | yarn add --dev @aceforth/nuxt-netlify 30 | ``` 31 | 32 | Add `@aceforth/nuxt-netlify` to the `buildModules` section of `nuxt.config.js`: 33 | 34 | :warning: If you are using Nuxt `< 2.9.0`, use `modules` instead. 35 | 36 | ```js 37 | { 38 | buildModules: [ 39 | '@aceforth/nuxt-netlify', 40 | ], 41 | 42 | netlify: { 43 | mergeSecurityHeaders: true 44 | } 45 | } 46 | ``` 47 | 48 | or 49 | 50 | 51 | ```js 52 | { 53 | buildModules: [ 54 | [ 55 | '@aceforth/nuxt-netlify', 56 | { 57 | mergeSecurityHeaders: true 58 | } 59 | ] 60 | ] 61 | } 62 | ``` 63 | 64 | 65 | ## Usage 66 | 67 | The default configuration will generate an empty `_redirects` file and a `_headers` file with some caching and security headers: 68 | 69 | ```text 70 | # _headers 71 | 72 | /* 73 | Referrer-Policy: origin 74 | X-Content-Type-Options: nosniff 75 | X-Frame-Options: DENY 76 | X-XSS-Protection: 1; mode=block 77 | 78 | /_nuxt/* 79 | Cache-Control: public, max-age=31536000, immutable 80 | 81 | /sw.js 82 | Cache-Control: no-cache 83 | ``` 84 | 85 | > :warning: the `/_nuxt/*` reference automatically changes with the value of [`build.publicPath`][nuxt-docs-build-publicPath]. 86 | 87 | ### Headers 88 | 89 | The headers object represents a JS version of the [Netlify `_headers` file format][netlify-headers-and-basic-auth]. You should pass in a object with string keys (representing the paths) and an array of strings for each header. For example: 90 | 91 | 92 | You can add extra headers as follows: 93 | 94 | ```js 95 | const pkg = require('./package.json') 96 | 97 | { 98 | netlify: { 99 | headers: { 100 | '/*': [ 101 | 'Access-Control-Allow-Origin: *', 102 | `X-Build: ${pkg.version}` 103 | ], 104 | '/favicon.ico': [ 105 | 'Cache-Control: public, max-age=86400' 106 | ] 107 | } 108 | } 109 | } 110 | ``` 111 | 112 | that will generate: 113 | 114 | ```text 115 | # _headers 116 | 117 | /* 118 | Referrer-Policy: origin 119 | X-Content-Type-Options: nosniff 120 | X-Frame-Options: DENY 121 | X-XSS-Protection: 1; mode=block 122 | Access-Control-Allow-Origin: * 123 | X-Build: 1.0.1 124 | 125 | /_nuxt/* 126 | Cache-Control: public, max-age=31536000, immutable 127 | 128 | /sw.js 129 | Cache-Control: no-cache 130 | 131 | /favicon.ico 132 | Cache-Control: public, max-age=86400 133 | ``` 134 | 135 | ### Redirects 136 | 137 | You can also add [redirects][netlify-redirects], as many as you like. You should pass in an array of objects with the redirection attributes. For example: 138 | 139 | 140 | ```js 141 | { 142 | netlify: { 143 | redirects: [ 144 | { 145 | from: '/home', 146 | to: '/' 147 | }, 148 | { 149 | from: '/my-redirect', 150 | to: '/', 151 | status: 302, 152 | force: true 153 | }, 154 | { 155 | from: '/en/*', 156 | to: '/en/404.html', 157 | status: 404 158 | }, 159 | { 160 | from: '/*', 161 | to: '/index.html', 162 | status: 200 163 | }, 164 | { 165 | from: '/store', 166 | to: '/blog/:id', 167 | query: { 168 | id: ':id' 169 | } 170 | }, 171 | { 172 | from: '/', 173 | to: '/china', 174 | status: 302, 175 | conditions: { 176 | Country: 'cn,hk,tw' 177 | } 178 | } 179 | ] 180 | } 181 | } 182 | ``` 183 | 184 | will generate: 185 | 186 | ```text 187 | # _redirects 188 | 189 | /home / 301 190 | /my-redirect / 302! 191 | /en/* /en/404.html 404 192 | /* /index.html 200 193 | /store id=:id /blog/:id 301 194 | / /china 302 Country=cn,hk,tw 195 | ``` 196 | 197 | 198 | See the [configuration][docs-configuration] section for all available options. 199 | 200 | ## Documentation & Support 201 | 202 | - 📄 If you want extra details of how to configure and use this project, the **full documentation** is available at [https://marquez.co/docs/nuxt-netlify/][docs]. 203 | - 🐞 For **Bug reports** or **Feature requests**, use the [Issues section][issues]. 204 | - 💬 For **questions**, you can also use the [Issues section][issues]. 205 | - 🚀 You may also want to **follow me** [on Twitter][twitter]. 206 | 207 | ## Professional Support 208 | 209 | This project is sponsored by me, a Full Stack Developer. If you require Professional Assistance on your project(s), please contact me at [https://marquez.co][contact-page]. 210 | 211 | ## Code of Conduct 212 | 213 | Everyone participating in this project is expected to agree to abide by the [Code of Conduct][code-of-conduct]. 214 | 215 | 216 | ## License 217 | 218 | Code released under the [MIT License][license-page]. 219 | 220 | 221 | ![](https://ga-beacon.appspot.com/UA-65885578-17/juliomrqz/nuxt-netlify?pixel) 222 | 223 | [docs]: https://marquez.co/docs/nuxt-netlify/?utm_source=github&utm_medium=readme&utm_campaign=nuxt-netlify 224 | [docs-es]: https://marquez.co/es/docs/nuxt-netlify/?utm_source=github&utm_medium=readme&utm_campaign=nuxt-netlify 225 | [docs-configuration]: https://marquez.co/docs/nuxt-netlify/configuration/?utm_source=github&utm_medium=readme&utm_campaign=nuxt-netlify 226 | [nuxt-docs-build-publicPath]: https://nuxtjs.org/api/configuration-build#publicPath 227 | [netlify-headers-and-basic-auth]: https://www.netlify.com/docs/headers-and-basic-auth/ 228 | [netlify-redirects]: https://www.netlify.com/docs/redirects/ 229 | [issues]: https://github.com/juliomrqz/nuxt-netlify/issues 230 | [twitter]: https://twitter.com/juliomrqz 231 | [contact-page]: https://marquez.co?utm_source=github&utm_medium=readme&utm_campaign=nuxt-netlify 232 | [code-of-conduct]: https://www.contributor-covenant.org/version/2/0/code_of_conduct/ 233 | [license-page]: https://github.com/juliomrqz/nuxt-netlify/blob/develop/LICENSE 234 | --------------------------------------------------------------------------------