unexpected token error testing component with graphql - reactjs

I'm trying to test my components with jest. I'm using apollo client to query date from apollo server. I have follewed apollo client docs for testing queries, but without success.
I'm using nextjs and mongoDB with mongoose.
I'm getting this error:
FAIL components/organisms/createPost/CreatePost.test.jsx
● Test suite failed to run
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
Details:
/Users/eyub/Documents/Learning/Projects/lim/node_modules/uuid/dist/esm-browser/index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export { default as v1 } from './v1.js';
^^^^^^
SyntaxError: Unexpected token 'export'
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1796:14)
here is my component
export default function CreatePost({}) {
const [createPost] = useMutation(CREATE_POST, {
refetchQueries: [{ query: GET_USER }, 'getUserData'],
})
const sumbitHandler = (event) => {
event.preventDefault()
createPost({ variables: { text: event.target[0].value } })
event.target[0].value = ''
}
return (
<Component onSubmit={sumbitHandler}>
<textarea placeholder="What's happening?" />
<button>
<Icon icon={'add'} />
</button>
</Component>
)
}
here is my test:
import { MockedProvider } from '#apollo/client/testing'
import { CREATE_POST } from '#graphql/client/mutation'
import '#testing-library/jest-dom'
import { render } from '#testing-library/react'
import CreatePost from './CreatePost'
const newPostData = {
text: '',
}
const mocks = [
{
request: {
query: CREATE_POST,
variables: {
text: '',
},
},
result: { data: newPostData },
},
]
describe('<CreatePost />', () => {
test('mocking test pass', () => {
const component = render(
<MockedProvider mocks={mocks} addTypename={false}>
<CreatePost />
</MockedProvider>
)
component.debug()
})
})
here my jest config:
const nextJest = require('next/jest')
const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: './',
})
// Add any custom config to be passed to Jest
const customJestConfig = {
// Add more setup options before each test is run
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
// if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
moduleNameMapper: {
'^#components/(.*)$': '<rootDir>/components/$1',
'^#utils/(.*)$': '<rootDir>/utils/$1',
'^#graphql/(.*)$': '<rootDir>/graphql/$1',
},
collectCoverageFrom: ['./components/**/*.{js,jsx}'],
moduleDirectories: ['node_modules', '<rootDir>/'],
testEnvironment: 'jest-environment-jsdom',
}
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig)

Related

How to import react js file in electron main.js?

