gatsbyjs / gatsby

The best React-based framework with performance, scalability and security built in.
https://www.gatsbyjs.com
MIT License
55.21k stars 10.33k forks source link

navigateTo() doesn't prepend pathPrefix #5739

Closed cnatale closed 6 years ago

cnatale commented 6 years ago

Description

Setting a pathPrefix in gatsby-config causes Gatsby-link component paths to update dynamically. However, the navigateTo() method does not.

Steps to reproduce

Set the pathPrefix property in gatsby-config.js. Use navigateTo('routeName') to navigate.

Expected result

The route is navigated to, with pathPrefix prepended to it.

Actual result

The route is navigated to, but without pathPrefix appended to it.

Environment

  System:
    OS: OS X El Capitan 10.11.6
    CPU: x64 Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 8.9.3 - ~/.nvm/versions/node/v8.9.3/bin/node
    Yarn: yarn install v0.24.6
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 43.83s. - ~/.yarn/bin/yarn
    npm: 5.7.1 - ~/.nvm/versions/node/v8.9.3/bin/npm
  npmPackages:
    gatsby: ^1.9.247 => 1.9.250 
    gatsby-cli: ^1.1.58 => 1.1.58 
    gatsby-link: 1.6.40 => 1.6.40 
    gatsby-plugin-less: ^1.1.8 => 1.1.8 
    gatsby-plugin-react-next: ^1.0.11 => 1.0.11 
    gatsby-source-filesystem: ^1.5.31 => 1.5.31 
    gatsby-transformer-json: ^1.0.16 => 1.0.16 
    gatsby-transformer-remark: ^1.7.40 => 1.7.40 

File contents (if changed)

gatsby-config.js:

module.exports = {
  // Note: it must *not* have a trailing slash.
  pathPrefix: '/awards',
  siteMetadata: {
    title: 'A title from the app config',
    title2: 'Another title from the app config'
  },
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `src`,
        path: `${__dirname}/src/`
      }
    },
    `gatsby-plugin-less`,
    `gatsby-plugin-react-next`,
    `gatsby-transformer-remark`,
    `gatsby-transformer-json`
  ]
};

package.json:

{
  "name": "xxx",
  "description": "xxx",
  "license": "MIT",
  "scripts": {
    "info": "gatsby info --clipboard",
    "develop": "gatsby develop",
    "build": "rimraf public && gatsby build --prefix-paths",
    "debug-serve": "node --inspect src/server/index.js",
    "serve": "node src/server/index.js",
    "test": "npm run lint && jest",
    "lint": "node_modules/.bin/eslint ./**/*.js",
    "prettify": "node_modules/.bin/prettier --write ./*.js ./src/**/*.js ./tests/**/*.js"
  },
  "jest": {
    "moduleNameMapper": {
      "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/file-mock.js",
      "\\.(css|less)$": "identity-obj-proxy"
    }
  },
  "dependencies": {
    "@ookla/common-ui": "^0.22.2",
    "@ookla/ookla-logging": "^3.0.0",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-preset-env": "^1.6.1",
    "babel-preset-react": "^6.24.1",
    "config": "^1.30.0",
    "express": "^4.16.3",
    "gatsby": "^1.9.247",
    "gatsby-link": "1.6.40",
    "gatsby-plugin-less": "^1.1.8",
    "gatsby-plugin-react-next": "^1.0.11",
    "gatsby-source-filesystem": "^1.5.31",
    "gatsby-transformer-json": "^1.0.16",
    "gatsby-transformer-remark": "^1.7.40",
    "identity-obj-proxy": "^3.0.0",
    "postcss-cssnext": "^3.1.0",
    "postcss-import": "^11.1.0",
    "postcss-loader": "^2.1.3",
    "postcss-nested": "^2.1.2",
    "prop-types": "^15.6.1",
    "purecss": "^1.0.0",
    "qs": "^6.5.1",
    "raw-loader": "^0.5.1",
    "react": "^16.3.2",
    "react-dom": "^16.3.2",
    "react-helmet": "^5.2.0",
    "react-scroll": "^1.7.9",
    "react-test-renderer": "^16.3.2",
    "rimraf": "^2.6.2"
  },
  "devDependencies": {
    "babel-eslint": "^8.2.3",
    "babel-jest": "^22.4.3",
    "enzyme": "^3.3.0",
    "enzyme-adapter-react-16": "^1.1.1",
    "eslint": "^4.19.1",
    "eslint-config-prettier": "^2.9.0",
    "eslint-plugin-filenames": "^1.2.0",
    "eslint-plugin-import": "^2.11.0",
    "eslint-plugin-prettier": "^2.6.0",
    "eslint-plugin-react": "^7.7.0",
    "gatsby-cli": "^1.1.58",
    "jest": "^22.4.3",
    "prettier": "^1.12.1"
  }
}```

`gatsby-node.js`:
```const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const postcssImport = require('postcss-import');
const postcssnext = require('postcss-cssnext');
const postcssNested = require('postcss-nested');
const cssVariables = require('@ookla/common-ui/lib/styles/variables');
const { getUrlFriendlyAwardType } = require('./src/utils/page-generation');

