slorber / gatsby-plugin-react-native-web

react-native-web plugin for Gatsby

Home Page:https://sebastienlorber.com/using-expo-in-gatsby

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

v3 static query problems

slorber opened this issue · comments

v3 does not support useStaticQuery

image

@sidharthachatterjee maybe you could give some insights here?

@EvanBacon brought Expo SDK support to this plugin in v3. Basically, Expo apis (usually for RN) now offer a binding for web, so they can also work in Gatsby too.

The thing is:

  • Gatsby has a complex webpack config / babel loader
  • Expo web has a complex webpack config / babel loader
  • Somehow we need to make the 2 play well together, or merge them

The webpack config of gatsby is "modified" by this method:
https://github.com/expo/expo-cli/blob/master/packages/webpack-config/src/addons/withUnimodules.ts#L22

It adds the expo babel loader (which is able to transpile RN modules) at the end of the webpack rules (so afaik it takes priority over the gatsby one).

So we have gatsbyLoader(expoLoader(jsCode)) somehow (at least for code in /src)

So, when gatsby loader (which has the static queries setup) do his work, the static queries may already have been "processed" (not sure how babel works), and now the gatsby loader do not recognize them anymore (???not sure about that???).

@sidharthachatterjee by chance do you know if it's possible to make static queries work with this gatsbyLoader(expoLoader(jsCode)) setup?

The problems I see:

  • It might be complex to merge expo loader into gatsby loader.
  • the Expo Webpack config should also be easy to apply to other frameworks as well (NextJS, CRA, Electron...)

@slorber For static queries in Gatsby, we have a two part process.

  1. Traverse directories, find queries, write results
  2. Use babel-plugin-remove-graphql-queries in our babel-loader to remove these queries from code so that they don't end up in the final assets.

What's happening here is that your instance of babel-loader doesn't include this plugin and hence those queries (and calls associated to graphql) aren't being removed.

Adding that plugin over should fix this.

I would however honestly recommend keeping Gatsby's instance of babel loader if possible and merging into it the stuff you'd like to add.

Thanks @sidharthachatterjee I thought if I did that maybe Gatsby wouldn't run the queries to collect the data, but if this is done as a first step, great then.

What's the risk of having 2 babel loaders? We might try to merge in the future but will try to see first if I can't get a first working version with 2 loaders.

So I've been able to make a static build!

The Expo loader does use babel.config.js if present so I added:

module.exports = function(api) {
  api.cache(true);
  return {
    presets: ["babel-preset-expo"],
    plugins: [["babel-plugin-remove-graphql-queries",{},"test-name"]]
  };
};

and it works

I had to alias the babel plugin because of this error, a bit surprised because the plugin would be used by 2 distinct loaders:

Generating JavaScript bundles failed

Duplicate plugin/preset detected.
If you'd like to use two separate instances of a plugin,
they need separate names, e.g.

  plugins: [
    ['some-plugin', {}],
    ['some-plugin', {}, 'some unique name'],
  ]

Duplicates detected are:
[
  {
    "alias": "/Users/sebastienlorber/Desktop/expo-examples/with-gatsby/node_modules/babel-plugin-remove-graphql-queries/index.js",
    "dirname": "/Users/sebastienlorber/Desktop/expo-examples/with-gatsby",
    "ownPass": false,
    "file": {
      "request": "babel-plugin-remove-graphql-queries",
      "resolved": "/Users/sebastienlorber/Desktop/expo-examples/with-gatsby/node_modules/babel-plugin-remove-graphql-queries/index.js"
    }
  },
  {
    "alias": "/Users/sebastienlorber/Desktop/expo-examples/with-gatsby/node_modules/babel-plugin-remove-graphql-queries/index.js",
    "dirname": "/Users/sebastienlorber/Desktop/expo-examples/with-gatsby",
    "file": {
      "request": "/Users/sebastienlorber/Desktop/expo-examples/with-gatsby/node_modules/babel-plugin-remove-graphql-queries/index.js",
      "resolved": "/Users/sebastienlorber/Desktop/expo-examples/with-gatsby/node_modules/babel-plugin-remove-graphql-queries/index.js"
    }
  }
]

