strapi / starters-and-templates

Monorepo for all official Strapi v4 templates
MIT License
321 stars 114 forks source link

Gatsby Blog starter fails frontend #38

Open notmattmonroe opened 2 years ago

notmattmonroe commented 2 years ago

Both approaches outlined in the doc for running the start successfully build and start the backend but fail to build the frontend.

OSX 12.1

node -v v16.14.2

yarn -v 1.22.18

NPX output npx.txt

YARN output yarn.txt

The Next Blog starter works fine with either approach

nzsg commented 2 years ago

Same issue here on MacOS 12.3.1

I found 2 issues.

  1. Something in the setup doesn't seem to like localhost. Replacing localhost with 127.0.0.1 let the connection to Strapi work.

  2. After the backend builds, the frontend tries to build but there is no .env.development with the API token configured so the frontend fails.

Creating a Strapi API token and setting the API endpoint to 127.0.0.1 in .env.development got me going. Hope this helps someone.

notmattmonroe commented 2 years ago

Yea, adding in the .env.development in the frontend project with API token resolved it. Documentation should be updated to reflect that step.

remidej commented 2 years ago

Yes the problem is that create-strapi-starter is not able to generate the API token required. It's mentioned in the readme:

You will however need to manually create a full access API token in Strapi. Once it's created, save it as STRAPI_TOKEN in your environment variables.

connerxyz commented 2 years ago

Adding a bit of detail here...

Attempting to use the Gatsby blog starter as documented here via npx didn't work.

The command is: npx create-strapi-starter my-project gatsby-blog

The error produced is:

ModuleNotFoundError: Module not found: Error: Can't resolve '../../public/page
[develop:frontend]   -data/sq/d/960431041.json'...

Work around:

Here's how I was able to get it to work.

1) Launch Strapi backend using npm run --prefix backend develop, which allowed me to create the admin initial account.

2) With the admin panel working, create a full-access API token.

3) Add frontend/.env.development with STRAPI_TOKEN and STRAPI_API_URL like this

STRAPI_TOKEN=5c9e945085...
STRAPI_API_URL=http://localhost:1337

4) Then Gatsby using npm run --prefix frontend develop

My system:

Jordan1022 commented 2 years ago

My frontend is failing as well but error is a little different:

Screen Shot 2022-06-03 at 11 56 26 AM Screen Shot 2022-06-03 at 11 57 41 AM

There are more errors similar to this one

Jordan1022 commented 2 years ago

Scratch that. @connerxyz was right. Went the route of running BE and getting the API key etc and now I'm up and running. Thanks!

jvmontes commented 2 years ago

@Jordan1022 @connerxyz I'm seeing the same issue and wasn't able to get a resolution..

I also followed the starter by running npx create-strapi-starter my-project gatsby-blog

Then I ran @connerxyz's work around and got this error below

 ERROR #11321  PLUGIN

"gatsby-source-strapi" threw an error while running the sourceNodes lifecycle:

connect ECONNREFUSED ::1:1337

  Error: connect ECONNREFUSED ::1:1337

  - node:net:1161 TCPConnectWrap.afterConnect [as oncomplete]
    node:net:1161:16

warn The gatsby-source-strapi plugin has generated no Gatsby nodes. Do you need it? This could also suggest the plugin is misconfigured.

This issue was also happening when I was simply trying to get Strapi connected to another app. I'd be very thankful for any help!

chadwcarlson commented 1 year ago

@jvmontes I found that the backend needs the following to get this starter to work.

I've found that replacing backend/src/bootstrap.js with the below fixes things on first startup. It will create the API token (setInitFrontendAPIToken) and match those permissions for you (setInitPermissions), saving the token to frontend/env.development.

// backend/src/bootstrap.js

"use strict";

const fs = require("fs-extra");
const path = require("path");
const mime = require("mime-types");
const set = require("lodash.set");
const {
  categories,
  authors,
  articles,
  global,
  about,
} = require("../data/data.json");

async function isFirstRun() {
  const pluginStore = strapi.store({
    environment: strapi.config.environment,
    type: "type",
    name: "setup",
  });
  const initHasRun = await pluginStore.get({ key: "initHasRun" });
  await pluginStore.set({ key: "initHasRun", value: true });
  return !initHasRun;
}

