Module parse failed? I need help setting up Babel - reactjs

I'm writing my first JavaScript library and I'm testing it locally with a React project. I'm not seeing any Typescript errors when I'm writing my code but when I run yarn start for the React project that it linked to I'm getting the following error:
ERROR in ../test-lib/src/add.ts 3:29
Module parse failed: Unexpected token (3:29)
File was processed with these loaders:
* ./node_modules/#pmmmwh/react-refresh-webpack-plugin/loader/index.js
* ./node_modules/source-map-loader/dist/cjs.js
You may need an additional loader to handle the result of these loaders.
| __webpack_require__.$Refresh$.runtime = require('/home/aaron/projects/react-projects/test-app/node_modules/react-refresh/runtime.js');
|
> export default function add(a: number, b: number) {
| return a + b
| }
I edited this question to simplify the problem after I did some research - which is it looks like I need to compile the typescript code in my library and export it to a dist folder? Then the React app that depends on it can use it.
I'm seeing articles about Babel and ones about Rollup and I'm confused about which I need (or both?) and why. Lots of outdated and incomplete/lazy tutorial articles that don't seem to help.
Can you help me set up what I need to get this to work? Here is the current file structure of my test library, test-lib:
node_modules/
src/
add.ts
index.js
package.json
tsconfig.ts
yarn.lock
Here are the contents of the pertinent files:
src/add.ts:
export default function add(a: number, b: number) {
return a + b
}
src/index.js:
import add from './add'
export default add
package.json:
{
"name": "test-lib",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
tsconfig.json:
{
"include": ["src/**/*"],
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
I'm aware I'll have to install #babel/... packages and the plugin for #babel/preset-typescript but I've left this out in the example because I wanted a freshly untouched typescript library for simplicity's sake. Help me start from scratch here.
I have additional questions as well:
Can I have all my files in *.ts format or does the entry point need to be a javascript file? (I'm assuming any *.config.* files probably need to be *.js as you need to start with javascript first so you can set up typescript for the rest of the project, right?
I've heard that I should compile my code for commonjs as well as esnext. Does my choice affect the needed libraries or steps to run their React app by the user that depends on my library?
The library I'm writing depends on React but it won't have any jsx/tsx files. It will have some custom React hooks though. Do I need to include the #babel/preset-react plugin as well?

Rollup or Webpack are module bundler and they handle files bundling only.
To transpile Javascript latest code to browser compatible code, we need transpilers like babel. There are plugins available for Rollup and Webpack to handle this transpiling of code, Babel is such a plugin.
So Babel and Rollup are different tools, we can use Babel inside Rollup for transpiling of Javascript.
Let's take Webpack as bundler for your questions
What about typescript ?
We need some plugin to convert it into js, there are plugins like ts-loader for Webpack
What about entry point ?
You can use ts or js, it does not matter as module bundler will assign each file to it's corresponding plugin to handle based on the Webpack configuration during bundling.
Can I have all my files in *.ts format or does the entry point need to be a javascript file?...
Yes, you can have all files in .ts. You may need .tsx if you have jsx code.
I've heard that I should compile my code for commonjs as well as esnext...
Yes, it will affect the user as their browser can be old and will not support latest code.
The library I'm writing depends on React but it won't have any jsx/tsx files...
Do you have jsx code?, if yes then you will need this.
Note: If your full code is in typescript, you do not need babel, you can simply use ts-loader following below link.
You may want to follow this simple Webpack config for typescript - https://webpack.js.org/guides/typescript/

Related

VSCode not picking up jsx when tsconfig is extended

I've got a monorepo project structured in the following way
/web
/native
/tsconfig.json
tsconfig.json
My /native/tsconfig.json looks like this
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"jsx": "react-native"
}
}
But for some reason my .tsx files with some jsx in them return following error
[ts] Cannot use JSX unless the '--jsx' flag is provided. [17004]
When I typecheck using cli tsc, I don't get these errors.
You need to specify the folder like this in your tsconfig.
"include": [
"./src/ts/**/*" //Path to your source
],
"jsx": "preserve",
Typescript version in VsCode workspace and package.json are not equal.
To solve this problem in Vscode,
Open the tsx file. In right bottom corner you will find
2 click this button and choose change VS Code to use the workspace's version of Typescript.
The errors will disappear.

Can I move storybook directory to prjroot/build/storybook? (in React Native)

I'm intoroducing storybook to my React Native project.
Default storybook directory is located at the root of project as prjroot/storybook/.
But I wanna place it to prjroot/build/storybook/, because I wanna write the storybook config files in TypeScript, and build it into prjroot/build/storybook/ .
Is there any ways to make storybook recognize the moved path?
By adding the outDir option to your Typescript config.
tsconfig.json
{
"compilerOptions": {
"outDir": "build/",
...
}
}
Note that configuring the rootDirs may also be useful if you want to specify the source directories.
https://storybook.js.org/configurations/typescript-config/#tsconfigjson
EDIT: in your specific case, using react-native-storybook-loader, you have to configure it:
"prestorybook": "rnstl --outputFile ./build/storybook/storyLoader.js --pattern \"**/*.story.tsx\" --searchDir ./App"
outputFile with the new path
pattern to scan .tsx files
searchDir can be useful to ignore node_modules and prevent conflict

babel and reactjs: how to use es2015 style imports

I'm new to javascript and javascript build scripts, and I'm trying to build a "future-proof" build script for building a ReactJS/Redux app. I'm having trouble with getting imports to work between javascript files.
My question is what is the recommended approach to add support for es2016-style import statements?
As I've been trying to get this working, these are the questions and comments that are rolling around in my head that help color where I'm coming from.
I've just been getting a little more comfortable with Gulp. Is it possible to use just Gulp, Babel, and npm to add support for es2016-style import statements?
I'm wondering if Gulp still the recommended way to go for building javascript bundles, or should I learn WebPack instead.
In the past, I've used to use Browserify for including other javascript files, but I've heard people mention that you can do what Browserify does with pure npm and that Browserify may be falling out of favor.
I've noticed a lot of ReactJS examples using WebPack. I'm not sure where WebPack fits in or if it's necessary. I'm wondering if WebPack takes the place of Browserify and if I need WebPack or if I can do without it.
I'd prefer to use whatever import syntax is the recommended. I believe that Browserify uses require() and es2015 syntax uses "import ... from". I'm wondering if the "import ... from" is the recommended syntax to use for imports now or if I should be using something else.
I've been trying to use Babel 6 to use es2015-style code. I've noticed that it doesn't pre-process the import statements and I think I read somewhere that Babel 6 removed support for import statements. I'm wondering what to use in place of that to pre-process import statements.
I'd be interested in minimizing the amount of configuration (dot files and such) to build a basic project.
Below is a simple example that I've been trying to get working, using Gulp. Currently, when Gulp runs, is creates a bundle, but the import statement doesn't seem to work. When I try to load index.html, everything looks concated together and I get javascript errors.
more package.json
{
"name": "test_jsx",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"babel-cli": "^6.14.0",
"babel-plugin-transform-react-jsx": "^6.8.0"
},
"devDependencies": {
"babel-preset-es2015": "^6.14.0",
"babel-preset-react": "^6.11.1",
"babel-preset-stage-0": "^6.5.0",
"gulp": "^3.9.1",
"gulp-babel": "^6.1.2",
"gulp-cli": "^1.2.2",
"gulp-concat": "^2.6.0",
"gulp-print": "^2.0.1",
"gulp-sourcemaps": "^1.6.0"
}
}
more gulpfile.js
var gulp = require("gulp");
var print = require('gulp-print');
var sourcemaps = require("gulp-sourcemaps");
var babel = require("gulp-babel");
var concat = require("gulp-concat");
const paths = {
src: 'src/**/*js',
dest: 'build'
}
gulp.task("default", function () {
return gulp.src(paths.src)
.pipe(print())
.pipe(sourcemaps.init())
.pipe(babel({ presets: ['react', 'es2015', ]}))
.pipe(concat("bundle.js"))
.pipe(sourcemaps.write("."))
.pipe(gulp.dest("dist"));
});
more src/test.js
// This import statement is what I'm trying to get working.
import { square } from './lib';
var profile = <div>
<img src="avatar.png" className="profile" />
<h3>{[user.firstName, user.lastName].join(' ')}</h3>
</div>;
more src/lib.js
// This is just a example function that I want to try to import
export function square(x) {
return x * x;
}
more index.html
<script src="dist/bundle.js"></script>
TEST
Build steps
npm install
./node_modules/.bin/gulp
You can use either webpack or browserify to build your bundle, but they'll both be leveraging babel to provide ES6 support. I am not sure where you read that Babel 6 removed the import statement - I use Babel 6 and have had no such issue. You can build the bundle with gulp too but I find it's more work and tends to be harder to maintain. But, you might be getting a lot of opinionated answers here.
There is a tool that was provided by Facebook recently to bootstrap a React app without having to configure build tools: Create React App. You might want to either try that or one of the available boilerplate starters on Github, unless you like tinkering with build scripts. It's less flexible but if you are looking to reduce the amount of configuration it does the job.