Not sure it's very reliable but at least it works.

@slorber's solution worked for me.

yarn add --dev babel-plugin-remove-graphql-queries

babel.config.js

module.exports = function(api) {
  api.cache(true)
  return {
    presets: ['babel-preset-expo'],
+    plugins: [['babel-plugin-remove-graphql-queries', {}, 'test-name']],
  }
}

I'm not familiar with how babel works, though, so I don't know what the downsides of this approach are.

even adding the plugin babel-plugin-remove-graphql-queries it's still not working, getting the same error about the graphql query not being compiled away.

how did you add it? any repro to share?

I'll make sure the plugin automatically adds the required babel plugin soon so that it's less painful to setup

Added it to babel.config.js like others have done above, but no luck. Let me try and set up a repro

sorry this took so long, here's my repro test case: https://github.com/tamagokun/gatsby-rnw-repro

clone repo, run yarn then yarn docs all seems to go well, until the browser launches and I get the same error screen as the top of the issue.

Hi @tamagokun

Your repro does not look much like a gatsby site to me, you don't even have gatsby in dependencies nor any pages folder. And there is a "docz" command.

If you are looking for a good starting point you can copy this folder: https://github.com/slorber/examples/tree/master/with-gatsby

So far it's the only site that I know of that is working correctly with v3 of this plugin (which is still a bit new and not really production ready)

You can also see a working app in the example folder of this repo: https://github.com/nandorojo/expo-gatsby-navigation

Hi @tamagokun

Your repro does not look much like a gatsby site to me, you don't even have gatsby in dependencies nor any pages folder. And there is a "docz" command.

If you are looking for a good starting point you can copy this folder: https://github.com/slorber/examples/tree/master/with-gatsby

So far it's the only site that I know of that is working correctly with v3 of this plugin (which is still a bit new and not really production ready)

that's right, it's a docz project, which uses Gatsby. After running yarn docs docz generates a gatsby site within a .docz folder in the project root. This might be able to shed some light on what may be going wrong. Though, I confess my repro might be difficult to track down with the indirection of a different library that uses Gatsby.

@tamagokun maybe you should put the babel config directly in the .docz subfolder then. I don't know about docs, I can check the docz site structure generated if you commit it (maybe it's not a best practice to commit it anyway?)

Anyway, will try to see how to avoid needing this babel config file and will let you know when it's ready, hopefully I'll have time to work on this next week.

That's probably the fix then, I'll go down that route and see how I do.

Hi,

Just published an update, you shouldn't need anymore to add babel-plugin-remove-graphql-queries in 3.0.0-beta.6 as it will be added automatically for you, so no need for having a local babel.config.js file

I'm actually trying to use docz to add docs to my own project too, and running into the same problem. The solutions mentioned here worked fine in my normal gatsby/expo example app, but when I run yarn docz dev, I get OP's error.

Interestingly, if I build the gatsby project and serve it (using yarn docz build && yarn docz serve), it works fine. I'll see if I can figure out why.

Thanks for your help @slorber!

Just tested the latest beta (6), and it still is a problem. This very well may be with something that docz is doing that is conflicting with babel.

https://github.com/tamagokun/gatsby-rnw-repro/tree/master/.docz

^ that's the gatsby project

https://github.com/tamagokun/gatsby-rnw-repro/blob/master/.docz/.cache/dev-404-page.js#L137-L145

^ this seems to be the code in question that didn't get compiled away in babel

thanks, will try to see what I can do using your repro.

Not sure I tried with a page query yet, just static queries, that may be the problem.

Never used docz but that'll be the good time to test it ;) would be cool if Expo did run there too, as RN lib authors could probably document their lib with a web widget embedded into the doc.

What's your usecase for using docz with this plugin?

