SystemJS with Typescript conflict? - angularjs

I am trying to configure SystemJS for an existing AngularJS + Typescript application.
I have a problem with module loading:
When I use this syntax:
import module1 from './path-to-module1'
TS compiler is happy but SystemJS will not find this module. After a little investigation I found this, on SystemJS documentation:
System.defaultJSExtensions = true;
// requests ./some/module.js instead
System.import('./some/module');
Cool, now both TS compiler and SystemJS work. But, SystemJS documentations says:
Note that this is a compatibility property for transitioning to using explicit extensions and will be deprecated in future.
So, I figured out that I should add a .js extention to my module loading, like this (removing the 'defaultJSExtensions = true' flag):
import module1 from './path-to-module1.js'
Now SystemJS knows how to load my module, by TS compiler says:
Cannot find module './path-to-module1.js'
How can I make TS figure this out? Should I manually add all my modules to a *.d.ts file? How?
10x!
EDIT
I found this post, which I guess should be what I need to do. I found this on my Grunt file:
typescript: {
build: {
src: ...,
outDir: '...',
reference: 'reference.ts',
options: {
target: 'es5',
sourceMap: false,
declaration: false,
removeComments: false,
experimentalDecorators: true,
module: 'commonjs'
}
}
}
But, changing the commonjs to system did not help hree..

Don't worry, the SystemJS documentation is a bit misleading... Once they remove the defaultJSExtension all you have to do it to mark your code directory as a package (In the systemJS configuration) You can read about it here
Anyway, the file name without the extension is a valid ES6 module import syntax, so SystemJS will have to support it, as I said they will support it using a different way in the configuration.

Related

Meteor - webpack and ecmascript are both trying to handle *.jsx

So I'm trying to install and use react-wavesurfer in Meteor which is a react component wrapper for an existing js library (wavesurfer.js). It requires that the wavesurfer.js file (which has to be installed separately) is made available as a global variable.
The suggestion is to use webpack for this as below :
// provide WaveSurfer as a globally accessible variable
plugins: [
new webpack.ProvidePlugin({
WaveSurfer: 'wavesurfer.js'
})
],
// Alias `wavesurfer` to the correct wavesurfer package.
// (wavesurfer.js has some non-standard naming convention)
resolve: {
alias: {
wavesurfer: require.resolve('wavesurfer.js')
}
},
I've never used Webpack (not entirely sure what it does) and I'm a Meteor / React newbie.
So I installed :
meteor add webpack:webpack
And now I'm getting the following error in the console :
While determining active plugins:
error: conflict: two packages included in the app (webpack:webpack and ecmascript) are both trying to handle *.js
error: conflict: two packages included in the app (webpack:webpack and ecmascript) are both trying to handle *.jsx
From the error I assume that ecmascript (again something I know nothing about) is doing a similar job to webpack already which is causing the clash?
So, my question... How do I set this up using ecmascript instead? I literally have no idea!
Try to use new package that I still maintain
https://github.com/ardatan/meteor-webpack

How to use a CommonJS module in React with Webpack?

I'm trying to install this React library:
html-2-jsx
Problem is, i don't know how to import it into React. The description says:
To use the Node.js module, require('htmltojsx') and create a new instance.
When i try to just require it in the React component, ESlint tells me:
File is a CommonJS module. It may be converted to an ES6 module.
Of course, when i try to run Webpack, i get errors.
The errors i get in Webpack:
Can't resolve 'child_process' in
'C:\xampp\htdocs\codeigniter_cms\public\node_modules\xmlhttprequest\lib'
And few errors of this kind:
Can't resolve 'fs' in
'C:\xampp\htdocs\codeigniter_cms\public\node_modules\cssstyle\lib'
How can this be done? To be honest, i find it a bit weird, that a library made for react, doesn't support ES6 import functionality.
Try adding this to your webpack config:
module.exports = {
...
node: {
fs: 'empty',
child_process: 'empty'
}
};
The warning you are seeing has nothing to do with those errors. If you'd like to fix the warning then it may require some context on where the warning occurs.

Setting up React router: how to use {import} in the browser?

I am following the React-router docs, but I have encountered an obstacle that is not really related to the router itself: Babel transpiles the {import} as require, which would be used by Express or Node.js on the server, but from what I understand from the docs, it is actually intended for client-side rendering.
Of course, the JSX file with the router transpiled using Babel and included into a HTML browser page does not work, since require is only used by express/node server-side.
May I ask how is it actually supposed to work in the browser?
Thank you
Babel's transpile of import produces code relying on CommonJS require, you're correct.
You're also correct that node offers a natire require implementation, whereas browsers do not.
There are tools - such as webpack, browserify, and requirejs (among others,) which each do at least two things:
to package up source into a single bundle
to expose that source in a way that satisfies require to match node, allowing you to use the same code at either side.
To that end, what you need to do is to pair babel with one of the packaging tools.
Webpack is more powerful; browserify is easier to use.
Here's a tiny gulpfile where I've automated the process. The relevant source clip is this:
gulp.task('browserify', ['babel'], function() {
var browserifyConfig = {},
bpack = browserify(browserifyConfig, { 'debug' : !production });
return bpack
.require('./dist/pbar.es5.js', { 'expose' : 'pbar' })
.bundle()
.on('error', errorHandler)
.pipe(source('pbar.es5.js'))
.pipe(gulp.dest('./dist'));
});
In order for commonjs like require statement to work in a browser environment. You will need to look into a bundling solution like:
https://webpack.github.io/
http://browserify.org/
A bundler will statically parse your commonjs files and their dependencies to create a bundle which can be used in the browser.
Internet is full of great examples on how they work.
Browserify is easier to get started than Webpack, however I would suggest you learn Webpack over Browserify. Webpack provides you much much more than just loading JS files with its extensive loaders, for example you can do something like:
const imgSrc = require('images/test.svg')
magical right?

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.

Webpack with angular 1.4 ES 5

I am working on an application which is build with angular 1.4 and ES5. It is using gulp to minify files. I wanted to use Webpack to leverage features like code-splitting and bundling everything in JavaScript files.
Is it even possible to use webpack with ES5 code as I see almost all blogs about WebPack deal with ES6. Any pointers will be greatly appreciated. Many thanks.
This is how my team did it. Essentially you want to create "entry point files" that perform requires for all your files, since this is how webpack works (it follows the dependency tree). Then point webpack at these "entry point files".
The example at the link above uses TypeScript, but you can easily use ES5 like this:
# ./entry-points/feature1.js
importAll = function(r) {
r.keys().forEach(r);
};
importAll(require.context('./app/feature1', true, /module\.js$/));
importAll(require.context('./app/feature1', true, /(^(?!.*(spec|module)\.js).*\.js)$/));
You can grab a polyfill for Object.keys here, and Array.forEach` here.
Then point to this file from your webpack config like this:
entry: {
'feature1': './entry-points/feature1.js'
}

Resources