Typescript and React outputting require - javascript

I'm trying to get Typescript and React working together in MVC Core
The problem is the requirement for the following lines in my .tsx file:
import React = require('react');
import ReactDOM = require('react-dom');
These lines pass through both compilers becoming the following in the JS for browser processing:
var React = require('react');
var ReactDOM = require('react-dom');
Obviously, the browser cannot run these lines, because "require" is not a function in the browser
And yes, I can verify that both Typescript and React have processed the file.
Elsewhere on the site, it is suggested to use a global import, however this is a bad idea (it even says so in that post), I could also fix this by creating an empty function called "require", but that would also be bad practice
That this situation has arisen at all I find surprising, I thought the whole point of TypeScript was to take better code that the browser doesn't understand and transform it into equivalent code that it would. Thus, that TypeScript has allowed these lines to just pass through is baffling to me.
I have tried using the module directive in tsconfig.json to produce the required output, however there doesn't seem to be a browser compatible option
Is there a way to get React's babel compiler to eat the require functions? Has Typescript left them in because it expects React to do something with them?
EDIT: My question is different from the one suggested as a duplicate because it asks about module() and not import.
Though I suspect the answers to the 2 questions may be the same, suggestions on the accepted answer such as "just us a reference" don't work and although use of an external module loader should solve the issue, it's a broken solution
require() is not a part of browser based JS, therefore I don't want TypeScript to output it at all
EDIT2: Since more details of my setup have been requested, here you go:
The structure of my wwwroot/js directory is as so:
/def
..react.d.ts
..react-dom.d.ts
tsconfig.json
source .tsx and compiled .js files
Note that the d.ts files are copypasta from the repositories. There doesn't seem to be a way to load them in "properly" without adding ridiculous dependencies to the project such as node. NuGet modules that seem to do this in regular mvc have no functionality in mvc core
I've also tried moving the d.ts files to be in the same folder as everything else, this has no effect
tsconfig.json looks like this:
{
"compileOnSave": true, //Doesn't do anything? Build required to compile
"compilerOptions": {
"noImplicitAny": false,
"noEmitOnError": true,
"removeComments": false,
"sourceMap": true,
"target": "es5", //Is this the ES version I'm supposed to be typing in or the ES version to compile to? Irrelevant, changing this does nothing
"jsx": "react" //Using "preserve" outputs a jsx file to go through the React Babel compiler, does not solve issue
//"module": Irrelevant, a "don't worry I've got them covered" flag option doesn't exist, no options are suitable for browser use
//"noResolve": Irrelevant, does nothing
},
//"files":[] Explicitly including the d.ts files here doesn't seem to do anything, does not allow me to remove import lines
"exclude": [ //Have tried removing this, doing so has no effect, does not allow me to remove import lines
"node_modules",
"wwwroot"
]
}
Since I'm using Visual Studio everything compiles on build, I assume it's using tsc.exe under the hood
As for React... I have the following listed in the dependencies section of project.json
"React.AspNet": "2.5.0",
"React.Core": "3.0.0-rc1"
In startup.cs I have the following in ConfigureServices:
services.AddJsEngineSwitcher(
options=>options.DefaultEngineName = V8JsEngine.EngineName
).AddV8();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddReact();
...and the following in configure
app.UseReact(config => {});
For development purposes I have the following in my _Layout.cshtml
<environment names="Development">
<script src="https://unpkg.com/react#15.3.2/dist/react.js"></script>
<script src="https://unpkg.com/react-dom#15.3.2/dist/react-dom.js"></script>
</environment>
This is a learning project so it won't go to production mode, but if it did I would self-host the react source code and put it through the default bundler for bundling and minification. I don't believe that the positives of using a cdn outweigh the risks
I have tried using /// references, they seem to be a deprecated feature and in this case they don't do anything
I have tried using the following syntax to import react, but this also leads to different non-browser compatible code being output
import React = __React;
import ReactDOM = __React.__DOM;
It's important to note that both TypeScript and React work completely under these conditions on their own, no node dependency, no silly packing thing. It is only the TypeScript module system that insists on outputting things I don't need