I am using react and electron building an electron app.
I am new to react and electron and I got a problem on how to import a function in react index.js to electron main.js
Why I need to import that function to main.js file?
Because I need to pass the dependencies of my react app from main.js and most of these dependecies are function dependencies.
Here is the function in index.js which receive the dependencies. Look at the function dependency
mport React from 'react';
import ReactDOM from 'react-dom/client';
import './App.scss'
import './configFile'
import './fonts/NotoSansSC.otf'
import { init as initConfigFile } from './configFile'
import { init as initLanguage } from './international/language'
import App from './App';
export function dependency(config, saveConfigFile, createNewUser) {
}
const root = ReactDOM.createRoot(document.getElementById('root'))
initLanguage()
initConfigFile({
parentPwd: null,
qa: {
'configQuestion1': '123',
'configQuestion2': '123',
'configQuestion3': '123'
},
timeRangesNotAllowToUseTheComputer: [
],
language: 'en',
onlyWorkForTheUsers: ['test'],
usernames: ['onTheRoad', 'test'],
timeZones: { '中国': 'cn', '英国': 'uk' },
choosedTimeZone: 'uk'
}, null, null)
root.render(
<App />
)
Here is the main.js file
const path = require('path');
const { app, BrowserWindow } = require('electron');
const isDev = require('electron-is-dev');
function createWindow() {
// Create the browser window.
const win = new BrowserWindow({
width: 800,
height: 800,
webPreferences: {
nodeIntegration: true,
},
});
// and load the index.html of the app.
// win.loadFile("index.html");
win.loadURL(`file://${path.join(__dirname, '../build/index.html')}`);
// Open the DevTools.
if (isDev) {
win.webContents.openDevTools({ mode: 'detach' });
}
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow);
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bars to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
I tried to import the file use require
const index = require('./index.js')
when I build the react app there is no error throwed but when I start the electron with electron . got error like this:
A JavaScript error occurred in the main process
Uncaught Exception:
/home/zxw/Desktop/bsd/src/index.js:1
import React from 'react';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Object.compileFunction (node:vm:352:18)
at wrapSafe (node:internal/modules/cjs/loader:1040:15)
at Module._compile (node:internal/modules/cjs/loader:1076:27)
at Module._extensions..js (node:internal/modules/cjs/loader:1175:10)
at Module.load (node:internal/modules/cjs/loader:988:32)
at Module._load (node:internal/modules/cjs/loader:829:12)
at c._load (node:electron/js2c/asar_bundle:5:13339)
at Module.require (node:internal/modules/cjs/loader:1012:19)
at require (node:internal/modules/cjs/helpers:102:18)
at Object.<anonymous> (/home/zxw/Desktop/bsd/public/main.js:4:15)
libva error: vaGetDriverNameByIndex() failed with unknown libva error, driver_name = (null)
And then I tried to load the function by import statement like below
import {dependency} from '../src/index'
When I build react app there is no error throwed but when I start the electron app I got error like this
A JavaScript error occurred in the main process
Uncaught Exception:
/home/zxw/Desktop/bsd/public/main.js:4
import {dependency} from '../src/index'
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Object.compileFunction (node:vm:352:18)
at wrapSafe (node:internal/modules/cjs/loader:1040:15)
at Module._compile (node:internal/modules/cjs/loader:1076:27)
at Module._extensions..js (node:internal/modules/cjs/loader:1175:10)
at Module.load (node:internal/modules/cjs/loader:988:32)
at Module._load (node:internal/modules/cjs/loader:829:12)
at c._load (node:electron/js2c/asar_bundle:5:13339)
at loadApplicationPackage (/home/zxw/Desktop/bsd/node_modules/electron/dist/resources/default_app.asar/main.js:121:16)
at Object.<anonymous> (/home/zxw/Desktop/bsd/node_modules/electron/dist/resources/default_app.asar/main.js:233:9)
at Module._compile (node:internal/modules/cjs/loader:1120:14)
libva error: vaGetDriverNameByIndex() failed with unknown libva error, driver_name = (null)
Is there is a way to pass the dependencies to the index.js from main.js ?
I fix it by throgh a dump way
First install the axios and the express
Then in the react src file add a file called appDependency
Here is the code
import axios from 'axios'
export function saveConfigFile(config) {
try {
axios.put('http://localhost:8888/config', config).then(response => {
if (response.status !== 200) {
throw response.data
}
})
} catch (e) {
console.error(`Error occrred while saving the config file: ${e}`)
throw e
}
}
export function createNewUser(username, pwd) {
try {
axios.post('http://localhost:8888/users', {
username: username,
pwd: pwd
}).then((response) => {
if (response.status !== 200) {
throw response.data
}
})
} catch (e) {
console.error(`Error occrred while creating new user. ${e}`)
throw e
}
}
async function fetchTheConfig() {
return await axios.get('http://localhost:8888/config').then((response) => {
console.log(`The response is ${JSON.stringify(response.data)}`)
if (response.status !== 200) {
throw response.data
} else {
return response.data
}
})
}
export function getConfigFile() {
try {
return fetchTheConfig()
} catch (e) {
console.error(`err occurred while fetching the config file. ${e}`)
throw e
}
}
And in the electron main.js file I use express created a server
const path = require('path');
const { app, BrowserWindow } = require('electron');
const express = require('express')
const exApp = express()
exApp.use(express.urlencoded())
exApp.use(express.json())
const config = {
parentPwd: null,
qa: {
'configQuestion1': '123',
'configQuestion2': '123',
'configQuestion3': '123'
},
timeRangesNotAllowToUseTheComputer: [
],
language: 'en',
onlyWorkForTheUsers: ['test'],
usernames: ['onTheRoad', 'test'],
timeZones: { '中国': 'cn', '英国': 'uk' },
choosedTimeZone: 'uk'
}
function configFile(req, res) {
console.log(`request received getConfigFile`)
res.status(200).send(config)
}
function saveConfigFile(req, res) {
console.log(`The body is ${req.body.timeRangesNotAllowToUseTheComputer}`)
res.status(200).send()
}
function createNewUser(req, res) {
console.log(`The req is `)
}
function appDependecys() {
exApp.get('/config', configFile)
exApp.put('/config', saveConfigFile)
exApp.post('/users', createNewUser)
exApp.listen(8888)
}
appDependecys()
In the react index.js I made the change to
import React from 'react';
import ReactDOM from 'react-dom/client';
import './App.scss'
import './configFile'
import './fonts/NotoSansSC.otf'
import { init as initConfigFile } from './configFile'
import { init as initLanguage } from './international/language'
import App from './App';
import { getConfigFile, saveConfigFile, createNewUser } from './appDependency'
const root = ReactDOM.createRoot(document.getElementById('root'))
getConfigFile().then((cfg) => {
console.log(`The fucking config is ${cfg}`)
initLanguage()
initConfigFile(cfg, saveConfigFile, createNewUser)
root.render(
<App />
)
})

