I'm following this tutorial so that I generate a static file during the vercel build. I've tried moving the files around but it always shows a log like:
23:41:48.432 $ node ./pages/api/build.js 23:41:48.493 Build time file created successfully! 23:41:48.495 Done in 0.09s. 23:41:48.507 Error: A "routes-manifest.json" couldn't be found. This is normally caused by a misconfiguration in your project.
Then it links to this. I've checked the issues and everything seems to be fine.
If I remove the "vercel-build": "node ./pages/api/build.js" line from package.json, the error disappears. But also the functionality..
my pages/api/index.js file:
const BuiltTime = require('./built-time');
module.exports = (req, res) => {
res.setHeader('content-type', 'text/plain');
res.send(`
This Serverless Function was built at ${new Date(BuiltTime)}.
The current time is ${new Date()}
`);
};
my pages/build.js:
const fs = require('fs');
fs.writeFile(
'pages/api/built-time.js',
`module.exports = '${new Date()}'`,
(err) => {
if (err) throw err;
console.log('Build time file created successfully!');
}
);
my package.json:
{
...
"scripts":{
"vercel-build": "node ./pages/api/build.js",
}
}
In the end I didn't use "vercel-build". I just run a script before the build:
// package.json
{
"scripts": {
"make-q": "node ./build.js",
"build": "yarn run make-q && next build",
}
The build file can't use import or call typescript files (at least for now):
// build.js
const slugify = require('./utils/slugify');
const fs = require('fs');
const qs = slugify('some string');
fs.writeFile(
'questionsDB.js',
`module.exports = ${JSON.stringify(qs, null, 2)}`,
(err) => {
if (err) throw err;
console.log('file created successfully!');
}
);
Finally, inside the pages/api/test.js:
const db = require('../../db');
module.exports = (req, res) => {
res.setHeader('content-type', 'text/plain');
res.send(`
working:
${db}
`);
};
Now, if I call url/api/test I get the result based on the build.
Things I tried that failed:
Different node version
Update nextjs
remove yarn.lock and build again
Related
Hey I am trying to unit test this cloud function right here:
import { logger, region, https } from "firebase-functions/v1";
import Message from "../types/message";
const helloWorldHandler = region("europe-west1").https.onCall((_, context) => {
if (context.app == undefined) {
throw new https.HttpsError("failed-precondition", "The function must be called from an App Check verified app.");
}
logger.info("Hello logs!", { structuredData: true });
const message: Message = {
text: "Hello from Firebase!",
code: 200,
};
return message;
});
export default helloWorldHandler;
with the following test:
import * as functions from "firebase-functions-test";
import * as path from "path";
const projectConfig = {
projectId: "myproject-id",
};
const testEnv = functions(projectConfig, path.resolve("./flowus-app-dev-fb-admin-sdk-key"));
// has to be after initializing functions
import helloWorldHandler from "../src/functions/helloworld";
import Message from "../src/types/message";
describe('Testing "helloWorld"', () => {
const helloWorld = testEnv.wrap(helloWorldHandler);
it("helloWorld does work", async () => {
const data = {};
const success: Message = await helloWorld(data);
expect(success.code).toBe(200);
});
});
When I run it with yarn test I receive the following error
Cannot find module 'firebase-functions/lib/encoder' from 'node_modules/firebase-functions-test/lib/providers/firestore.js'
Even though my function does not even use firestore in the first place?
Any ideas ?
I was facing a similar issue while trying to set up a unit testing environment for firebase cloud functions.
Mainly, after following all the steps on Firebase's docs, and running npm test
I would get the following error
Error [ERR_PACKAGE_PATH_NOT_EXPORTED] Package subpath './lib/encoder'
is not defined by "exports"
After stumbling on Farid's suggestion for this problem, I realized that, for some reason, npm i firebase-functions-test does not install the latest version of the module.
Try npm i firebase-functions-test#latest.
I am trying to deploy a delete function into the firebase cloud functions but then I get this error Error: Functions did not deploy properly. I have installed all the dependences e.g firebase-tools. Some of the steps I went through setting up the project are in these:
This is the code I am trying to deploy:
const admin = require('firebase-admin');
const firebase_tools = require('firebase-tools');
const functions = require('firebase-functions');
admin.initializeApp();
exports.mintAdminToken = functions.https.onCall(async (data, context) => {
const uid = data.uid;
const token = await admin
.auth()
.createCustomToken(uid, { admin: true });
return { token };
});
exports.recursiveDelete = functions
.runWith({
timeoutSeconds: 540,
memory: '2GB'
})
.https.onCall(async (data, context) => {
// Only allow admin users to execute this function.
if (!(context.auth && context.auth.token && context.auth.token.admin)) {
throw new functions.https.HttpsError(
'permission-denied',
'Must be an administrative user to initiate delete.'
);
}
const path = data.path;
console.log(
`User ${context.auth.uid} has requested to delete path ${path}`
);
// Run a recursive delete on the given document or collection path.
// The 'token' must be set in the functions config, and can be generated
// at the command line by running 'firebase login:ci'.
await firebase_tools.firestore
.delete(path, {
project: process.env.GCLOUD_PROJECT,
recursive: true,
yes: true,
token: functions.config().fb.token
});
return {
path: path
};
});
As from the comments, running the following solved the problem
npm install firebase-functions#latest firebase-admin#latest --save
npm install -g firebase-tools
I need my app to work well on a subfolder of the main domain. Exactly here
At first I had a plenty of errors of scripts, css and images not being loaded.
I added the following to next.config.js:
basePath: "/out",
Now scripts and css are working well when exported, they have the /out/ in the path.
However the files do not have yet the /out/ in the path, thus they are giving 404 errors.
I tried to follow this tutorial, but it looks like I am still doing something wrong,
My next.config.js now is:
const path = require("path");
module.exports = {
trailingSlash: true,
sassOptions: {
includePaths: [path.join(__dirname, "styles")],
},
basePath: "/out",
assetPrefix: process.env.BASE_PATH || '',
publicRuntimeConfig: {
basePath: process.env.BASE_PATH || '',
},
};
The relevant piece of the package.json is:
"scripts": {
"dev": "node server.js -p $PORT",
"build": "next build",
"prod": "BASE_PATH=/out next build && next export",
"start": "NODE_ENV=production node server.js -p $PORT",
"start2": "next start"
},
The server.js is:
const express = require('express');
const next = require('next');
const path = require('path');
const bodyParser = require('body-parser');
const keys = require("./server/config/keys");
const stripe = require('stripe')(keys.stripeSecretKey);
const routes = require('./routes');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dir: '.', dev });
const handle = routes.getRequestHandler(app);
app.prepare().then(() => {
const server = express();
// Static files
// https://github.com/zeit/next.js/tree/4.2.3#user-content-static-file-serving-eg-images
server.use('/images', express.static(path.join(__dirname, 'images'), {
maxAge: dev ? '0' : '365d'
}));
server.use(bodyParser.json());
server.get('*', (req, res) => {
return handle(req, res)
});
server.post('/api/stripe/checkout', async (req, res) => {
await stripe.charges.create({
amount: req.body.amount,
currency: 'usd',
description: 'Mojosa - React Next Landing Page Templates',
source: req.body.token.id
});
res.send({})
});
const PORT = process.env.PORT || 3000;
server.listen(PORT, (err) => {
if (err) throw err
console.log(`> Read on http://localhost:${PORT}`)
});
})
And here is an example of an image in a component:
<div className="col-lg-6 col-md-12">
<div className="book-image">
<img src='/images/book-img.png' alt="image" />
</div>
With this configuration:
EXPORT - next build && next export on the /out/ folder are working well when uploaded to the live website, BUT images are giving 404
DEV or BUILD they are giving 404 and working much worse than the EXPORT site published on the real domain. If I remove basePath: "/out", the dev mode works excellent
Questions:
How can I make the /out/ path be added to all the images/assets?
I am ok to re-add basePath: "/out",` when exporting.
Just ran into this one too. You'll need to manually prefix anything in your public folder with your basePath (images, fonts etc)
Docs
"Files in the public folder; if you want to serve those assets over a CDN, you'll have to introduce the prefix yourself"
<div className="col-lg-6 col-md-12">
<div className="book-image">
<img src={`${process.env.BASE_PATH}/images/book-img.png`} alt="image" />
</div>
Developing Google cloud functions locally.
Trying to test functions that invoke Firestore.
Here is a minimal example.
Emulators are running.
The function addMessage() works completely fine when invoked from the browser.
The function fails with error TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. when invoked from tests.
Question: Why is this error occurring and how can I invoke the Firestore function successfully from the tests?
functions/index.js:
require ('dotenv').config();
const functions = require ('firebase-functions');
const admin = require ('firebase-admin');
admin.initializeApp();
exports.addMessage = functions.https.onRequest (async (req, res) => {
const original = req.query.text;
const writeResult = await admin.firestore().collection ('messages').add ({text: original});
const docSnap = await writeResult.get();
const writtenText = docSnap.get ('text');
res.send (`Message with text: ${writtenText} added.`);
});
functions/test/index.test.js:
const admin = require ('firebase-admin');
const firebase_functions_test = require ('firebase-functions-test')({
projectId: 'my-project-id'
}, '/path/to/google-application-credentials.json');
const testFunctions = require ('../index.js');
describe ('addMessage()', () => {
it ('returns Message with text: Howdy added.', (done) => {
const req = {query: {text: 'Howdy'} };
const res = {
send: (body) => {
expect (body).toBe (`Message with text: Howdy added.`);
done();
}
};
testFunctions.addMessage (req, res);
});
});
Starting jest from functions folder:
(Among other test-related output):
FAIL test/index.test.js
● addMessage() › returns Message with text: Howdy added.
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type object
7 | exports.addMessage = functions.https.onRequest (async (req, res) => {
8 | const original = req.query.text;
> 9 | const writeResult = await admin.firestore().collection ('messages').add ({text: original});
| ^
10 | const docSnap = await writeResult.get();
11 | const writtenText = docSnap.get ('text');
12 | res.send (`Message with text: ${writtenText} added.`);
at GrpcClient.loadProto (node_modules/google-gax/src/grpc.ts:166:23)
at new FirestoreClient (node_modules/#google-cloud/firestore/build/src/v1/firestore_client.js:118:38)
at ClientPool.Firestore._clientPool.pool_1.ClientPool [as clientFactory] (node_modules/#google-cloud/firestore/build/src/index.js:326:26)
at ClientPool.acquire (node_modules/#google-cloud/firestore/build/src/pool.js:87:35)
at ClientPool.run (node_modules/#google-cloud/firestore/build/src/pool.js:164:29)
at Firestore.request (node_modules/#google-cloud/firestore/build/src/index.js:983:33)
at WriteBatch.commit_ (node_modules/#google-cloud/firestore/build/src/write-batch.js:496:48)
Caused by: Error:
at WriteBatch.commit (node_modules/#google-cloud/firestore/build/src/write-batch.js:415:23)
at DocumentReference.create (node_modules/#google-cloud/firestore/build/src/reference.js:283:14)
at CollectionReference.add (node_modules/#google-cloud/firestore/build/src/reference.js:2011:28)
at Object.<anonymous>.exports.addMessage.functions.https.onRequest (index.js:9:71)
at Object.addMessage (node_modules/firebase-functions/lib/providers/https.js:50:16)
at Object.done (test/index.test.js:17:19)
Environment:
"node": "10"
"firebase-admin": "^8.12.1",
"firebase-functions": "^3.7.0"
"firebase-functions-test": "^0.2.1",
"jest": "^25.5.4"
Solved by adding jest.config.js to functions/:
module.exports = {
testEnvironment: 'node'
};
Solution based on this (but NB I needed to place jest.config.js in functions/, not the project root).
Also tried this but appeared to do nothing.
Tests now run perfectly except that they end with a Jest error:
Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.
This seems to be harmless.
Thanks #gso_gabriel for the valuable links!
I'm received error with gatsby develop. It's very similar to this one: https://github.com/firebase/firebase-js-sdk/issues/2222, but I'm received error with gatsby develop, not with gatsby build. I did a lot of research but I can't find working solution.
At first I had a problem with gatsby build, like in this post: https://github.com/firebase/firebase-js-sdk/issues/2222, but I resolved it with custom onCreateWebpackConfig(you can find it below).
Stack:
- Gatsby
- Firebase(error probably with that)
- Redux
I'm also delete .cache and node_modules and install everything again, but it didn't work.
Error:
There was an error compiling the html.js component for the development server.
See our docs page on debugging HTML builds for help https://gatsby.dev/debug-html ReferenceError: IDBIndex is not defined
]);
86 |
> 87 | proxyRequestMethods(Index, '_index', IDBIndex, [
| ^
88 | 'get',
89 | 'getKey',
90 | 'getAll',
WebpackError: ReferenceError: IDBIndex is not defined
- idb.mjs:87 Module../node_modules/idb/lib/idb.mjs
node_modules/idb/lib/idb.mjs:87:1
- index.esm.js:1 Module../node_modules/#firebase/installations/dist/index.esm.js
node_modules/#firebase/installations/dist/index.esm.js:1:1
- index.esm.js:1 Module../node_modules/#firebase/analytics/dist/index.esm.js
node_modules/#firebase/analytics/dist/index.esm.js:1:1
- index.esm.js:1 Module../node_modules/firebase/analytics/dist/index.esm.js
node_modules/firebase/analytics/dist/index.esm.js:1:1
- index.ts:1 Module../src/firebase/index.ts
src/firebase/index.ts:1:1
- index.esm.js:32 emit
node_modules/#firebase/analytics/dist/index.esm.js:32:1
My gatsby-node file:
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
if (stage === 'build-html') {
actions.setWebpackConfig({
externals: getConfig().externals.concat(function(context, request, callback) {
const regex = /^#?firebase(\/(.+))?/;
if (regex.test(request)) {
return callback(null, `umd ${request}`);
}
callback();
}),
});
}
};
My firebase dependencies:
"#firebase/firestore-types": "^1.10.1",
"firebase": "^7.13.1",
"firebase-admin": "^8.10.0",
"firebase-functions": "^3.5.0",
"firebase-tools": "^7.16.1",
Firebase index file:
import firebase from 'firebase/app';
import 'firebase/firestore';
import 'firebase/auth';
import 'firebase/storage';
import 'firebase/analytics';
const firebaseConfig = {...};
firebase.initializeApp(firebaseConfig);
export const firestore = firebase.firestore();
export const auth = firebase.auth();
export const storage = firebase.storage();
Project repo: https://github.com/olafsulich/Projecty
Post on Github issues: https://github.com/firebase/firebase-js-sdk/issues/2946
Thanks in advance.
The following snippet will only work on build environment because of your condition (stage === 'build-html'):
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
if (stage === 'build-html') {
actions.setWebpackConfig({
externals: getConfig().externals.concat(function(context, request, callback) {
const regex = /^#?firebase(\/(.+))?/;
if (regex.test(request)) {
return callback(null, `umd ${request}`);
}
callback();
}),
});
}
};
Remove it and use it like this:
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
actions.setWebpackConfig({
externals: getConfig().externals.concat(function(context, request, callback) {
const regex = /^#?firebase(\/(.+))?/;
if (regex.test(request)) {
return callback(null, `umd ${request}`);
}
callback();
}),
});
};
Thank's a lot! It's working only on gatbsy develop, but now when I
want to build project, I get an error - TypeError: Cannot read
property 'concat' of undefined. You know how to solve it?
Regarding the new issue, you can follow a workaround in this topic, This is a common error in third-party modules in Gatsby when they try to reach a DOM element (usually window) that is not already defined when the app builds. So, you need to wait until window is defined. You can achieve this in two ways:
Instancing your firebase with a condition like this:
import firebase from '#firebase/app';
import '#firebase/auth';
import '#firebase/firestore';
import '#firebase/functions';
const config = {
... firebase config here
};
let instance;
export default function getFirebase() {
if (typeof window !== 'undefined') {
if (instance) return instance;
instance = firebase.initializeApp(config);
return instance;
}
return null;
}
Note the if (typeof window !== 'undefined') statement
By ignoring firebase module in you webpack configuration like shows their docs. In your gatsby-node.js:
exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
if (stage === "build-html") {
actions.setWebpackConfig({
module: {
rules: [
{
test: /bad-module/,
use: loaders.null(),
},
],
},
})
}
}
Replace bad module for firebase (or the package/folder name in node_modules). Leave the slashes since test is a regular expression rule
This snippet replaces your previous one that seems to throw an error in concat() function.
For those who wants to try the concat() resolution, this will be helpful too:
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
if (stage === 'build-html') {
actions.setWebpackConfig({
externals: getConfig().externals.concat((context, request, callback) => {
const regex = /^#?firebase(\/(.+))?/
// exclude firebase products from being bundled, so they will be loaded using require() at runtime.
if (regex.test(request)) {
return callback(null, `commonjs ${request}`) // <- use commonjs!
}
callback()
}),
})
}
}
Solved this problem!!
I'm using "gatsby": "^3.10.2", "firebase": "9.0.0-beta.6".
firebase needs to be set externals as commonjs.
gatsby-node.js:
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
if (stage === 'build-html') {
actions.setWebpackConfig({
externals: getConfig().externals.concat((context, request, callback) => {
const regex = /^#?firebase(\/(.+))?/
// exclude firebase products from being bundled, so they will be loaded using require() at runtime.
if (regex.test(request)) {
return callback(null, `commonjs ${request}`) // <- use commonjs!
}
callback()
}),
})
}
}
Please try this setting.