Webpack configuration with react class containing server code - reactjs

I have an isomorphic react/flux (alt) implementation.
I'm trying to transform the project from browserify to webpack.
Considering my React class could look like this:
var dataAccess = require('../server/data-access');
var MyReactClass = React.createClass({
statics: {
/**
* This gets called by the containing component, so that each class
* handles its own data fetching.
* This part is obviously irrelevant in the client since the
* fetching is only done server-side and the result is used
* to populate the Alt.js store
*/
getData: function () {
return dataAccess.fetchData(
);
}
}...
I'd like to avoid bundling the entire "server" folder when running webpack, but when I do (via exclude in the loader config), things break in a strange way:
ERROR in ./react/react-routes.js
Module parse failed: C:\project\react\react-routes.js Line 19: Unexpected token <
You may need an appropriate loader to handle this file type.
| var routes = (
|
| <Route name="App" path="/" handler={App}>
|
| <DefaultRoute name="Default Route" handler={Main}/>
# ./client/index.js 5:18-50
If I return "server" back I'm getting errors on transforming mongojs's dependencies ("net" and such), which I don't believe is the correct direction.
If I remove all requires to my react classes in react-routes.js webpack is able to complete successfully. From this I understand that the problem indeed is in the fact that my classes have server code in them.
In browserify I was able to overcome this by using the require for the "data-access" and other server files inside the function getData(), but with webpack I didn't have luck so far.
What should be my ignore/exclude rules and how should I implement them?
Thanks.

What if you solved it outside of Webpack? You could do npm i babel --save-dev and then trigger require('babel/register') before importing that dataAccess bit. It will be able to deal with the JSX then. That would feel like the simplest solution to me.

React with Flux here is my github repository hope it will helps to understand the basic of react with flux https://github.com/TameshwarNirmalkar/ES6Babel it has:
Webpack
ES6
Babel
Eslint
React
Flux
Json-server for rest api
Complete CRUD operation
Hope it would be helpful.

Related

Import a file as a string (or source asset) in Gatsby / React

I want to import .ts, .tsx, .js, and .jsx files into a react component and render them within a PrismJS highlighting block. For example, let's say I have a TypeScript file with functionA in it that I want to highlight in my actual website:
functionA.ts:
export function functionA() {
console.log("I am function A!");
}
I want to include this in a different component. The problem is, when I import it, I am obviously importing the webpack module version of it. My weak attempt at trying to get my function render in a react component looks like this:
MyComponent.tsx:
import * as React from "react"
import { functionA } from "./functionA"
export function MyComponent() {
return (
<>
<h1>Here is your code block:</h1>
<pre>
<code>
{functionA.toString()}
</code>
</pre>
</>
)
}
and what will actually render on the page where the code block is will look something like this:
Here is your code block:
WEBPACK__IMPORT.functionA() {
console.log("I am function A!")
}
I can't exactly remember what the .toString() function output looked like, but the point is it is NOT just the contents of the file how it appears in a code edit for example - it has been modulized by WebPack.
So, in a Gatsby project, how can i get these various code snippets to be imported directly as a string, purely as they are written, without WebPack enacting its import stuff on it? Is there a plugin or some way to tell Webpack to use the imported file as its asset/source module type? I know for MD or MDX files there is the gatsby-remark-embed-snippet, but I am building a component based HTML page and can't use MD or MDX files!
It's very late, and perhaps I just can't see the forest from the trees, I know there must be a way to do this...
You need to require the file using webpack's raw-loader, i.e:
const functionA = require("!!raw-loader!./functionA");
This works for create-react-app, as in the solution discussed here, and this works for Gatsby as well!
After using require on such a file, the file contents can be rendered in the component as:
<pre>{functionA.default.toString()}</pre>
It's then up to you to add syntax highlighting using a tool like prism or similar.
Note this solution will only work as long as Gatsby V3 continues to use WebPack v4, as raw-loader is deprecated in WebPack v5 and will be phased out for asset/source type modules.

How to use React components on WebWorker

I am creating a PDF generator using the react-pdf package at https://react-pdf.org/. The process of converting the react-pdf components into a pdf blocks the main thread, so I would like to convert them on a separate Worker thread.
I am using create-react-app with worker-loader to recognize WebWorker files. I am having a hard time coming up with a way to import the react components into the Webworker and convert them using the pdf(Component).toBlob() method provided by react-pdf. The pdf(Component).toBlob() takes a react component as input and outputs the blob files, this means that the worker has to somehow be able to load the React component. The WebWorker works as expected when no React components are included.
I naively tried importing the React components into the WebWorker and tried running the conversion method:
pdf(<Component />).toBlob().then(blob=>{
...
})
which causes a module parse error:
Uncaught Error: Module parse failed: Unexpected token (14:8)
File was processed with these loaders:
* ./node_modules/eslint-loader/index.js
You may need an additional loader to handle the result of these loaders.
Any help would be extremely appreciated.
Edit:
I am using the create-react-app default webpack configuration with the addition of worker-loader which detects .worker.js files and registers them as Webworker. I added the work-loader using the react-app-rewired package:
module.exports = function override(config, env) {
config.module.rules.push({
test: /\.worker\.js$/,
use: { loader: 'worker-loader' }
})
config.output['globalObject'] = 'this';
return config;
}
This answer is an extension of the discussion we had in the chat.
The issue at hand here is the .push() from the override function. As stated in the MSDN documentation:
The push() method adds one or more elements to the end of an array and returns the new length of the array.
Effectively the config.module.rules.push() is adding the loader at the end of the rules array, thus processing first the React code and then the worker.js.
As Ali Zeaiter found out the solution was to use .unshift() (cf. doc) instead of .push() in order to prepend the loader to the rules array and thus processing first the worker.js file.

Why do I have to use "require" instead of "import from" for an image in React?

I see that this answer suggests the syntax for importing images as shown below (commented out). In my case, it didn't work out (complaining there's no modules to find in that file) and I had to switch to the syntax that's currently active.
// import Author from "../assets/author.png";
var Author = require("../assets/author.png");
The difference I can imagine is that I'm using TypeScript (transpiling my TSX by awesome-typescript-loader and loading my PNG file-loader) and they seem to use JSX. But as far my understanding goes, it all transpiles to plain JS and require in the end.
Being a noob on React, I'm not sure what the reason of this discrepancy is but also I'm not sure what to google for to investigate myself.
This is more of a problem with typescript than webpack itself, you might need to declare modules on a declaration file.
Create a declarations.d.ts
Update your tsconfig.json
"include": [
"./declarations.d.ts",
],
Put this on that file:
declare module '*.png';
Error might be gone.
You can declare a module for your images like this:
declare module "*.png" {
const value: any;
export default value;
}
Then, you will be able to import your image like this:
import AuthorSrc from "../assets/author.png";
This is happening because webpack doesn't support image import out of the box. So you need to add a rule for that in the webpack config file. When you add a new rule, TypeScript doesn't automatically know that, so you need to declare a new module to resolve this. Without the module, you will be able to import images, but TypeScript will throw an error because you didn't tell to it is possible.
This issue has nothing to do with webpack or any bundler and is not quite a problem with typescript.
Typescript has stated that `require("path") is a way to include modules to the scope of your current module, whilst it can be also used to read some random files (such as json files, for example).
As Vincent and Playma256 specified, you can declare a module wildcard to match certain file types, so you can import it as an import statement. But you don't really need to do this. Typescript won't give you an error if you are trying to import a png or a json file (tslint might, but that depends on your configuration).
By the way, if your declaration is within the source folder of your project as defined in tsconfig.json, you don't need to include it as specified by Playma256.
I've created a sample project in node for you to test:
https://github.com/rodrigoelp/typescript-declare-files
I think you can solve this problem with Webpack&&typescript.The official webpage of webpack has introduced something about this in
https://webpack.js.org/guides/typescript/
And I have try this myself in
https://github.com/reactpersopnal/webpack-root/tree/feature/typescript
The reason is that you would like to use non-code assets with TypeScript, so we need to defer the type for these imports for webpack.
Your could simply add custom.d.ts.
declare module "*.jpg" {
const content: any;
export default content;
}

Including an external js script in a React Component

I have a react application, managed using react-scripts.
In my app i am using an external js script. The external script doesn't do any module exports.
The structure of the external script is as below (too big to include it in full).
var TradingView = {.... various functions }
At the end of the file:
if (window.TradingView && jQuery) {
jQuery.extend(window.TradingView, TradingView)
} else {
window.TradingView = TradingView
}
My goal is to create a simple react component using the external script, and call the function: TradingView.widget({...});
I have been searching online for ways to include an external script in a react component/ES6 style, and have tried various options: react-async-script-loader, and various webpack plugins: script-loader, imports-loader, ProvidePlugin etc. But i haven't been able to make it work.
The error i am getting after using the imports-loader or ProvidePlugin is:
1189:31 error 'jQuery' is not defined no-undef
1190:9 error 'jQuery' is not defined no-undef
In my webpack config, i have:
In the loaders section:
{
test: /tv\.exec\.js/,
loader: 'imports?jQuery=jquery,$=jquery,this=>window'
}
In the plugins section:
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
When i create a simple webpage (no react), and include the script, and call TradingView.widget(), the page just works fine.
The closest i could get help was to look at:
Managing jQuery plugin dependency in webpack
But it didn't work for me. I am quite new to the react, webpack ecosystem, so I am not sure what i am missing here.
Please let me know if you need any additional info.
Update: I tested the above, including the script in a simple react component, but not using the react-scripts this time, and directly using webpack configurations. I was simply able to import the external js in my component directly, and it worked. I was also able to use imports-loader plugin in webpack to expose jQuery, which also worked. So its possible that using react-scripts needs something else to make it work.
It looks like your external script is handling its "exports" by adding them as members of window. You can use the import keyword on a file that doesn't define exports like so:
import "modulename";
There's nothing special about that syntax except that it doesn't imply that any functions or variables will be made available via the import facility. The code in "modulename" that assigns members to .window will execute, which is the important thing.
For compiler complaints about accessing window.* globals, try assigning the variable you want to access to a local variable:
const jquery = window.jquery;
...or maybe...
const TradingView = window.TradingView;
Then you'll have the variable in scope, and it should be usable.

React FixedDataTable Webpack bundle - Uncaught TypeError: Cannot read property 'requestAnimationFrame' of undefined

I've created a simple component called MyDataTable, as a wrapper over React FixedDataTable component and bundled it with Webpack. The file resulted from this bundle is called my-components.js. Nothing really complicated until here. You can try the source code to see how it works: https://github.com/cosminnicula/fdtwebpack
Now, the second step would be to consume this my-components.js library in a separate project. Here https://github.com/cosminnicula/fdtwebpackclient you can see how I imported the library and tried to use the <MyDataTable /> component:
'use strict';
//fdtwebpackclient/src/main.jsx
import React from 'react';
import MyDataTable from './../lib/my-components.js';
React.render(
<div>
Hello MyDataTable!
<MyDataTable></MyDataTable>
</div>
, document.body
)
However, if i try to browse index.html, I get a nasty error, which I don't find a logical explanation for: "Uncaught TypeError: Cannot read property 'requestAnimationFrame' of undefined".
BTW, the wrapper component was copy-pasted from here http://jsbin.com/temufa/18/edit?html,js,output, so it should suppose to work.
Any idea on this error?
I've identified the problem and the solution is very simple. Inside fdtwebpackclient change:
import MyDataTable from './../lib/my-components.js';
...
<MyDataTable></MyDataTable>
with:
import MyComponents from './../lib/my-components.js';
...
<MyComponents.MyDataTable></MyComponents.MyDataTable>
I think the problem is that you have a bundle within a bundle kind of situation. FixedDataTable seems to do some trickery to find global context (ie. window). This breaks here.
Instead of bundling a bundle within a bundle at your wrapper you could push FixedDataTable as an external there like this:
externals: {
'fixed-data-table': 'fixed-data-table',
},
The wrapper should probably consume FixedDataTable as a peer dependency then. Your main project would depend on FixedDataTable directly then. Webpack can deal with mapping the dependency to your wrapper.

Resources