async function setInitPermissions(roleType, newPermissions) {
  // Find the ID of the role
  const role = await strapi
    .query("plugin::users-permissions.role")
    .findOne({
      where: {
        type: roleType,
      },
    });

  // Create the new permissions and link them to the role
  const allPermissionsToCreate = [];
  Object.keys(newPermissions).map((controller) => {
    const actions = newPermissions[controller];
    const permissionsToCreate = actions.map((action) => {
      return strapi.query("plugin::users-permissions.permission").create({
        data: {
          action: `api::${controller}.${controller}.${action}`,
          role: role.id,
        },
      });
    });
    allPermissionsToCreate.push(...permissionsToCreate);
  });
  await Promise.all(allPermissionsToCreate);
}

async function setInitFrontendAPIToken(attributes) {
  const apiTokenService = strapi.service(`admin::api-token`);
  const apiToken = await apiTokenService.create(attributes);
  const accessKey = apiToken.accessKey;
  const credentialsLocation = process.env.FRONTEND_ENV_LOCATION || "frontend/.env.development"
  fs.writeFile(credentialsLocation, `STRAPI_TOKEN=${accessKey}`, function (err) {
    if (err) return console.log(err);
    console.log('Frontend .env file updated.');
  });
}

function getFileSizeInBytes(filePath) {
  const stats = fs.statSync(filePath);
  const fileSizeInBytes = stats["size"];
  return fileSizeInBytes;
}

function getFileData(fileName) {
  const filePath = path.join("data", "uploads", fileName);
  // Parse the file metadata
  const size = getFileSizeInBytes(filePath);
  const ext = fileName.split(".").pop();
  const mimeType = mime.lookup(ext);

  return {
    path: filePath,
    name: fileName,
    size,
    type: mimeType,
  };
}

async function uploadFile(file, name) {
  return strapi
    .plugin("upload")
    .service("upload")
    .upload({
      files: file,
      data: {
        fileInfo: {
          alternativeText: `An image uploaded to Strapi called ${name}`,
          caption: name,
          name,
        },
      },
    });
}

// Create an entry and attach files if there are any
async function createEntry({ model, entry }) {
  try {
    // Actually create the entry in Strapi
    await strapi.entityService.create(`api::${model}.${model}`, {
      data: entry,
    });
  } catch (error) {
    console.error({ model, entry, error });
  }
}

async function checkFileExistsBeforeUpload(files) {
  const existingFiles = [];
  const uploadedFiles = [];
  const filesCopy = [...files];

  for (const fileName of filesCopy) {
    // Check if the file already exists in Strapi
    const fileWhereName = await strapi.query("plugin::upload.file").findOne({
      where: {
        name: fileName,
      },
    });

    if (fileWhereName) {
      // File exists, don't upload it
      existingFiles.push(fileWhereName);
    } else {
      // File doesn't exist, upload it
      const fileData = getFileData(fileName);
      const fileNameNoExtension = fileName.split('.').shift()
      const [file] = await uploadFile(fileData, fileNameNoExtension);
      uploadedFiles.push(file);
    }
  }
  const allFiles = [...existingFiles, ...uploadedFiles];
  // If only one file then return only that file
  return allFiles.length === 1 ? allFiles[0] : allFiles;
}

async function updateBlocks(blocks) {
  const updatedBlocks = [];
  for (const block of blocks) {
    if (block.__component === "shared.media") {
      const uploadedFiles = await checkFileExistsBeforeUpload([block.file]);
      // Copy the block to not mutate directly
      const blockCopy = { ...block };
      // Replace the file name on the block with the actual file
      blockCopy.file = uploadedFiles;
      updatedBlocks.push(blockCopy);
    } else if (block.__component === "shared.slider") {
      // Get files already uploaded to Strapi or upload new files
      const existingAndUploadedFiles = await checkFileExistsBeforeUpload(
        block.files
      );
      // Copy the block to not mutate directly
      const blockCopy = { ...block };
      // Replace the file names on the block with the actual files
      blockCopy.files = existingAndUploadedFiles;
      // Push the updated block
      updatedBlocks.push(blockCopy);
    } else {
      // Just push the block as is
      updatedBlocks.push(block);
    }
  }

  return updatedBlocks;
}

async function importArticles() {
  for (const article of articles) {
    const cover = await checkFileExistsBeforeUpload([`${article.slug}.jpg`]);
    const updatedBlocks = await updateBlocks(article.blocks);

    await createEntry({
      model: "article",
      entry: {
        ...article,
        cover,
        blocks: updatedBlocks,
        // Make sure it's not a draft
        publishedAt: Date.now(),
      },
    });
  }
}

async function importGlobal() {
  const favicon = await checkFileExistsBeforeUpload(["favicon.png"]);
  const shareImage = await checkFileExistsBeforeUpload(["default-image.png"])
  return createEntry({
    model: "global",
    entry: {
      ...global,
      favicon,
      // Make sure it's not a draft
      publishedAt: Date.now(),
      defaultSeo: {
        ...global.defaultSeo,
        shareImage
      }
    },
  });
}