Right so... after much much researching, my conclusion is that MVC Core, TypeScript and React shouldn't all go together just yet.
A lot of documentation and discussions hint at some sort of implicit referencing that's possible, and that seems to be the preferred way forwards when your project doesn't warrant a client-side module system, however... this feature doesn't seem to work with non-Typescript modules, or if it does it's so obscure and badly documented that I can't figure it out
....this could be one of those things where it's so obvious to everyone else that nobody bothers discussing it, if it is please let me know how stupid I am
The bottom line seems to be that if you want to use TypeScript's module system, you're supposed to have a browser-side module system that it can talk to.
I've looked over all of these and put a lot of work into understanding which is the best one for React and .Net
React places some extra constraints on this because you want to be using it's Server Side Rendering feature... like, you seriously want to be using that it's the best thing about React, so you need a module system that also plays nicely with it.
I've concluded that RequireJS is probably the right way to go for a number of reasons, for the client it's just 1 lightweight JS file, which compares nicely to the gargantuan JS behemoths of it's competitors, and it's own server side components have a .net version which should lead to an easier time making them work with React's server side stuff
....unfortunately RequireJS's server side components have a dependency on the old MVC for .Net Framework, so you can't use them in MVC Core yet, for now it's a dead end
Honestly, coming from a decade and a half of Javascript programming, I find this assumption on TypeScript's part that everyone is using a heavy client-side module system to be more than a little scary
I think it's important to remember that no matter what scripting you do for the browser, it all either runs in, or compiles back to, Javascript. This means that nothing you can bring in can possibly be more powerful than Javascript on it's own.
You use these things because they're quicker to code with, easier to test, show up errors at design time etc etc, i.e. they make life much easier for you and your team, but just like a box of pills, every single one of them has side effects and if you use too many they build up and cause problems
These module systems all look like great tools in the right projects, just like every "pill" in the "box" mentioned above, but I don't think they should be nearly as ubiquitous as TypeScript seems to assume they are
If you go for a small client stack that closely fits the needs of your project, and correctly segregate your JS into a global bundle, and a set of view-specific bundles your application can grow very large without encountering any of the issues that you want a heavy module system to solve
If you ever find yourself thinking you need such a thing, I would take the time to go back over your tech stack and really work out what each piece is doing for you and whether it's worth the cost to have it there, cutting that stack down is in many cases going to be a much better way to keep it stable than adding yet another framework to it
You've got to ask yourself what problems each tool is solving for you, whether it's successful in doing so, and if there's a better way... particularly one provided by another tool on your stack, a solution requiring no additional tools at all, or a solution provided by removing the tool that causes the issue as a side effect
I've seen a lot of people talking about these module loaders as a way to avoid clashes caused by adding things to the global namespace, and I'm sorry but moving all of those names to a module list so that they can clash there instead really doesn't solve anything
That in mind... webpack.... I think I jumped too early on the node dependency here, on taking a closer look I think it just uses node to compile things at design time, which is fine, as long as it doesn't want node on my production server we're cool but... all webpack is doing is taking your require lines and using them to inline other scripts, that's not what these lines are meant to be used for and using them in this way defeats the object of using them in the first place
All it seems to do is take the modules and dump them back into the global namespace where you didn't want them in the first place, furthermore if you're taking my advice above and making a global bundle, and one for each view that needs it's own tooling you're going to run into problems doing things the webpack way.... again, please correct me if I've misjudged this one
Well, that's the best answer that I can come up with for now, really hoping some people will show up and discuss it with me because it feels like I'm missing the point in a few places
For now I'm going to look into a bunch of React specific things and then maybe I'll see if I can get this stack working in MVC for Framework and see what changes
And if someone can come up with a better answer or a proper solution becomes available in a few months after the components have been patched a bit more then I'll move the green tick over

Obviously, the browser cannot run these lines, because "require" is not a function in the browser
Indeed. What tutorial are you following? You definitely need a module bundler in addition to TypeScript compilation e.g. here is a quickstart on webpack : https://basarat.gitbooks.io/typescript/content/docs/quick/browser.html

Related

Import, Require? How to Mash Javascript Files Together?

