transform-class-properties plugin in React Enzyme shallow rendering - javascript

Enabled transform-class-properties plugin webpack module exports, which is helping me to have class which is a registered word in javascript to be used normally in my html code and transpilation step using the plugin takes on the heavy lifting.
I'm using enzyme for testing components now I have issue where in I have my component like this.
export default class Settings extends React.Component {
render() {
return (
<div class='something'>Settings</div>
);
}
}
If I want to test in my unit test if I have any something class in my Component it fails always.
export default class Settings extends React.Component {
render() {
return (
<div className='something'>Settings</div>
);
}
}
But if I do the above transformation myself, I have UT passing.
How can I do the transformation step to kick in before unit testing too. I'm using npm script test like this
"test": "mocha -w ./test/**/*.js --compilers js:babel-core/register --reporter spec",

My bad -- The solution lies in .bablerc solved it using another stackoverflow thread Mocha throws unexpected token error for ES6 object spread operator

Related

Trying to remove 'react-hot-loader' from final bundle using webpack ignorePlugin

This is what the react-hot-loader DOCs says:
https://www.npmjs.com/package/react-hot-loader
Note: You can safely install react-hot-loader as a regular dependency instead of a dev dependency as it automatically ensures it is not executed in production and the footprint is minimal.
Even though it says that. My goals are:
I want to remove react-hot-loader from my production bundle.
And I also want a single App.js file. That should work for DEV and PROD.
The only command that I have related to react-hot-loader is inside of my App.js file:
App.js
import { hot } from 'react-hot-loader/root';
import React from 'react';
import Layout from './Layout/Layout';
function App() {
console.log('Rendering App...');
return(
<Layout/>
);
}
export default process.env = hot(App);
If I run it just like this, I end up with the following line on my app.js transpiled and bundled file:
/* WEBPACK VAR INJECTION /(function(process) {/ harmony import / var react_hot_loader_root__WEBPACK_IMPORTED_MODULE_0__ = webpack_require(/! react-hot-loader/root */ "wSuE");
That's expected.
But if I change my App.js file to:
AppV2.js
import { hot } from 'react-hot-loader/root'; // KEEPING THE IMPORT
import React from 'react';
import Layout from './Layout/Layout';
function App() {
console.log('Rendering App...');
console.log(window);
return(
<Layout/>
);
}
// export default hot(App); <--- COMMENTED OUT THE hot() LINE
export default App;
And I add this line to my webpack.config.js
webpack.config.js
plugins:[
new webpack.IgnorePlugin(/react-hot-loader/)
]
I'll end up with a new transpiled app.js file with this line:
*** !(function webpackMissingModule() { var e = new Error("Cannot find module 'react-hot-loader/root'"); e.code = 'MODULE_NOT_FOUND'; throw e; }());
Note: The first '***' chars in the line above don't really exist. I had to add them in order to the ! exclation mark to be shown in the quote. Don't know why but you can't start a quote with an exclamation mark.
QUESTION
Isn't the IgnorePlugin supposed to completely ignore the react-hot-loader package? Why is it being marked as missing? See that it's not even being used on the code (since I've commented out the hot() call).
Ignore Plugin only excludes that particular module in bundle generation. However it will not remove the references to the module from your source code. Hence your webpack output is throwing that error.
One way of bypassing this error is to use the DefinePlugin to create a dummy stub for react-hot-loader. More on that here.
That said react-hot-loader itself proxies the children without any changes if the NODE_ENV is production. Check here and here. So in production mode apart from the hot() function call which directly returns your component, there is no other stuff that happens.
Another option could be:
// App.js
export default function AppFactory() {
if (process.env.NODE_ENV === "development") {
return hot(App);
} else {
return App;
}
}
// index.js:
import AppFactory from './App';
const App = AppFactory();
// ...
<App />
Now since webpack is creating bundles at build time, it knows if the mode is development or production (more on build modes) and should be able to eliminate the dead code with tree shaking and UglifyjsWebpackPlugin.
Make sure that if you are using Babel it's not transpiling your code to CommonJS - see Conclusion section, point 2 of the tree shaking page.
Pass the ambient mode to babel.
"scripts": {
"build-dev": "webpack --node-env development",
"build-prod": "webpack --node-env production",
},

Reactjs not understanding ES6?

I'm reeeally new to reactjs and I was copying a tutorial (link: https://www.youtube.com/watch?v=Ke90Tje7VS0). I'm currently on Windows and did the following on cmd (as per tutorial):
npm i -g create-react-app#1.5.2
create-react-app
The files/directories, etc. have all been installed, but I noticed that my App.js features this syntax:
function App()
{
return(...);
}
While the App.js from the tutorial (and many other demos) use this kind of syntax, from what I understand it's ES6:
class App extends Component
{
render()
{
return(...);
}
}
I tried copying this syntax onto my App.js but then my react app (from typing npm start in cmd) broke. How can I fix this (i.e. use the ES6 code without breaking my project)? Does it have the exact same functionality as my above code anyway?
Here is my error message:
Line 8: Parsing error: Unexpected token
6 | class App extends Component {
7 | return (
> 8 | <div className="App">
| ^
9 | <header className="App-header">
10 | <img src={logo} className="App-logo" alt="logo" />
11 | <p>
I really doubt it's a parsing error, the JSX worked fine with function App(), but when I changed it to class App extends Component without touching anything else, the program broke.
The issue here is from trying to return HTML/JSX from your class directly, rather than from within a function. If you're using a class, you'll need to wrap the returned HTML/JSX in the render function.
For example:
class App extends Component {
render() {
return (...)
}
}
Also, regarding the difference between the two syntax examples you posted: the first is what's called a functional component, while the second is a class-based component. In the past, class-based components were used for anything that required state (data held and manipulated internally) or life-cycle methods, while functional components were used for components that were presentation-only. With Hooks (introduced , functional components can now have state and access to life-cycle methods so the two are pretty much equivalent. Put simply, you can think of a functional-component as just the render method of a class-based component.
In general the difference in use goes like this:
Class-based:
class App extends Component {
render() {
return (...)
}
}
Functional:
const App = props => { // or function App(props) {
return (...)
}
Check out these docs for a bit more detail:
Class-based components: https://reactjs.org/docs/react-component.html
Discussion on functional components: https://reactjs.org/docs/components-and-props.html
-By assuming you are begginer in React you need to install react in your machine with this command below
npm i -g create-react-app#1.5.2
Then to create a new react app type command npx create-react-app yourAppName
And you question was does React understand ES6 and answer is big
YES
When you successfully installed and handle your app, now it's time to see how es6 works perfectly with React
Instance:
// importing react library
import React from 'react';
// ES6 Function
const App = () => {
const data = [
{
firstname: 'Joe'
},
{
firstname: 'Claire'
},
{
firstname: 'John'
}
]
return {data.map(data => <li key={data.firstname}>{data.firstname}</li>)}
}

How to Embed StencilJS components inside Storybook React App?

I'm trying to integrate Stencil and Storybook inside the same project. I've been following this set up guide and this one however one of the steps is to publish the library of components to NPM and that's not what I want.
I have this repo which I've configured with components library (src folder) and with the reviewer of those components with Storybook, which resides in the storybook folder.
The problem is that when I compile the components using Stencil and copy the dist folder inside the Storybook app and import the component nothing renders. Tweaking the configuration using custom head tags I was able to import it correctly however no styles where applied.
When I open the network panel there is some error when importing the component:
And thus the component is present in the DOM but with visibility set to hidden, which I think it does when there is an error.
This is the component au-button:
import { Component } from '#stencil/core';
#Component({
tag: 'au-button',
styleUrl: 'button.css',
shadow: true
})
export class Button {
render() {
return (
<button class="test">Hello</button>
);
}
}
Here is the story my component:
import React from 'react';
import { storiesOf } from '#storybook/react';
import '../components/components.js'
storiesOf('Button', module)
.add('with text', () => <au-button></au-button>)
These are the scripts inside the Storybook app:
"scripts": {
"storybook": "start-storybook -p 9009",
"build-storybook": "build-storybook",
"copy": "cp -R ./../dist/* components"
},
And the workflow is as follows:
Launch storybook
Make changes in the component
Execute build command
Execute copy command
Also, I would like to automate the developer experience, but after I solve this problem first.
Any ideas of what I could be doing wrong?
Sample for this could be found in the repo
https://github.com/shanmugapriyaEK/stencil-storybook. It autogenerates stories with knobs and notes. Also it has custom theme in it. Hope it helps.
I'm using #storybook/polymer and it's working for me really well.
following your example:
import { Component } from '#stencil/core';
#Component({
tag: 'au-button',
styleUrl: 'button.css',
shadow: true
})
export class Button {
render() {
return (
<button class="test">Hello</button>
);
}
}
the story would be:
import { storiesOf } from '#storybook/polymer';
storiesOf('Button', module)
.add('with text', () => <au-button></au-button>)
the scripts in the package.json:
"scripts": {
"storybook": "start-storybook -p 9001 -c .storybook -s www"
},
the storybook config file:
import { configure, addDecorator } from '#storybook/polymer';
const req = require.context('../src', true, /\.stories\.js$/);
function loadStories() {
req.keys().forEach((filename) => req(filename))
}
configure(loadStories, module);
and storybook preview-head.html you have to add to the body the following:
<body>
<div id="root"></div>
<div id="error-message"></div>
<div id="error-stack"></div>
</body>
I've been following this set up guide and this one however one of the steps is to publish the library of components to NPM and that's not what I want.
My reading of those guides is that they're stating “publish to NPM” as a way to have your files at a known URL, that will work most easily for deployment.
Without doing that, you'll need to figure out a different deployment strategy. How will you get the build products – the dist directory and static files – published so that your HTML will be able to reference it at a known URL? By choosing to diverge from the guidelines, that's the problem you have to address manually instead.
Not an insurmountable problem, but there is no general solution for all. You've chosen (for your own reasons) to reject the solution offered by the how-to guides, which means you accept the mantle of “I know what I want” instead :-)