async function importAbout() {
  const updatedBlocks = await updateBlocks(about.blocks);

  await createEntry({
    model: "about",
    entry: {
      ...about,
      blocks: updatedBlocks,
      // Make sure it's not a draft
      publishedAt: Date.now(),
    },
  });
}

async function importCategories() {
  for (const category of categories) {
    await createEntry({ model: "category", entry: category });
  }
}

async function importAuthors() {
  for (const author of authors) {
    const avatar = await checkFileExistsBeforeUpload([author.avatar]);

    await createEntry({
      model: "author",
      entry: {
        ...author,
        avatar,
      },
    });
  }
}

async function importSeedData() {

  // Initial demo permissions.
  const initPermissions = {
    article: ["find", "findOne"],
    category: ["find", "findOne"],
    author: ["find", "findOne"],
    global: ["find", "findOne"],
    about: ["find", "findOne"],
  }

  // Initialize public permissions.
  await setInitPermissions("public", initPermissions)

  // Initialize authenticated permissions.
  await setInitPermissions("authenticated", initPermissions)

  // Creating initial demo API token for the frontend.
  await setInitFrontendAPIToken({
    type: 'full-access',
    name: 'full-access-demo',
    description: 'Initial frontend demo token'
  })

  // Create all entries
  await importCategories();
  await importAuthors();
  await importArticles();
  await importGlobal();
  await importAbout();
}

module.exports = async () => {
  const shouldImportSeedData = await isFirstRun();

  if (shouldImportSeedData) {
    try {
      console.log("Setting up the template...");
      await importSeedData();
      console.log("Ready to go");
    } catch (error) {
      console.log("Could not import seed data");
      console.error(error);
    }
  }
};
jvmontes commented 1 year ago

@chadwcarlson thank you!

So, here's what I had to do to get my app up and running.

Follow @connerxyz 's work around. Before hitting step 4:

npm run --prefix frontend develop

I follow @chadwcarlson lead and replace backend/src/bootstrap.js with his update.

Thanks, finally can see the blog welcome screen! Cheers

AminSarafraz commented 1 year ago

@connerxyz workaround worked for me. If you are using yarn instead of npm, while in your main project directory, your commands will become:

yarn --cwd backend develop yarn --cwd frontend develop

lancesnider commented 1 year ago

None of these have helped me. I'm using the starter out of the box, but I'm still getting:

Error: connect ECONNREFUSED ::1:1337

I've tried everything mentioned here and in other threads:

I'm feeling pretty stuck at this point.

red1 commented 1 year ago

I've the same issues guys, So I generated a full access token, and updated my strapi endpoint url to

STRAPI_TOKEN=128b964c... a9109424
STRAPI_API_URL=http://localhost:1337

Now i'm not anymore stuck on the 403 but I've got the following error


 ERROR #85923  GRAPHQL

There was an error in your GraphQL query:

Cannot query field "strapiGlobal" on type "Query".

If you don't expect "strapiGlobal" to exist on the type "Query" it is most likely a typo. However, if you expect "strapiGlobal" to exist there are
 a couple of solutions to common problems:

- If you added a new data source and/or changed something inside gatsby-node/gatsby-config, please try a restart of your development server.
- You want to optionally use your field "strapiGlobal" and right now it is not used anywhere.

It is recommended to explicitly type your GraphQL schema if you want to use optional fields.

File: src/components/seo.js:8:7

See our docs page for more info on this error: https://gatsby.dev/creating-type-definitions

for all templates of the starter kit : about.js, ... Is this starter code really supposed to work ?

red1 commented 1 year ago

nevermind I found the issue when I looked at the global api -> 404 : http://localhost:1337/api/global So I looked and found the site to configure in the admin UI : http://localhost:1337/admin/content-manager/singleType/api::global.global and the about stuff as well

hoseindoran commented 1 year ago

I've the same issues guys, So I generated a full access token, and updated my strapi endpoint url to

STRAPI_TOKEN=128b964c... a9109424
STRAPI_API_URL=http://localhost:1337

Now i'm not anymore stuck on the 403 but I've got the following error


 ERROR #85923  GRAPHQL

There was an error in your GraphQL query:

Cannot query field "strapiGlobal" on type "Query".

If you don't expect "strapiGlobal" to exist on the type "Query" it is most likely a typo. However, if you expect "strapiGlobal" to exist there are
 a couple of solutions to common problems:

- If you added a new data source and/or changed something inside gatsby-node/gatsby-config, please try a restart of your development server.
- You want to optionally use your field "strapiGlobal" and right now it is not used anywhere.

