New to React / Babelify; How to fix "Accessing PropTypes" warning - node.js

I'm new to both React and Babelify.
I'm using Node to compile a web app. Right now I'm doing this:
browserify({debug: true})
.transform(
babelify.configure({
comments : false,
presets : [
"react",
"babili",
],
})
)
.require('./app.js', {entry: true})
.plugin(collapse)
.bundle()
.on("error", function (err) {
console.log("Error:", err.message);
})
.pipe(fs.createWriteStream(destination));
My app is a VERY trivial "Hello, World!" proof-of-concept at the moment that's about this complex:
class Renderer {
render () {
ReactDOM.render(
<div>Hello, World!</div>
document.querySelector("#react-app")
);
}
}
module.exports = Renderer;
I'm getting this warning:
Warning: Accessing PropTypes via the main React package is deprecated, and
will be removed in React v16.0. Use the latest available v15.* prop-types
package from npm instead. For info on usage, compatibility, migration and more,
see https:/gfb.me/prop-types-docs
Warning: Accessing createClass via the main React package is deprecated,
and will be removed in React v16.0. Use a plain JavaScript class instead. If
you're not yet ready to migrate, create-react-class v15.* is available on npm
as a temporary, drop-in replacement. For more info see
https:/gfb.me/react-create-class
Error: [BABEL] /home/gweb/code/app.js: Unknown option:
/home/gweb/code/node_modules/react/react.js.Children. Check out
http:/gbabeljs.io/docs/usage/options/ for more information about options.
A common cause of this error is the presence of a configuration options
object without the corresponding preset name. Example:
Invalid:
`{ presets: [{option: value}] }`
Valid:
`{ presets: [['presetName', {option: value}]] }`
For more detailed information on preset configuration, please see
http:/gbabeljs.io/docs/plugins/#pluginpresets-options. (While processing
preset: "/home/gweb/code/node_modules/react/react.js") while parsing file:
/home/gweb/code/app.js
I read the recommended stuff, but I'm new enough to both that I can't quite get a handle on it. I also read a bunch of other articles and SO posts, but none of them (that I could find) had this set (browserify, babelify, react).
My goal at the moment is just to get it transpiling with support for the React syntax (which is JSX, from what I understand?), so I can start playing with it and learning both libraries. What's the fastest way to get this implemented (I don't necessarily need most efficient or best; I'd rather have the easiest-to-understand incantation at this stage, so I can have things transparent while I learn).

It is not your setup issue but problem is with your import statements, i'm assuming you are importing react and PropTypes from react
import React, { PropTypes } from 'react';
So, using PropTypes from react library has been deprecated as mentioned in warning and you need to install PropTypes as a standalone library from npm and use that instead.
npm install prop-types --save and then do,
import PropTypes from 'prop-types', for more info https://www.npmjs.com/package/prop-types
this will resolve your first warning, also for second warning you need to install and use https://www.npmjs.com/package/create-react-class.
for the babel error please check if you have both required libraries installed.
https://www.npmjs.com/package/babel-preset-react,
https://www.npmjs.com/package/babel-preset-babili

Do you have an import of the form import * as React from 'react'?
If so, try replacing it with import React from 'react'.
The * imports everything from react, including the deprecated exports, and that's what triggers the warnings.

Related

Why the import url must start with "node:"

I was checking the node official docs and I found that the import url of the node native modules in the examples of es modules starts with node:.
I did not use node very much, maybe there were some huge changes happened. So:
Can someone share some links that I can get some context about this change?
What if we don't add the node: before the import url? I tested a bit and it seems everythings works fine.
Thanks a lot.
import { open } from 'node:fs/promises';
let filehandle;
try {
filehandle = await open('thefile.txt', 'r');
} finally {
await filehandle?.close();
}
I wrote some node packages and use "type": "module" in pacakge.json and not use node: when I import native modules, I did not see any errors.
From the docs:
Core modules can be identified using the node: prefix, in which case it bypasses the require cache. For instance, require('node:http') will always return the built in HTTP module, even if there is require.cache entry by that name.

Vite: Cannot use import statement outside a module