exports.modifyWebpackConfig = ({ config, stage } /* , options */) => {
  const cssFiles = /\.css$/;

  delete config._config.postcss;
  delete config._loaders.cssModules;
  delete config._loaders.css;

  config.merge({
    postcss: [
      postcssImport(),
      postcssnext({
        features: {
          customProperties: { variables: cssVariables.all }
        }
      }),
      postcssNested()
    ]
  });

  // Override url-loader default to exclude svg
  config.loader(`url-loader`, cfg => {
    cfg.test = /\.(jpg|jpeg|png|gif|mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/;
    return cfg;
  });

  // Load svg files with raw-loader, support icons in common-ui
  config.loader(`svg`, cfg => {
    cfg.test = /.svg$/;
    cfg.loader = 'raw-loader';
    return cfg;
  });

  // remove default css-loader, use custom loader & ETP config to support css-modules
  config.removeLoader('css');
  config.loader(`css`, () => {
    if (stage === 'develop') {
      return {
        test: cssFiles,
        loaders: ['style', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]', `postcss`]
      };
    }

    return {
      test: cssFiles,
      loader: ExtractTextPlugin.extract([
        'css?modules&importLoaders=1&minimize&localIdentName=[hash:base64:8]',
        `postcss`
      ])
    };
  });
};

exports.onCreateNode = ({ node, getNode, boundActionCreators }) => {
  const { createNodeField } = boundActionCreators;

  if (node.internal.type === 'Year2017Json') {
    // create location-award template slug
    createNodeField({
      node,
      name: 'locationAwardSlug',
      value: `${node.locationName}/${node.year}/`
    });

    // create award-type and provider-awards template slugs
    createNodeField({
      node,
      name: 'awardTypeSlug',
      value: `${getUrlFriendlyAwardType(node.type)}/${node.year}/`
    });

    createNodeField({
      node,
      name: 'providerAwardSlug',
      value: `${node.winner}/${node.year}/`
    });
  }
};

exports.createPages = ({ graphql, boundActionCreators }) => {
  const { createPage } = boundActionCreators;
  return new Promise(resolve => {
    graphql(`
      {
        allYear2017Json {
          edges {
            node {
              fields {
                locationAwardSlug
                awardTypeSlug
                providerAwardSlug
              }
              location {
                country
                countryId
              }
              year
              winner
              timePeriod
              locationName
              type
            }
          }
        }
      }
    `).then(
      result => {
        // generate individual award pages
        result.data.allYear2017Json.edges.forEach(({ node }) => {
          // create location-award pages
          createPage({
            path: node.fields.locationAwardSlug.replace(' ', '_').toLowerCase(),
            component: path.resolve(`./src/templates/location-award.js`),
            context: {
              // Data passed to context is available in page queries as GraphQL variables and as components props
              locationAwardSlug: node.fields.locationAwardSlug,
              year: node.year,
              locationSlug: `/${node.locationName.replace(' ', '_').toLowerCase()}`,
              locationName: node.locationName,
              searchString: '',
              searchType: '',
              datePickerFilter: node.locationName
            }
          });

          // default without year in url
          createPage({
            path: `${node.locationName}/`.replace(' ', '_').toLowerCase(),
            component: path.resolve(`./src/templates/location-award.js`),
            context: {
              // Data passed to context is available in page queries as GraphQL variables and as components props
              locationAwardSlug: node.fields.locationAwardSlug,
              year: node.year,
              locationSlug: `/${node.locationName.replace(' ', '_').toLowerCase()}`,
              locationName: node.locationName,
              searchString: node.locationName,
              searchType: 'location',
              datePickerFilter: node.locationName
            }
          });

          // create award-type pages
          createPage({
            path: node.fields.awardTypeSlug.replace(' ', '_').toLowerCase(),
            component: path.resolve(`./src/templates/award-type.js`),
            context: {
              awardTypeSlug: node.fields.awardTypeSlug,
              year: node.year,
              awardType: node.type,
              searchString: '',
              searchType: '',
              datePickerFilter: node.type
            }
          });

          // default without year in url
          createPage({
            path: `${getUrlFriendlyAwardType(node.type)}/`.replace(' ', '_').toLowerCase(),
            component: path.resolve(`./src/templates/award-type.js`),
            context: {
              awardTypeSlug: node.fields.awardTypeSlug,
              year: node.year,
              awardType: node.type,
              searchString: '',
              searchType: '',
              datePickerFilter: node.type
            }
          });

          // create provider-award pages
          createPage({
            path: node.fields.providerAwardSlug.replace(' ', '_').toLowerCase(),
            component: path.resolve(`./src/templates/provider-award.js`),
            context: {
              providerAwardSlug: node.fields.providerAwardSlug,
              year: node.year,
              companySlug: node.winner.replace(' ', '_').toLowerCase(),
              companyName: node.winner,
              searchType: '',
              searchString: '',
              datePickerFilter: node.winner
            }
          });

          // default without year in url
          createPage({
            path: `${node.winner}/`.replace(' ', '_').toLowerCase(),
            component: path.resolve(`./src/templates/provider-award.js`),
            context: {
              providerAwardSlug: node.fields.providerAwardSlug,
              year: node.year,
              companySlug: node.winner.replace(' ', '_').toLowerCase(),
              companyName: node.winner,
              searchString: node.winner,
              searchType: 'provider',
              datePickerFilter: node.winner
            }
          });
        });
        resolve();
      },
      res => {
        console.log('Error generating pages');
        console.log(res);
        resolve();
      }
    );
  });
};

// remove trailing slashes
exports.onCreatePage = ({ page, boundActionCreators }) => {
  const { createPage, deletePage } = boundActionCreators

  return new Promise((resolve, reject) => {
    // Remove trailing slash
    const newPage = Object.assign({}, page, {
      path: page.path === `/` ? page.path : page.path.replace(/\/$/, ``),
    })
    if (newPage.path !== page.path) {
      // Remove the old page
      deletePage(page)
      // Add the new page
      createPage(newPage)
    }

    resolve();
  })
};

gatsby-browser.js: N/A gatsby-ssr.js: N/A

pieh commented 6 years ago

Just to clarify - navigation itself works? Just url in adress bar is missing pathPrefix?

nihgwu commented 6 years ago

@cnatale I edited the wrong markdown format for better reading

KyleAMathews commented 6 years ago

Due to the high volume of issues, we're closing out older ones without recent activity. Please open a new issue if you need help!