Typescript compile errors when importing C3 and D3

I am playing with the graphing library C3 in an Ionic2/Angular2 typescript project. I have installed C3 via npm, and the type definitions via tsd.
I have imported when into my own ts file as follows..
import {Component} from '#angular/core';
import {NavController} from 'ionic-angular';
import * as C3 from 'c3';
import * as D3 from 'd3';
#Component({
templateUrl: 'build/pages/graphs-page/graphs-page.html'
....
})
All appears fine. I can see the typings for the C3 (and dependant D3), and also when I run everything seems to work.
However, when the application builds (when I run ionic serve), I always get the following typescript compile errors...
TypeScript error: D:/dev/ionic2/testcomonents/app/pages/graphs-page/graphs-page.ts(3,21): Error TS2307: Cannot find module 'c3'.
TypeScript error: D:/dev/ionic2/testcomonents/app/pages/graphs-page/graphs-page.ts(4,21): Error TS2307: Cannot find module 'd3'.
Does anyone have any ideas why I am getting these errors at build time, when I get no errors in the IDE (I am using vscode), and everything seems to work fine?
[EDIT]
I have since installed typescipt 2 and run with the --traceResolution flag. I can see that tsc only seems to look under various levels of node_modules and never looks under typings folder, which is where vscode is looking.
More confusing (to me) is how the c3.js source is included, when this is located under the node_modules/c3 folder. I have not specifically added any reference to c3.js, yet the graphs show up.
The settings in the tsconfig.json are
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"emitDecoratorMetadata": true,
"experimentalDecorators": true
},
"filesGlob": [
"**/*.ts",
"!node_modules/**/*"
],
"exclude": [
"node_modules",
"typings/main",
"typings/main.d.ts"
],
"compileOnSave": false,
"atom": {
"rewriteTsconfig": false
}
}
I have tried various edits in the above tsconfig.json but cannot get it to look in the typings folder.
So my questions now become
How to make Typscript look in the typings folder
How does the the actual c3.js file located at node_modules\c3\c3.js get included in the Ionic bundle (since I have not added a reference to it anywhere)
I think I now know the answer to this, but if I am incorrect, please correct me!
looking in the Ionic file D:\dev\ionic2\testcomponents\node_modules\ionic-gulp-browserify-typescript\index.js, there is the following src property
var defaultOptions = {
watch: false,
src: ['./app/app.ts', './typings/main.d.ts'],
so If I add the following to main.d.ts
/// <reference path="globals/c3/index.d.ts" />
/// <reference path="globals/d3/index.d.ts" />
the errors go away.
If I run tsc --traceResolution I still see errors, but my guess here is that running tsc from the command line does not include looking at the above Ionic script or main.d.ts.
To get rid of the error when using tsc --traceResolution, I tried added the following to the file D:\dev\ionic2\testcomponents\node_modules\c3\package.json
"typings": "../../typings/globals/c3/index.d.ts",
and then do the same thing for d3. But this then causes the following error when I run the Ionic build
TypeScript error: d:/dev/ionic2/testcomponents/app/pages/graphs-page/graphs-page.ts(3,21): Error TS2656: Exported external package
typings file 'd:/dev/ionic2/testcomponents/typings/globals/c3/index.d.ts' is not a module. Please contact the package author to update the package definition.
So, I think in the Ionic context, the correct thing to do is add the /// paths to the main.d.ts file.
The other question I had, ie how is the c3.js etc file included, this is all part of the Browserfity / gulp build, and this examines everything under the nodes_modules folder. They all have the packeage.json file, and, in the case of c3, we have the line "main": "c3.js".

How to transpile a Relay query from TypeScript to ES5?

I'm writing a web app in TypeScript. The app uses React and Relay from Facebook.
My TypeScript source code gets compiled into ES6 code using the TypeScript compiler TSC. Then, the ES6 code gets transpiled into ES5 code using Babel. In order for Relay to work in the browser, a Babel plugin needs to transform the Relay GraphQL queries: https://facebook.github.io/relay/docs/guides-babel-plugin.html. The problem is, because TSC first transpiles these queries, the Babel Relay plugin doesn't recognize them anymore so they don't get transpiled into something the browser understands, so the browser throws an error:
Uncaught Invariant Violation: RelayQL: Unexpected invocation at
runtime. Either the Babel transform was not set up, or it failed to
identify this call site. Make sure it is being used verbatim as
Relay.QL.
My TypeScript source code:
const SiteQuery = {
store: () => Relay.QL`query { site }`
};
... this gets compiled by TSC into something like this:
var SiteQuery = {\r\n store: function () { return (_a = [\"query { site }\"], _a.raw = [\"query { site }\"], Relay.QL(_a)); var _a; }\r\n};
... instead of something like this (because the Babel Relay plugin doesn't do its work properly):
var SiteQuery = {\n store: function store() {\n return (function () {\n return {\n fieldName: 'site',\n kind: 'Query',\n metadata: {},\n name: 'Router',\n type: 'Site'\n };
This is because the Babel Relay plugin doesn't recognize the transpiled version, and as a result it doesn't transpile the query into something the browser understands.
How to make this work?
The answers here were helpful, but I thought I'd share what finally worked for me.
Setup your babel-relay-plugin correctly. If you're running into problems here, I recommend using the npm package babel-relay-plugin-loader which then allows you to specify the location of your schema.json in package.json. For example:
{ "metadata": { "graphql": { "schema": "./schema.json" } } }
Setup your babel config correctly. It should look something like this:
{
"passPerPreset": true,
"presets": [
"react",
"es2015",
"stage-0"
],
"plugins": [
"babel-relay-plugin-loader"
]
}
},
Setup your tsconfig to target "es6" -- this actually was essential to make my setup work. ts-loader then compiles to es6 and Babel handles the transpile down to es5.
Finally, add the loaders to your webpack config. Remember, it applies these RIGHT to left. So, mine looks like this:
loaders: [
{
test: /.tsx?$/,
exclude: /node_modules/,
loader: 'react-hot!babel!ts-loader',
},
],
You need to tell the Typescript compiler to transpile to ES6, then use Babel with babel-relay-plugin and es2015 preset to transpile the code to ES5 to run in your browser.
I recommend using Webpack to orchestrate all this. These will get you started:
http://www.jbrantly.com/typescript-and-webpack/
http://www.jbrantly.com/es6-modules-with-typescript-and-webpack/
The posts were written for Babel 5.x, so you'll need to manually add es2015 preset to make sure Babel compiles the ES6 sources to ES6.
Just in case, when you say
My TypeScript source code gets compiled into ES6 code using the TypeScript compiler TSC. Then, the ES6 code gets transpiled into ES5 code using Babel.
You can instruct TypeScript itself to transpile directly to es5, just set target: 'es5' in tsconfig.json and that's it, hope it helps since you can eliminate babel from your compile chain.

Resources