Components aren't rendering because of the Uncaught ReferenceError error. The error is thrown in one of the React API files (see the code in question below). I'm using the react-rails gem and am trying to render a blank component called 'Test'.
The file from React API(line 3)
'use strict';
if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react.production.min.js');
} else {
module.exports = require('./cjs/react.development.js');
}
ERB Rendering Component
<div style="width:100vw">
<%= react_component('Test') %>
</div>
The Component
import React from "react";
import PropTypes from "prop-types";
export default class Test extends React.Component{
render(){
return (
<div>
test
</div>
)
}
}
The React API should render 'test' to the (v)dom.
React-rails gem uses webpacker, so I would follow their documentation to make sure you source your environment variables correctly, particularly the portion involving the setup of dotenv files if you don't use webpack-dev-server:
Environment variables are supported out of the box in Webpacker. For
example if you run the webpack dev server like so:
FOO=hello BAR=world ./bin/webpack-dev-server
You can then reference these variables in your JavaScript app code with process.env:
console.log(process.env.FOO) // Compiles to console.log("hello")
You may want to store configuration in environment variables via .env files, similar to the dotenv Ruby gem.
Here is what you could do to support a "Ruby-like" dotenv:
yarn add dotenv
// config/webpack/environment.js
...
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
const dotenv = require('dotenv')
const dotenvFiles = [
`.env.${process.env.NODE_ENV}.local`,
'.env.local',
`.env.${process.env.NODE_ENV}`,
'.env'
]
dotenvFiles.forEach((dotenvFile) => {
dotenv.config({ path: dotenvFile, silent: true })
})
environment.plugins.prepend('Environment', new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(process.env))))
module.exports = environment
If you'd like to pass custom variables to the on-demand compiler, use Webpacker::Compiler.env attribute.
Webpacker::Compiler.env['FRONTEND_API_KEY'] = 'your_secret_key'
Related
I'm trying to implement i18n-perser with Next Js. According to the i18n-perser documentation I need to create a gulpfile.js on the root directory. My gulpfile.js is something like this.
import gulp from 'gulp';
import { gulp as i18nextParser } from 'i18next-parser';
export async function i18next() {
return gulp
.src('./**')
.pipe(
new i18nextParser({
locales: ['en', 'nl'],
output: './i18n/locales/$LOCALE/$NAMESPACE.json',
})
)
.pipe(gulp.dest('./'));
}
It's gives me SyntaxError: Cannot use import statement outside a module. I tried some solution like the dynamic import. But it's not working for me in this case. It's giving me the same SyntaxError.
import dynamic from 'next/dynamic';
const gulp = dynamic(() => import('gulp'), { ssr: false });
const { gulp: i18nextParser } = dynamic(() => import('i18next-parser"'), { ssr: false });
I triend the dynamic import but it's also not working in my case. It's working perfectly in React but not working with NextJs. Basiclly if I run npm run gulp it will create parer file for me.
Probably your project is set to use the CommonJS module system by default.
In that case, you could rename your gulpfile.js to gulpfile.mjs to keep using the import syntax.
I want to write stories for both React and Svelte components. I already have a few React components, and I'm attempting to install Svelte. My closest attempt can either run React OR Svelte depending on whether I comment out my React configuration. If I don't comment it out, I get this message when I look at my Svelte component in storybook:
Error: Objects are not valid as a React child (found: object with keys {Component}). If you meant to render a collection of children, use an array instead.
in unboundStoryFn
in ErrorBoundary
(further stack trace)
This refers to my story stories/test.svelte-stories.js:
import { storiesOf } from '#storybook/svelte';
import TestSvelteComponent from '../src/testComponentGroup/TestSvelteComponent.svelte';
storiesOf('TestSvelteComponent', module)
.add('Svelte Test', () => ({
Component: TestSvelteComponent
}));
My configuration is as follows:
.storybook/config.js:
import './config.react'; // If I comment out this line, I can make the svelte component work in storybook, but of course my react stories won't appear.
import './config.svelte';
.storybook/config.react.js:
import { configure } from '#storybook/react';
const req = require.context('../stories', true, /\.react-stories\.js$/);
function loadStories() {
req.keys().forEach(filename => req(filename));
}
configure(loadStories, module);
.storybook/config.svelte.js:
import { configure } from '#storybook/svelte';
const req = require.context('../stories', true, /\.svelte-stories\.js$/);
function loadStories() {
req.keys().forEach(filename => req(filename));
}
configure(loadStories, module);
.storybook/webpack.config.js:
module.exports = async ({ config, mode }) => {
let j;
// Find svelteloader from the webpack config
const svelteloader = config.module.rules.find((r, i) => {
if (r.loader && r.loader.includes('svelte-loader')) {
j = i;
return true;
}
});
// safely inject preprocess into the config
config.module.rules[j] = {
...svelteloader,
options: {
...svelteloader.options,
}
}
// return the overridden config
return config;
}
src/testComponentGroup/TestSvelteComponent.svelte:
<h1>
Hello
</h1>
It seems as though it's attempting to parse JSX via the Svelte test files, but if I import both React AND Svelte configurations I can still see the React components behaving properly.
See this discussion on github : https://github.com/storybookjs/storybook/issues/3889
It's not possible now and it's planned for the v7.0
The official position now is to create two sets of configuration (preview and manager), instanciate two separates storybook, and then use composition to assemble the two storybook into one.
I am trying to get up and running with react create app and mobx state tree. I keep getting
Support for the experimental syntax 'decorators-legacy' isn't currently enabled (4:1):
I never used react create app so I am not sure how to enable, I tried making a .babelrc file but that did not help
{
"presets": ["#babel/preset-env"],
"plugins": [
["#babel/plugin-proposal-decorators", { "legacy": true }]
]
}
import React, { Component } from "react";
import { observer, inject } from "mobx-react";
#inject("domainStores")
#observer
export default class MainComponent extends Component {
async componentDidMount() {}
render() {
return <div className="main-container">
helllo
</div>;
}
}
I am also open to suggestions if things have changed, I have not used the newest version of Mobx State tree so many there is a better way of doing this now?
If you only using MST without regular MobX stuff and only need inject and observer then you can use regular function syntax, it looks not that great, but does not require any setup:
export const WrappedComponent = inject("domainStores")(observer(Component)
// Or use export default here if you prefer
If you are using other features of MobX then in MobX 6 there is a new thing that will probably allow you to drop decorators (like computed, action and etc) altogether, makeAutoObservable:
import { makeAutoObservable } from "mobx"
class Store {
// Don't need decorators now
string = 'Test String';
setString = (string) => {
this.string = string;
};
constructor() {
// Just call it here
makeAutoObservable (this);
}
}
With that you don't even need decorator syntax to be enabled.
More info here
https://mobx.js.org/migrating-from-4-or-5.html
and
https://mobx.js.org/react-integration.html
Instead of using the old decorators proposal, you can use observer as a function on your components instead of as a decorator.
We can also use React's own context instead of inject, as the documentation states:
Note: usually there is no need anymore to use Provider / inject in new code bases; most of its features are now covered by
React.createContext.
This way we can use Create React App as is.
Example
import React from "react";
import { observer } from "mobx-react";
import { types } from "mobx-state-tree";
const StoresContext = React.createContext("store");
// custom hook that we can use in function components to get
// the injected store(s)
function useStore() {
return React.useContext(StoresContext);
}
const StoreModel = types.model({
things: types.array(types.string)
});
const storeInstance = StoreModel.create({ things: ["foo", "bar"] });
// instead of using the #observer decorator, we can use observer as
// a function and give it a component as argument
const MainComponent = observer(() => {
const store = useStore();
return (
<div>
{store.things.map((thing) => (
<div key={thing}>{thing}</div>
))}
</div>
);
});
export default observer(function App() {
return (
<StoresContext.Provider value={storeInstance}>
<MainComponent />
</StoresContext.Provider>
);
});
CRA does not allow you to extend your own configuration, so, in order to extend cra configuration, you will have to use customize-cra with react-app-rewired.
So, follow the steps below:
Install customize-cra, react-app-rewired and #babel/plugin-proposal-decorators using npm or yarn
add config-overrides.js at root level of your project and paste the code given below:
const {override, addDecoratorsLegacy } = require('customize-cra');
module.exports = override(addDecoratorsLegacy());
Update package.json scripts to the below ones:
"start": "react-app-rewired start",
"build": "react-app-rewired build"
P.S: if you want to use babel configuration then your config-overrides.js should be like:
const {override, addDecoratorsLegacy, useBabelRc } = require('customize-cra');
module.exports = override(addDecoratorsLegacy(), useBabelRc());
useBabelRc will load config from your root of project automatically.
My CRA project isn't parsing my environment variables. I see this in the docs:
By default you will have NODE_ENV defined for you, and any other
environment variables starting with REACT_APP_
And here is some code for testing:
// .env in the project root folder
REACT_APP_GOOGLE=google.com
REACT_APP_API_POST_URL=http://localhost:4000/api/
// App.js
import dotenv from 'dotenv';
componentDidMount() {
if (dotenv.error) {
console.log('dotenv.error', dotenv.error);
} else { console.log('dotenv.parsed', dotenv.parsed); // undefined
}
}
// App.js insider render()
<button
onClick={e => {
e.preventDefault();
console.log("process.env", process.env); //
// {NODE_ENV: "development", PUBLIC_URL: ""}
// NODE_ENV: "development"
// PUBLIC_URL: ""
console.log("process.env.NODE_ENV", process.env.NODE_ENV); // development
console.log("process.env.REACT_APP_GOOGLE", process.env.REACT_APP_GOOGLE); // undefined
}}
>log .env</button>
Anyone know why it's not parsing the env variables?
Here is your component:
import React, { Component } from 'react';
import './App.css';
const googleEnvVariable = process.env.REACT_APP_GOOGLE;
class App extends Component {
render() {
return <div className="App">{googleEnvVariable}</div>;
}
}
export default App;
And here is your .env
REACT_APP_GOOGLE=hereisyourenvvar
You should see hereisyourenvvar
EDIT: updated answer to display on the screen instead of the console.log...
From the code you gave, it seems like you forgot to call the config function (unless you didn't show it). If you want your .env to be implemented, you will have to do the following at the top level of your project :
import dotenv from 'dotenv';
// Load ENV vars
const dotEnvOptions = {
path: 'env/dev.env' //Example path relative to your project folder
}
dotenv.config(dotEnvOptions)
To figure out what is going wrong you may turn on logging to help debug why certain keys or values are not being set as you expect :
dotenv.config({ debug: true })
From there, if a path/variable isnt recognized, it will be printed int he console :
If you are not seeing anything, it either means that your path is wrong or that the code isn't executed
I'm developing an application using create-react-app and I'm trying to split my code into modules implementing the way described in the react-router huge-apps example.
Everything works well except the unit tests : I get this error while running the jest tests for the route components :
TypeError: Cannot read property 'contextTypes' of undefined
A route component looks like this :
export class IntroPage extends React.Component {
render() {
return (
<div></div>
);
}
}
const mapStateToProps = (state) => {
return {
...
}
};
module.exports = connect(mapStateToProps)(IntroPage);
and a test :
import React from 'react';
import {shallow} from 'enzyme';
import {IntroPage} from '../IntroPage';
it('should render without crashing', () => {
shallow(
<IntroPage {...props}/> // IntroPage is undefined
)
});
How do I have to export/import my components to be able to test them properly.
Thanks.
If you transpile in Babel:
export class IntroPage extends React.Component {
...
}
You will notice that Babel will move that to the exports variable.
Object.defineProperty(exports, "__esModule", {
value: true
});
... more good stuff
...
var IntroPage = exports.IntroPage = function (_React$Component) {
So you can console.log these:
console.log(exports);
console.log(module.exports);
console.log(module);
and check exports variable and module object.
In here module.exports should be the same as exports.
If you type:
module.exports = connect(mapStateToProps)(IntroPage);
at the end of your component file, you are overwriting the module.exports with the new value.
This is the core of the problem.
The solution?
I think you already found one, but the best would be not to mix commonJS with ES6 export, since ES6 export will be transpiled to commonJS syntax.
Check also "What is export default in JavaScript?"
Found a solution with this post : React router dynamic routes not rendering component
I just had to add 'default' to the require statements when exporting with es6 module.