I know little about bundler and I'm using vite to build project, I got a error when import some package to configure dev server :
SyntaxError: Cannot use import statement outside a module
So here is the thing:
import pinyin from 'pinyin/esm/pinyin-web.js'
export const somePlugin = {
name: 'someplugin',
configureServer(server) {
server.middlewares.use('/somepath', (req, res, next) => {
const foo = pinyin('foo')
next()
})
},
}
I don't use the normal way(import pinyin from 'pinyin') , because that need a package nodejieba which need to install unnecessary node-gyp, so I choose the web version that don't need nodejieba.
I've searched the error, some says add "type": "module" to package.json file. but it already exist in my package.json.
however, I make the change:
// import pinyin from 'pinyin/esm/pinyin-web.js'
import pinyin from 'pinyin/lib/pinyin-web.js'
and problem get solved,I was confused because I thought vite prefer ES module.
So,
1> what cause the problem above?
2> why should I import file with extensions ? eg: import pinyin from 'pinyin/lib/pinyin-web.js'
I have to add extensions .js or it will cause error. while in vite.config.ts I needn't add extensions.
3> I tried to add field optimizeDeps in vite.config.ts like this
export default defineConfig({
plugins: [vue(), somePlugin],
optimizeDeps: {
include: ['pinyin'],
},
})
but it seems to be useless, the offical doc says:
"During development, Vite's dev serves all code as native ESM. Therefore, Vite must convert dependencies that are shipped as CommonJS or UMD into ESM first."
did that work for the frontend part and package "pinyin" is for the dev server so whether add the
field optimizeDeps there is no difference.
codesandbox

Question regarding NPM, ReactJS, and installed packages both globally, and locally

Question regarding NPM, ReactJS, and installed packages both globally, and locally. I have done quite of bit of searching and found no real resolution. Here's my main App component:
import React, { Component } from 'react'
// import ReactLogger from 'react-terminal-logger/console-logger'
import 'whatwg-fetch'
import Intro from '../Intro/Intro'
import './app.css'
// ReactLogger.config({
// visible: ['log', 'error', 'info', 'warn', 'logr'],
// save_logs: false,
// only_msg: true,
// port: 1234,
// stacktrace_hide: true,
// })
// ReactLogger.start()
class App extends Component {
state = {
series: [],
logs: [],
}
componentDidMount() {
// Hook(window.console, (log) => {
// this.setState(({ logs }) => ({ logs: [...logs, Decode(log)] }))
// })
fetch('http://api.tvmaze.com/search/shows?q=Vikings').then((response) => {
console.log(response)
// logr(response)
})
}
render() {
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">TV Series List</h1>
</header>
<Intro message="Here you can find all you most loved series!" />
The length of the series array is - {this.state.series.length}{' '}
</div>
)
}
}
export default App
Any time I install a package globally, so I can reuse it in other projects I end up with an error when I try to start the server. Such as the logging package (above) react-terminal-logger. I used the following steps:
npm install -g react-terminal-logger
added import and initialized components as per instructions
tried to use component (eg. logr(response))
I end up with the same error at compile time no matter what I installed globally and add to my project.
C:\Users\DawsonSchaffer\Documents\ProjectsDirectory\Projects\reactjsx-tutorial-old\node_modules\react-scripts\scripts\start.js:19
throw err;
[Error: ENOENT: no such file or directory, stat 'C:\Users\DawsonSchaffer\Application Data'] {
errno: -4058,
code: 'ENOENT',
syscall: 'stat',
path: 'C:\\Users\\DawsonSchaffer\\Application Data'
}
My global package prefix points to "C:\Users\DawsonSchaffer\AppData\Roaming\npm" which is the default. If I simply remove the components use by it commenting out everything works.
How do I resolve this? What is the proper way to install a new global package and add it to an existing project? What am I missing? Any help would be greatly appreciated.
One other note, if I install the component locally in my project it works fine. Overall point though is too not have to install it in every project.
Thanks
Dawson
The first thing to understand here is that the global install option of common JS package managers is not intended to facilitate shared project dependencies. To clarify, from NPM itself:
Installing a package globally allows you to use the code in the package as a set of tools on your local computer.
With that out of the way, the optimization you're looking for is a real one, but for different reasons than you may think. When thinking about dependency management, you're really thinking about a small subset of pros and cons related to deciding whether you want use a mono-repo, multi-repo (microservices) or some hybrid.
If you're dealing with entirely different projects that are using the same dependency, then ignore the previous paragraph as they should definitely each manage their own dependencies independently.
Maybe this answer could help you:
How do I install a module globally using npm?
Usually, global installation are meant to be for CLI tools or executable tools.
So I finally got it all straightened out. I uninstalled react, react-dom, and react-scripts from global; leaving me with only create-react-app. I created an empty project called react-boilerplate, and installed react, react-dom, react-scripts, and react-router-dom in the new project. I then uploaded to my GitHub account so I have a common starting point for new projects. Should have thought about this before but it took me a while to wrap my head around everything. Now I can update my boilerplate as needed, and use it to clone as a starting point for new projects. Yeah!
Thanks to everyone especially Dennis G for all his help!!
Dawson