Import ace code editor into webpack, es6, typescript project

I'm trying to build a web component that will host the ace editor. The trouble is that I don't find enough information on how to import the module and set the types. The code bellow was working just fine using simple <script> tags and global vars.
So far this is what I have:
npm install ace-code-editor --save
npm install #types/ace --save-dev
code-editor.cmp.ts
// Error: [ts] File '.../node_modules/#types/ace/index.d.ts' is not a module.
import * as ace from 'ace';
export class CodeEditorCmp extends HTMLElement {
// DOM
private editor: AceAjax; // How do I import the type. What type to use?
constructor() {
super();
}
connectedCallback() {
this.initCodeEditor();
}
initCodeEditor(){
this.editor = ace.edit("editor-vsc");
// How do I import the editor themes?
this.editor.setTheme("ace/theme/xcode");
// How do I import the editor modes?
var JavaScriptMode = ace.require("ace/mode/html").Mode;
this.editor.session.setMode(new JavaScriptMode());
this.editor.getSession().setTabSize(4);
this.editor.getSession().setUseSoftTabs(true);
this.editor.getSession().setUseWrapMode(true);
this.editor.setAutoScrollEditorIntoView(true);
// Update document
this.editor.getSession().on('change', this.onEditorChange);
}
onEditorChange(){
}
}
require('./code-editor.cmp.scss');
window.customElements.define('editor-vsc', CodeEditorCmp);
For those who don't want to use the brace module, I saw that my issue was that I was importing the wrong version of ace. Once installed, make sure to import from src-noconflict. The noconflict version uses ace.require which seems to play a lot more nicely than the other iterations that use require.
I would suggest that you do the following:
npm install ace-builds --save
npm install #types/ace --save-dev
Afterwards in your file just import the noconflict like below:
import * as ace from 'ace-builds/src-noconflict/ace';
This will result in a variable ace being defined. You will then be able to reference methods and properties of ace as normal, such as ace.edit()
You can get more information about the different versions of ace check out the git page.
After a lot of digging I managed to find brace module. It's a browserify wrapper for ace. Fortunately it works straight away with webpack. No need to use separate types, they come prepackaged.
import * as ace from 'brace';
import 'brace/mode/javascript';
import 'brace/theme/monokai';
export class CodeEditorCmp extends HTMLElement {
private editor: ace.Editor;
initCodeEditor(){
this.editor = ace.edit('javascript-editor');
this.editor.getSession().setMode('ace/mode/javascript');
this.editor.setTheme('ace/theme/monokai');
//...
}
//...
}

Error "Unexpected token" when run mocha against JSX syntax

I am kind of new to Javascript programming. I tried writing a test for a script with JSX format, but somewhat it fails with Unexpected token.
Here's the test code, I haven't write any test yet.
//Rectangle.js
let assert = require('chai').assert,
path = require('path');
import Rectangle from './Rectangle';
And here's the code that needs to be tested
//Rectangle.jsx
import React from 'react';
class Rectangle extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Here's the error
SyntaxError: Rectangle.jsx: Unexpected token (5:11)
3 | class Rectangle extends React.Component {
4 | render() {
> 5 | return <h1>Hello, {this.props.name}</h1>;
| ^
6 | }
7 | }
Here's the mocha command that I got from some articles nyc mocha --compilers js:babel-core/register Rectangle.js.
I also uploaded the code on github (link), so you could see the installed dependencies.
How should I fix this? Is there a step that I missed?
You need to add react preset to you babel config inside package.json
"babel": {
"presets": ["es2015", "react"]
}
I think you may need custom compiler to help you compile jsx code.
You can see the example here: Mocha-react repo.

Categories