Storybook re-renders story after receiving MSW response

When I trigger requests to the backend within a Storybook story, the story is re-rendered after receiving the response from Mock Service Worker (MSW). How can I prevent the re-rendering from happening?
Here's the story:
I followed the tutorial on https://storybook.js.org/addons/msw-storybook-addon to set up MSW for my Storybook stories.
So I:
installed msw and msw-storybook-addon
generated a service worker: npx msw init static/
updated my preview.js to call the initialize() function, added the mswDecorator, and set some global handlers (e. g. for "/api/customers")
When opening a component in Storybook that includes a request to "/api/customers" the following happens:
Initially MSW is telling me that it's enabled: [MSW] Mocking enabled.
I click a button to manually send a request to "/api/customers"
MSW is telling me that this API request is covered: [MSW] 15:21:20 GET /api/customers/ (200 OK)
I print the request results on the console - that works and I can see the expected results printed
But right after that the story is unintentionally re-rendered - this is what I want to suppress.
FF is telling me:
The connection to http://localhost:6006/__webpack_hmr was interrupted
while the page was loading.
Chrome doesn't give me that piece of information.
Here's the setup:
package.json:
{
...
"msw": {
"workerDirectory": "static"
}
}
main.js (Storybook):
// imports ...
const toPath = (filePath) => path.join(process.cwd(), filePath);
module.exports = {
core: {
builder: "webpack5",
},
stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.#(js|jsx|ts|tsx)"],
addons: [
"#storybook/addon-links",
"#storybook/addon-essentials",
],
features: {
emotionAlias: false,
},
webpackFinal: (config) => {
return {
...config,
module: {
...config.module,
rules: custom.module.rules, // rules how to handle file extensions
},
resolve: {
...config.resolve,
alias: {
...config.resolve.alias,
"#emotion/core": toPath("node_modules/#emotion/react"),
"emotion-theming": toPath("node_modules/#emotion/react"),
},
},
};
},
staticDirs: ["../path/to/static/"], // that's our public
};
Here's some code:
preview.js
export const parameters = {
...
msw: {
handlers: [
rest.get("/api/customers", (req, res, ctx) => {
let customers = ...;
return res(
ctx.json({
data: customers,
})
);
}),
],
},
}
ExampleStory.stories.jsx:
export default {
title: "Customers",
};
const getCustomers = () => {
// ... set axios config etc.
axios.get("/api/customers", config)
.then((response) => response.data.data)
.then((customers) => console.log(customers)); // yep, the customers gets printed!
};
export const ExampleStory = () => {
return (
<div>
Simple demo story
<button onClick={getCustomers}>Get customers</button>
</div>
);
};
Node Modules:
Storybook#6.5.9
msw#0.42.3
msw-storybook-addon#1.6.3

How to reset or clear the useQuery mocks of ApolloProvider before each single test?