How to import a node module inside an angular web worker?

I try to import a node module inside an Angular 8 web worker, but get an compile error 'Cannot find module'. Anyone know how to solve this?
I created a new worker inside my electron project with ng generate web-worker app, like described in the above mentioned ng documentation.
All works fine until i add some import like path or fs-extra e.g.:
/// <reference lib="webworker" />
import * as path from 'path';
addEventListener('message', ({ data }) => {
console.log(path.resolve('/'))
const response = `worker response to ${data}`;
postMessage(response);
});
This import works fine in any other ts component but inside the web worker i get a compile error with this message e.g.
Error: app/app.worker.ts:3:23 - error TS2307: Cannot find module 'path'.
How can i fix this? Maybe i need some additional parameter in the generated tsconfig.worker.json?
To reproduce the error, run:
$ git clone https://github.com/hoefling/stackoverflow-57774039
$ cd stackoverflow-57774039
$ yarn build
Or check out the project's build log on Travis.
Note:
1) I only found this as a similar problem, but the answer handles only custom modules.
2) I tested the same import with a minimal electron seed which uses web workers and it worked, but this example uses plain java script without angular.
1. TypeScript error
As you've noticed the first error is a TypeScript error. Looking at the tsconfig.worker.json I've found that it sets types to an empty array:
{
"compilerOptions": {
"types": [],
// ...
}
// ...
}
Specifying types turns off the automatic inclusion of #types packages. Which is a problem in this case because path has its type definitions in #types/node.
So let's fix that by explicitly adding node to the types array:
{
"compilerOptions": {
"types": [
"node"
],
// ...
}
// ...
}
This fixes the TypeScript error, however trying to build again we're greeted with a very similar error. This time from Webpack directly.
2. Webpack error
ERROR in ./src/app/app.worker.ts (./node_modules/worker-plugin/dist/loader.js!./src/app/app.worker.ts)
Module build failed (from ./node_modules/worker-plugin/dist/loader.js):
ModuleNotFoundError: Module not found: Error: Can't resolve 'path' in './src/app'
To figure this one out we need to dig quite a lot deeper...
Why it works everywhere else
First it's important to understand why importing path works in all the other modules. Webpack has the concept of targets (web, node, etc). Webpack uses this target to decide which default options and plugins to use.
Ordinarily the target of a Angular application using #angular-devkit/build-angular:browser would be web. However in your case, the postinstall:electron script actually patches node_modules to change that:
postinstall.js (parts omitted for brevity)
const f_angular = 'node_modules/#angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/browser.js';
fs.readFile(f_angular, 'utf8', function (err, data) {
var result = data.replace(/target: "electron-renderer",/g, '');
var result = result.replace(/target: "web",/g, '');
var result = result.replace(/return \{/g, 'return {target: "electron-renderer",');
fs.writeFile(f_angular, result, 'utf8');
});
The target electron-renderer is treated by Webpack similarily to node. Especially interesting for us: It adds the NodeTargetPlugin by default.
What does that plugin do, you wonder? It adds all known built in Node.js modules as externals. When building the application, Webpack will not attempt to bundle externals. Instead they are resolved using require at runtime. This is what makes importing path work, even though it's not installed as a module known to Webpack.
Why it doesn't work for the worker
The worker is compiled separately using the WorkerPlugin. In their documentation they state:
By default, WorkerPlugin doesn't run any of your configured Webpack plugins when bundling worker code - this avoids running things like html-webpack-plugin twice. For cases where it's necessary to apply a plugin to Worker code, use the plugins option.
Looking at the usage of WorkerPlugin deep within #angular-devkit we see the following:
#angular-devkit/src/angular-cli-files/models/webpack-configs/worker.js (simplified)
new WorkerPlugin({
globalObject: false,
plugins: [
getTypescriptWorkerPlugin(wco, workerTsConfigPath)
],
})
As we can see it uses the plugins option, but only for a single plugin which is responsible for the TypeScript compilation. This way the default plugins, configured by Webpack, including NodeTargetPlugin get lost and are not used for the worker.
Solution
To fix this we have to modify the Webpack config. And to do that we'll use #angular-builders/custom-webpack. Go ahead and install that package.
Next, open angular.json and update projects > angular-electron > architect > build:
"build": {
"builder": "#angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./extra-webpack.config.js"
}
// existing options
}
}
Repeat the same for serve.
Now, create extra-webpack.config.js in the same directory as angular.json:
const WorkerPlugin = require('worker-plugin');
const NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin');
module.exports = (config, options) => {
let workerPlugin = config.plugins.find(p => p instanceof WorkerPlugin);
if (workerPlugin) {
workerPlugin.options.plugins.push(new NodeTargetPlugin());
}
return config;
};
The file exports a function which will be called by #angular-builders/custom-webpack with the existing Webpack config object. We can then search all plugins for an instance of the WorkerPlugin and patch its options adding the NodeTargetPlugin.