This is vague - I apologize in advance, I am trying to be as succinct as I can with my limited understanding, while exposing my potentially incorrect assumptions.
I have a website that's literally one huge HTML file. It runs scripts defined in-line in a <scripts> tag.
My goal is to move all the scripts into individual .js files and pull them into index.html (or into one another where required). I am familiar with the usage of Node's require and I am familiar with import, as used in Angular. I stress usage because I don't really know how they work.
Assumption 1: I cannot use require - it is purely for Node.js. The reason I bring it up is that I am pretty sure I have seen require in AngularJS 1.5 code, so assuming makes me uncomfortable. I am guessing this was stitched together by WebPack, Gulp, or similar.
Assumption 2: I should use import, but import only works with a URL address, if I have my .js hosted on a server or CDN, it will be be pulled. BUT, I cannot give local pathing (on the server) here - index.html will NOT automatically pull in the dependencies while being served. I need npm/Webpack/other to pre-compile my index.html if I want the deps pulled in on the server.
Assumption 3: Pre-compiling into a single, ready-to-go, html file is the desired way to build things, because the file can be served quickly (assuming it's ready to go). I make the assumption with the recent trend of serving Markdown from CDNs, the appearance of the JAMstack, and the number of sites using Jekyll and such (though admittedly for traditional Jekyll sites).
Assumption 4: I also want to go to Typescript eventually, but I assume that changes nothing, since I will just pull in TS to compile it down to .js and then use whatever solution I used above
Question: If it's clear what I am trying to do and what confuses me, is a decent solution to look into npm/Webpack to stich together my .js files? What would prepare them for being stiched together, using import/export? If so, is there an example of how this is usually done?
As you mentioned, require cannot be used for your purposes, since it is a part of CommonJS and NodeJS's module system. More info on require can be found here: What is this Javascript "require"?
Import is a ES2015 standard JS syntax. But ES2015 standard and everything above it has very limited browser support. You can read more about it here: Import Reference
However, you can still code in the latest standard (thereby enabling the use of import/export etc.,) and then transpile the code to be able to run on the browser. Inorder to do this, you require a transpiler. You can refer Babel which is one of the most popular transpilers : https://babeljs.io/
For your exact purpose, you need to use a module bundler. Webpack/Rollup etc., are some popular module bundlers. They can automatically identify all the JS files referenced through import, combine them and then transpile code to be able to run on the browser (they also use a transpiler) and produce a single JS file (or multiple, based on your configurations).
You can refer the getting started guides of Webpack: https://webpack.js.org/guides/getting-started/
or RollupJS: https://rollupjs.org/guide/en#quick-start

Gradually move from including each JS files to module bundling

In our AngularJS application we currently have a lot (400+) of files, which get included via <script>-tags. The order these files is something like this:
AngularJS script files
3rd party plugins / modules
business Logic files
modules
services
controllers / components / directives
We would like to move to a better approach utilizing a module bundler and TypeScript. New files are already written in TypeScript but don't make use of import/export. In order to make things easier, we could convert every JavaScript file into a TypeScript file and fix the resulting errors in a feasible time.
However, before we do this, we would like to have a viable strategy on how we could gradually make use of import/export. I'm thinking of something like rewriting one module from time to time, starting with modules deep down in the dependency tree.
However I was not able to achieve this, but I'm quiet sure that others already had to solve this before.
Once you decide on a module bundler, you'll need to learn about its facilities for (1) allowing other JavaScript on the page to access things defined in the bundle and (2) allowing the bundle to access things defined by other JavaScript on the page. (If you're able to migrate in strict dependency order, you might never need #2.) For example, for Webpack, #1 would be the library* output options and #2 would be externals. Then just move the code into modules little by little, adjusting the configuration as necessary so that each part of the code has access to the things it needs from the other part of the code. Since Webpack only supports a single library export module, during the transition, you may have to maintain a dummy module that just re-exports all modules that you need to access from code outside the bundle. This is a little tedious and represents extra work that you wouldn't have to do if you migrated all at once, but you may decide it's worth paying that cost in order to be able to migrate gradually.
If you have issues getting type information from TypeScript module files in non-module TypeScript files, see this answer for a workaround.

How do I build and validate a plain JavaScript-based code base?

My front end is an Angular 1.x project with tons of files. I basically need to validate it and find any errors that are there in any of the files. Specifically, errors that can break the page. In compiled/static type languages like Java, this is very easy, as the compiler will tell you exactly what's wrong. However, since JS is interpreted/dynamically typed, I can't figure out a way to "build" these files and find errors like I would for compiled languages. Going to every single page in the browser after I make any change is neither practical nor scalable.
I am also not using TypeScript or ES6 and it's not possible at the moment to migrate to any of them. Tools like ESLint and JSHint have also not been very successful, since they only bring out minor errors within that file. However, a lot of major code is spread over several files. Although my code is already all ES5, I thought about concatenating all JS files together in one file and running babel on it. But have it been sure how to manage dependencies during the concatenation (such as in what order to concatenate files).
This cant be the only project that uses vanilla JS and needs to be validated for errors. Anyone has any ideas on how I should go about accomplishing the task?
I highly recommend writing tests using jasmine and karma. I've found the two of these integrate really well with Angular and test driven development is highly regarded as one of the best development styles.
With all of this being said, I understand that's not what you're looking for directly because you want more of a "compiler" like solution. The closest thing that you can get to this in JS in my opinion is a linter and when combined with tests, this solution is rather good at finding errors in JS code.

Exposing a Node.js library via ambient TypeScript

In an attempt to simplify the use of pg-promise library for those who prefer coding for Node.js in TypeScript, I created a complete set of ambient declarations needed to fully represent the library, and included it into the distribution in a separate folder.
However, being not a proficient TypeScript developer, I'm stuck in my research for best practices in doing this sort of thing.
I want to know if simply including ambient declarations in a separate folder is sufficient for developers to start using it right away, without running into problems.
I also want to write some sort of a short guideline for how to use those TypeScript declarations, but frankly, I am myself not doing a good job at it, even though the declarations all seem correct.
So my question is then:
Is there any article or a guideline to explain it to Node.js developers how to do it with the latest version of TypeScript? (best practices for exposing a Node.js library via TypeScript)
UPDATE
One of the very first problems I'm running into, trying to use such ambient declarations directly, from a TypeScript file - the main file refuses to find the two dependent ones, no matter what change I try, it keeps on saying Cannot file module....
UPDATE
I've tried countless per-mutations for how to re-declare the library, and yet I haven't been able to get it work after all.
I've tried to move dependent declarations inside one file, using in their own namespace and as an inner namespace.
I've tried different combinations of ambient declarations with classic declarations.
I've tried changing modules into namespaces.
It only brought me to a point of desperation and dislike toward TypeScript. All I want is to make my Node.js library readily usable for TypeScript developers.
Most of the time I've running into issues where it says that my TypeScript is not a module. In other cases it couldn't find some types. Nothing but trouble. Please somebody help me with this.
UPDATE
Should I even include TypeScript with the library or should it be published on Definitely Typed instead?

How to unextend Extendables framework, keeping just the logger and Jasmine test functionalities

I'm using a nice framework for Adobe ExtendScript called Extendables. I forked the project here: https://github.com/daluu/Extendables
A problem though is that in some ways using the framework is worse than not because the framework extends javascript objects with more functionality. And on an initial review of the code files, they seem rather interdependent such that it will take some work to uncouple the strict dependencies to make it optional/configurable to load only what you need and skip the rest in case of issues with particular features (i.e. you can just not load/include what you don't use - I don't think that's currently possible, although I might be mistaken). See the issue tracker in my project for details but in general the issues encountered using the full framework is failure of try/catch blocks and object iteration includes unintented properties.
For me, I'd just like at a minimum to make all functionality optional and just load the logger and Jasmine test framework as those are the only two feature/modules that I really use with Extendables. I don't care for the extensions to strings, files, object, arrays, etc.
As I'm a novice in javascript/ExtendScript, and this is not a trivially simple javascript framework, I could use suggestions on how to decouple the dependencies so that every module (baring it's dependendencies) can be optionally loaded, and where there are dependencies we can group into sets as in you can load or not load this set of features.
Sorry that I can't include code snippets as its too much to post, you can find it in my Github fork.
Not sure if this is best StackExchange site to post but starting here.
You should be able to extract the log module from this file:
https://github.com/daluu/Extendables/blob/master/core-packages/logging/lib/index.jsx
Try to use it like this (not tested):
#include "core-packages/logging/lib/index.jsx"
Log.debug("Log this");
You might need to adjust some things in there e.g. Folder.extendables does not exist in ExtendScript. Also exports.Log at the end will throw an error.

Categories

Resources