I am having in one describe two test functions. They both use a component with apollo mocks as this component uses useQuery. But the response from mocks for each test should be different. Now I am unable to reset or clear mocks which I propagate to the ApolloProvider. Has anyone had this kind of issue? How did you solve it?
import React from 'react'
import { render, createMocks, screen, cleanup } from 'test-utils'
import GET_DEVICES from 'src/screens/dashboard/queries/GET_DEVICES'
import Section from './Section'
describe('DashboardScreen', () => {
const result = {
data: {
numDevices: 1
}
}
const mocks = createMocks([{
query: GET_DEVICES,
result: result,
}])
afterEach(() => {
jest.clearAllMocks() <------ THIS IS NOT SOLVING THE ISSUE
})
it('should load Section with expected badges', async () => {
render(<Section />, { mocks })
const badge0 = screen.getByTestId('Badge-0')
expect(badge0).toBeInTheDocument()
const badge1 = screen.getByTestId('Badge-1')
expect(badge1).toBeInTheDocument()
})
it('should display the exclamation icon and 7 devices require attention', async () => {
const result_local = {
data: {
numDevices: 4,
}
}
const mocks_local = createMocks([
{
query: GET_DEVICES,
result: result_local,
}
])
render(<Section } />, { mocks: mocks_local })
const devicesWithActiveIssuesIcon = await screen.findByTestId('ExclamationIcon')
expect(devicesWithActiveIssuesIcon).toBeInTheDocument()
})
})
The createMocks is an import and looks like this:
const createMocks = mocks =>
mocks.reduce(
(requests, mock) => [
...requests,
{
request: {
query: mock.query,
variables: mock.variables
},
result: mock.result
}
],
[]
)
It will return an object as follows:
const mocks = [
{
request: {
query: GET_DEVICES,
variables: {}
},
result: {
data: {
numDevices: 1
},
},
},
]
the issue might be from that the ApolloProviders used to render this two components are sharing the same InMemoryCache instance. see the following link for details.
https://github.com/benawad/apollo-mocked-provider/issues/1#issuecomment-511593398
if this is the case you just need to create new instance of InMemoryCache for every test.

Amplify React Native - Duplicate Error using amplify add api