how to use node module with es6 import syntax in typescript

I have a typescript project which has uses one of our node modules which normally runs in our front-end. We are now looking to use this module in node on our server.
The module uses es6 import syntax import { props } from 'module/file'
When I include a ref in typescript using either of the following methods
import { props } from 'module/file';
var props = require('module/file');
I get the following error from typescript
unexpected token 'import'
(function (exports, require, module, __filename, __dirname) { import
It's a big job to re-write the module, and I've tried using babel with babel-plugin-dynamic-import-node, as well as SystemJS.
The problem with these systems is that they are all asynchronous, so I can't import the module in the standard fashion, so I would need to do a whole bunch of re-write when we get to the point that I can use import natively in node.js.
I can't be the first person to have this issue, but I can't seem to find a working solution.
--------------- update with set-up -------------
In response to #DanielKhoroshko's response. The original module I am trying to import is normally packaged by webpack in order to use on the front-end. I am now trying to use this same module both server-side and in the front-end (via webpack on the front-end) without re-writing the imports to use require and without running webpack to bundle the js to use on the server.
To be clear, the original module is written in JS, our service which is trying to use this module is written in typescript and transpiled. When the typescript tries to require the old module which uses import, it is at this point that we are running into the issue.
------------------ some progress ---------------------------
I've made some progress by creating a file in my imported module which uses babel in node.js to transpile the es6 code into commonJS modules.
I've done this via
var babel = require("babel-core")
var store = babel.transformFileSync(__dirname + '/store.js', {
plugins: ["transform-es2015-modules-commonjs"]
});
module.exports = {
store: store.code
}
I can now get the store in my new node.js project. However, the submodules within the store.js file are not included in the export.
So where in my module, it says
import activities from './reducers/activities';
I now get an error
Cannot find module './reducers/activities'
How can I get babel to do a deep traversal to include the sub-directories?
unexpected token 'import' means you are running es-modules code in environment that doesn't support import/export commands. If you are writing you code in TypeScript it's important to transpile it first before building for the browser or use ts-node to run it server-side.
If you are using webpack there are loaders ts-loader and awesome-typescript-loader
What is your setup?
To describe the module you would need to create an activities.d.ts file in the same folder where the js-version (I understood it is called activities.js and containers a reducer) resides with the following (approx.):
import { Reducer } from 'redux';
export const activities: Reducer<any>;
#Daniel Khoroshko was right in many ways, I ended up finding #std/esm which lets you import es6 modules and worked find for fetching the included imports as well.
var babel = require('babel-register')({
presets: ["env"]
});
require = require('#std/esm')(module);
var store = require('ayvri-viewer/src/store');
exports.default = {
store: store
}
I had to run babel to get a consistent build from es6 to node compatible es5

Resources