So, good news is that it's definitively possible to make it work with docz, in both dev and prod.
Here's a deployment: https://goofy-carson-fc4758.netlify.com/src-components-button

Bad news is there is a bug that seems related to the nested structure of docz.

This fragile function does not return the expo js loader but another one:

const getExpoJsLoader = config => {
  const {
    conditionMatchesFile,
    getRules
  } = require('@expo/webpack-config/utils');

  const {
    resolve,
    join
  } = require('path');

  const rules = getRules(config);
  const jsLoaders = rules.filter(({
    rule
  }) => rule.test && conditionMatchesFile(rule, resolve(join(__dirname, '../..', 'foo.js')))); 

// expo js loader is normally last added js loader (fragile but works)

  const expoJsLoader = jsLoaders[jsLoaders.length - 1];

  return expoJsLoader
};

@EvanBacon do you think there's a more reliable way you could expose to modify existing expo js loader?

That's just what I needed! I got it working. How's this for finding the expo loader?

const expoJsLoader = rules
  .filter(rule => !!rule.rule && rule.rule.use)
  .find(({ rule }) => {
    const loaders = [].concat(rule.use);
    return !!loaders.find(
      loader =>
        loader.options &&
        loader.options.presets &&
        loader.options.presets.filter(presetPath => presetPath.match(/babel-preset-expo/))
          .length > 0
    );
  });

I've published beta7 with a fix.

Honestly not sure what's the safest way to identify the expo js loader.
I've used the trick @EvanBacon suggested here: expo/examples#39 (comment)

Just added the .docz path as a folder to try resolve in:

// Temporary until better api is provided to get/customize expo js loader
// See https://github.com/expo/examples/pull/39#discussion_r367702217
const getExpoJsLoaderRule = config => {
  const {
    conditionMatchesFile,
  } = require('@expo/webpack-config/utils')
  const { resolve, join } = require('path')

  const rules = config.module.rules

  // TODO bad way to find js loaders...
  const jsLoaders = rules.filter(rule => {
    if (rule.test) {
      const relativeFoldersToTry = [
        '../..',
        '../../.docz', // Needed for Docz, as it has a nested structure
      ]
      return relativeFoldersToTry.some(relativeFolder =>
        conditionMatchesFile(
          rule,
          resolve(join(__dirname, relativeFolder, 'foo.js'))
        )
      )
    }
    return false
  })

  // TODO bad way to find expo loaders among js loaders...
  // expo js loader is normally last added js loader (fragile, but works)
  const expoJsLoader = jsLoaders[jsLoaders.length - 1]

  // console.log("expoJsLoader",JSON.stringify(expoJsLoader,null,2));
  return expoJsLoader
}

The babel loader is:

https://github.com/expo/expo-cli/blob/master/packages/webpack-config/src/loaders/createBabelLoader.ts#L126

If user has a babel.config.json, it will read from that directly. The rule may just be

{
    // Explicitly use babel.config.js instead of .babelrc
    babelrc: false,
    // Attempt to use local babel.config.js file for compiling project.
    configFile: true,
  };

So looking at the expo preset will not work in such case because.

hmm, I wondered about that, but figured since it is a webpack config it would be populated with the presets properly. Darn.

just confirmed it working with beta7. Thanks for the help!

hmm, I wondered about that, but figured since it is a webpack config it would be populated with the presets properly. Darn.

Actually some will likely use the same folder to build both a mobile Expo app, and the gatsby website, in such case it's possible there will be a local babel config (even if it's unusual in Gatsby land)

just confirmed it working with beta7. Thanks for the help!

Awesome, so I'm closing.

Let me know if you build something meaningful with this plugin

@slorber found something that might be of use:

Gatsby includes a config.context in the webpack config, which is the path to the gatsby project, so in the case of a docz project:

exports.onCreateWebpackConfig = ({ getConfig }) => {
  const config = getConfig();
  console.log(config.context); // /Users/mkruk/dev/docz-project/.docz
}

thanks that can be useful to have something more generic ;)