I'm using this Amplify guide https://aws-amplify.github.io/docs/js/tutorials/building-react-native-apps/#connect-to-your-backend-1 and when I create an API using "aplify add api" the app fails.
I'm using "expo" and I'm using IphoneX for test phase.
My app code is
import React, { Component } from 'react';
import { StyleSheet, Text, Button, View, Alert } from 'react-native';
import Amplify, { API } from 'aws-amplify';
import amplify from './aws-exports';
import awsmobile from './aws-exports';
import { withAuthenticator } from 'aws-amplify-react-native';
Amplify.configure(amplify);
Amplify.configure(awsmobile);
state = { apiResponse: null };
class App extends Component {
async getSample() {
const path = "/items"; // you can specify the path
const apiResponse = await API.get("theListApi" , path); //replace the API name
console.log('response:' + apiResponse);
this.setState({ apiResponse });
}
render() {
return (
<View style={styles.container}>
<Text>test</Text>
<Button title="Send Request" onPress={this.getSample.bind(this)} />
<Text>Response: {this.state.apiResponse && JSON.stringify(this.state.apiResponse)}</Text>
</View>
);
}
}
export default withAuthenticator(App);
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#63C8F1',
alignItems: 'center',
justifyContent: 'center',
},
});
executing "expo start" the command line return this message error:
jest-haste-map: Haste module naming collision: theListFunction
The following files share their name; please adjust your hasteImpl:
* <rootDir>/amplify/backend/function/theListFunction/src/package.json
* <rootDir>/amplify/#current-cloud-backend/function/theListFunction/src/package.json
Failed to construct transformer: DuplicateError: Duplicated files or mocks. Please check the console for more info
at setModule (/Users/j_hen/Documents/jdev/smartApp/sourcecode/mySmaertProject/node_modules/jest-haste-map/build/index.js:620:17)
at workerReply (/Users/j_hen/Documents/jdev/smartApp/sourcecode/mySmaertProject/node_modules/jest-haste-map/build/index.js:691:9)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async Promise.all (index 391) {
mockPath1: 'amplify/backend/function/theListFunction/src/package.json',
mockPath2: 'amplify/#current-cloud-backend/function/theListFunction/src/package.json'
}
(node:1506) UnhandledPromiseRejectionWarning: Error: Duplicated files or mocks. Please check the console for more info
at setModule (/Users/j_hen/Documents/jdev/smartApp/sourcecode/mySmaertProject/node_modules/jest-haste-map/build/index.js:620:17)
at workerReply (/Users/j_hen/Documents/jdev/smartApp/sourcecode/mySmaertProject/node_modules/jest-haste-map/build/index.js:691:9)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async Promise.all (index 391)
(node:1506) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:1506) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
or
Error: Duplicated files or mocks. Please check the console for more info
at setModule (/Users/j_hen/Documents/jdev/smartApp/sourcecode/mySmaertProject/node_modules/jest-haste-map/build/index.js:620:17)
at workerReply (/Users/j_hen/Documents/jdev/smartApp/sourcecode/mySmaertProject/node_modules/jest-haste-map/build/index.js:691:9)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async Promise.all (index 391)
What is wrong? How can I use the API correctly?
Amplify creates a copy of your current cloud backend configuration in amplify/#current-cloud-backend/.
You don't need those files to build your app, so you can ignore them in order to get rid of the error.
To do so, you can create a blacklist and add the folder to it.
Create a rn-cli.config.js file in the root of your project.
./rn-cli.config.js:
// works with older react native versions
// const blacklist = require('metro').createBlacklist;
const blacklist = require('metro-config/src/defaults/blacklist');
module.exports = {
resolver: {
blacklistRE: blacklist([/#current-cloud-backend\/.*/]),
},
};
Reference issue.
TypeScript considerations:
(As stated in Mush's answer)
If you are using typescript you should create the blacklist on
metro.config.js NOT rn-cli.config.js.
module.exports = {
resolver: {
blacklistRE: /#current-cloud-backend\/.*/
},
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
};
As stated
here.
2022
In Metro v0.64.0 blacklist was renamed to blocklist, release notes
My current solution is to edit the metro.config.js (or create a new one) and add the following
const exclusionList = require('metro-config/src/defaults/exclusionList');
module.exports = {
resolver: {
blacklistRE: exclusionList([/amplify\/#current-cloud-backend\/.*/]),
},
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
};
If you are using typescript you should create the blacklist on metro.config.js NOT rn-cli.config.js.
module.exports = {
resolver: {
blacklistRE: /#current-cloud-backend\/.*/
},
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
};
As stated here.
I just ran into this problem and had to create ./rn-cli.config.js with the following as blacklist was in a different folder:
const blacklist = require('metro-config/src/defaults/blacklist');
module.exports = {
resolver: {
blacklistRE: blacklist([/#current-cloud-backend\/.*/]),
},
};
After updating to Expo SDK41 this issue came back.
I needed to change previous rn-cli.config.js to metro.config.js (even though I'm not using TS) and install #expo/metro-config as devDependency.
Expo + Late 2021 Update
Not sure if this is fix is expo specific, but the current way to do this is with blacklist (rather than exclusionList). Like so:
metro.config.js
const blacklist = require("metro-config/src/defaults/blacklist")
module.exports = {
resolver: {
blacklistRE: blacklist([/amplify\/#current-cloud-backend\/.*/]),
},
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
}
For anyone who is still facing this issue I had to change something after this issue re-appeared.
For me, I had to change blacklist in line 1 to exclusionList
metro.config.js
const blacklist = require("metro-config/src/defaults/exclusionList")
module.exports = {
resolver: {
blacklistRE: blacklist([/amplify\/#current-cloud-backend\/.*/]),
},
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
}

Unable run isomorphic single page app on firebase with ES6

I have an isomorphic react app. It has a server.js file inside app/src/ directory.
Server.js
import path from 'path';
import express from 'express';
import cookieParser from 'cookie-parser';
import bodyParser from 'body-parser';
import expressJwt, { UnauthorizedError as Jwt401Error } from 'express-jwt';
import nodeFetch from 'node-fetch';
import React from 'react';
import ReactDOM from 'react-dom/server';
import PrettyError from 'pretty-error';
import App from './components/App';
import Html from './components/Html';
import { ErrorPageWithoutStyle } from './routes/error/ErrorPage';
import errorPageStyle from './routes/error/ErrorPage.css';
import createFetch from './createFetch';
import router from './router';
import assets from './assets.json'; // eslint-disable-line import/no-unresolved
import configureStore from './store/configureStore';
import { setRuntimeVariable } from './actions/runtime';
import config from './config';
const app = express();
//
// Tell any CSS tooling (such as Material UI) to use all vendor prefixes if the
// user agent is not known.
// -----------------------------------------------------------------------------
global.navigator = global.navigator || {};
global.navigator.userAgent = global.navigator.userAgent || 'all';
//
// Register Node.js middleware
// -----------------------------------------------------------------------------
app.use(express.static(path.resolve(__dirname, 'public')));
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
//
// Authentication
// -----------------------------------------------------------------------------
app.use(
expressJwt({
secret: config.auth.jwt.secret,
credentialsRequired: false,
getToken: req => req.cookies.id_token,
}),
);
// Error handler for express-jwt
app.use((err, req, res, next) => {
// eslint-disable-line no-unused-vars
if (err instanceof Jwt401Error) {
console.error('[express-jwt-error]', req.cookies.id_token);
// `clearCookie`, otherwise user can't use web-app until cookie expires
res.clearCookie('id_token');
}
next(err);
});
if (__DEV__) {
app.enable('trust proxy');
}
//
// Register server-side rendering middleware
// -----------------------------------------------------------------------------
app.get('*', async (req, res, next) => {
try {
const css = new Set();
// Universal HTTP client
const fetch = createFetch(nodeFetch, {
baseUrl: config.api.serverUrl,
cookie: req.headers.cookie,
});
const initialState = {
user: req.user || null,
};
const store = configureStore(initialState, {
fetch,
// I should not use `history` on server.. but how I do redirection? follow universal-router
});
store.dispatch(
setRuntimeVariable({
name: 'initialNow',
value: Date.now(),
}),
);
// Global (context) variables that can be easily accessed from any React component
// https://facebook.github.io/react/docs/context.html
const context = {
// Enables critical path CSS rendering
// https://github.com/kriasoft/isomorphic-style-loader
insertCss: (...styles) => {
// eslint-disable-next-line no-underscore-dangle
styles.forEach(style => css.add(style._getCss()));
},
fetch,
// You can access redux through react-redux connect
store,
storeSubscription: null,
};
const route = await router.resolve({
...context,
pathname: req.path,
query: req.query,
});
if (route.redirect) {
res.redirect(route.status || 302, route.redirect);
return;
}
const data = { ...route };
data.children = ReactDOM.renderToString(
<App context={context} store={store}>
{route.component}
</App>,
);
data.styles = [{ id: 'css', cssText: [...css].join('') }];
data.scripts = [assets.vendor.js];
if (route.chunks) {
data.scripts.push(...route.chunks.map(chunk => assets[chunk].js));
}
data.scripts.push(assets.client.js);
data.app = {
apiUrl: config.api.clientUrl,
state: context.store.getState(),
};
const html = ReactDOM.renderToStaticMarkup(<Html {...data} />);
res.status(route.status || 200);
res.send(`<!doctype html>${html}`);
} catch (err) {
next(err);
}
});
//
// Error handling
// -----------------------------------------------------------------------------
const pe = new PrettyError();
pe.skipNodeFiles();
pe.skipPackage('express');
// eslint-disable-next-line no-unused-vars
app.use((err, req, res, next) => {
console.error(pe.render(err));
const html = ReactDOM.renderToStaticMarkup(
<Html
title="Internal Server Error"
description={err.message}
styles={[{ id: 'css', cssText: errorPageStyle._getCss() }]} // eslint-disable-line no-underscore-dangle
>
{ReactDOM.renderToString(<ErrorPageWithoutStyle error={err} />)}
</Html>,
);
res.status(err.status || 500);
res.send(`<!doctype html>${html}`);
});
//
// Launch the server
// -----------------------------------------------------------------------------
if (!module.hot) {
app.listen(config.port, () => {
console.info(`The server is running at http://localhost:${config.port}/`);
});
}
//
// Hot Module Replacement
// -----------------------------------------------------------------------------
if (module.hot) {
app.hot = module.hot;
module.hot.accept('./router');
}
export default app;
I want to deploy my app using firebase. For that I have setup firebase.json like so -
{
"database": {
"rules": "database.rules.json"
},
"hosting": {
"public": "build",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"function": "app"
}
]
}
}
where app is a firebase function defined inside app/functions/ i.e. src and functions have same parent directory.
Functions directory has node_modules, properly configured and its working when tested for other functions.
Problem -
My index.js file inside app/functions is like so -
import app from '../src/server';
import functions from 'firebase-functions';
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
// response.send("Hello from Firebase!");
// });
exports.app = functions.https.onRequest(app);
Firebase is complaining that it doesnt support ES6. How do I get this function to work with ES6? I cannot simply change functions/index.js file to ES5 and hope things will work as when requires are resolved, they'd expect everything inside to be ES5 as well which is not the case as my entire codebase is in ES6.
I found the solution to this problem.
Make a directory in functions/ say 'build'.
Build your project
Copy all the contents of your ./dist or ./build (wherever your build files are present) to functions/build
Modify functions/index.js as follows -
const app = require('./build/bundle.js').default;
const functions = require('firebase-functions');
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
// response.send("Hello from Firebase!");
// });
exports.app = functions.https.onRequest(app);
Works like a charm

Resources