It is recommended to explicitly type your GraphQL schema if you want to use optional fields.

File: src/components/seo.js:8:7

See our docs page for more info on this error: https://gatsby.dev/creating-type-definitions

for all templates of the starter kit : about.js, ... Is this starter code really supposed to work ?

I have the same issue I generate a full access token API, but I got error what should I do?

lancesnider commented 1 year ago

3 of us spent a week on this issue with no luck. In the end we went with Contenful. :( Too bad because Strapi seemed to fit our needs better.

hoseindoran commented 1 year ago

I want use strapi in my project :( I tested all of solutions above, but did not fix. I don't know doing really

lancesnider commented 1 year ago

I want use strapi in my project :( I tested all of solutions above, but did not fix. I don't know doing really

I don't think the problem is you. 🤷

red1 commented 1 year ago

You need to fill up the site info in the global collection from the admin ui

Le dim. 29 janv. 2023 à 20:12, Lance Snider @.***> a écrit :

I want use strapi in my project :( I tested all of solutions above, but did not fix. I don't know doing really

I don't think the problem is you. 🤷

— Reply to this email directly, view it on GitHub https://github.com/strapi/starters-and-templates/issues/38#issuecomment-1407746003, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAA4SWQTGHEO3D4RLCGZWP3WU26JNANCNFSM5T2W3VGA . You are receiving this because you commented.Message ID: @.***>

hoseindoran commented 1 year ago

Global is in the single types category, its fill by default

lancesnider commented 1 year ago

I filled mine as well.

nullRefErr commented 1 year ago

Adding a bit of detail here...

Attempting to use the Gatsby blog starter as documented here via npx didn't work.

The command is: npx create-strapi-starter my-project gatsby-blog

The error produced is:

ModuleNotFoundError: Module not found: Error: Can't resolve '../../public/page
[develop:frontend]   -data/sq/d/960431041.json'...

Work around:

Here's how I was able to get it to work.

  1. Launch Strapi backend using npm run --prefix backend develop, which allowed me to create the admin initial account.
  2. With the admin panel working, create a full-access API token.
  3. Add frontend/.env.development with STRAPI_TOKEN and STRAPI_API_URL like this
STRAPI_TOKEN=5c9e945085...
STRAPI_API_URL=http://localhost:1337
  1. Then Gatsby using npm run --prefix frontend develop

My system:

  • MacOS Catalina 10.15.7
  • Node v16.13.1
  • NPX 8.1.2
  • NVM 0.33.11

fixed my issue

hoseindoran commented 1 year ago

I filled mine as well.

I downgrade strapi version to 4.0.0 then its worked for me

Alex-Van-Dijck commented 1 year ago

I keep getting

GraphQLError: Unknown type "STRAPICOMPONENT_SHARED_MEDIA". Did you mean "STRAPICOMPONENT_SH ARED_SEO", "STRAPICOMPONENT_SHARED_QUOTE", "STRAPICOMPONENT_SHARED_SEOEdge", "STRAPICOMPO NENT_SHARED_SLIDER", or "STRAPICOMPONENT_SHARED_QUOTEEdge"?

upon executing my page query's but can't seem to find the cause.

devsWecreate commented 1 year ago

@Alex-Van-Dijck I am having the same error, any progress?

Alex-Van-Dijck commented 1 year ago

@Alex-Van-Dijck I am having the same error, any progress?

Yes, had to work with another blog template without strapi sad enough.

devsWecreate commented 1 year ago

@Alex-Van-Dijck thank you for your quick feedback. Yes very sad. Normally we use Gatsby/Strapi or WP or Laravel, without GraphQl, with Rest API, I wanted to jump to GraphQL, but only it is giving a problems, so sad.

devsWecreate commented 1 year ago

@Alex-Van-Dijck I fixed, and it works for me in the about.js file,

const { strapiAbout } = useStaticQuery(graphql query { strapiAbout { title blocks { ...Blocks } } } )

Change about for strapiAbout

ionurboz commented 4 months ago

03.17.2024 and we haven't any solution?

red1 commented 4 months ago

I've switched to nextjs far better and easier to customize

Le dim. 17 mars 2024, 11:13, Onur @.***> a écrit :

03.17.2024 and we haven't any solution?

— Reply to this email directly, view it on GitHub https://github.com/strapi/starters-and-templates/issues/38#issuecomment-2002393271, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAA4SWSZF2TNLVNGXFUR7RTYYVUEZAVCNFSM5T2W3VGKU5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TEMBQGIZTSMZSG4YQ . You are receiving this because you commented.Message ID: @.***>