When I work with angular2 code I often need to see the implementation of a class, let's say the Router class.
If I click on the Router type in my IDE WebStorm, e. g. inside the constructor of another class
export class myClass {
constructor(private router: Router) {}
// ...
}
my IDE takes me to the TypeScript definition file router.d.ts inside my node_modules folder. What I want is it to take me to the original router.ts file with the implementation of the router class, not just its definition.
The original .ts file is not included in the node_modules folder structure when you get angular2 from github via the standard package.json suggested in the Angular2 Quickstart. Currently, I have to look up the original code in the official github repo.
Any ideas how to get the .ts files into my node_modules/#angular folder instead of the .d.ts files?
Sadly, it's not possible since no TS files exist. Even if you add them it still not possible since you import real angular paths which always point to the definition files. On top of that the file structure of the project does not correlate to the structure of the import string literals.
Some background and more information
The NPM package does not include .ts files, this is by design from the angular team. Up until some time ago the .ts files were indeed supplied with the NPM package.
The reasoning for removing them is to disable abuse from users accessing private classes and #internal and private APIs which is public methods/properties in the API that are not supposed to be public but must be so other angular internal classes can use them.
We used to see a lot of code samples out there doing things like import { PromiseCompleter } from 'angular2/src/facade/lang'; (before RC0) but this was changed when the project structure had a big structure refactor in RC0. This abuse was wide and it's bad, very bad... For users and for Angular PR.
The Angular project has a complex and robust build process where all of the API is moved from .ts files into d.ts files using an automated process that limits exposure. (public_api_guard)
The end result is d.ts files only.
It's also not possible to clone the git repo and use it since, again, the file structure is way way different so imports will have to change. Most importantly without the build Angular will, most likely, not work.
A solution using a different approach
However, if you debug your app you notice that you reach actual angular core .ts files in the source view of the console, this is because the NPM package comes with source map files that include the whole TS source code. Nice trick they did there.
This is what I use to dig deep into angular, it works quite great and I get a lot from it.
It's not as nice as Goto Declaration but it something...
IMO it's also easier to understand when you step through code...
Related
I have a nodejs project (in JS). Unfortunately, I have to utilize a lot of node global variables.
Everything works fine (even a lot of people are suggesting not to use globals) except thing:
There is no intellisense for globals. So every time I want to use, let's say, global function/object I need to look in its code and figure out what are the
parameters, what does it return, etc.
Let's say I have a global variable which is a pure object:
foo = {
bar: {
level2: {
level3: {
level4: "abc
}
}
}
}
It's quite annoying to deal with it since I can't "see" the structure of the object when using it and it's easy to make a mistake when writing code.
The reason why I posted this question is the ...npm packages
There are plenty of packages written in vanilla JS and most of them are utilizing the power d.ts files.
Once you install the package you can use it from any place in your projects and VS code will have intellisense for them. If you will click on tooltip (IDK how it's called... Type definition tooltip?) of VS code
you will be navigated to the d.ts file of the package (not the actual implementation of the command).
So my question is how to do the same in my project. I'm not going to publish it as npm I just want a d.ts file somewhere in the project so I can
use my global without looking into its implementation every time I need to recall what it does.
Let inside your .d.ts file be anything
To access variables, functions, interface add this line in your .ts file, VS code IntelliSense will suggest you
/// <reference path="./test.d.ts" />
If you want to use this test.d.ts all over your project not just on any particular file. Then add this line in tsconfig.json
"files" : [ "./src/test.d.ts" ]
Update as mentioned in the comment section
my js file which I am assuming similar to what you are trying to do
export const testString = 'aditya';
in your js file you
/// <reference path="test.js" />
Regardless of if it is possible or not, the worst drawback of what you are looking for is that the declaration file(s) must be kept updated by hand each time a global variable/function is changed.
There are plenty of packages written in vanilla JS and most of them are utilizing the power d.ts files.
Usually .d.ts files are not written by hand, but are produced by tsc: many of the packages you are speaking about are probably written in TypeScript and distributed as JavaScript packages (to be used in JavaScript projects as well) with an associated index.d.ts file (to be used in TypeScript projects)
even a lot of people are suggesting not to use globals
+1
I have a two-year-old AngularJs 1.x project, which is built with Gulp for development and Grunt for production (don't ask me why; I don't know either).
The build process is basically:
Compile all scss files into one css file
Merge all JS files into one JS file. We are not using any import mechanism. Each file is basically one of AngularJs' controller, component, service or filter. Something like this:
angular.module("myApp").controller("myCtrl", function() {//...});
Merge all html templates into one JS file. Each template is hardcoded with $templateCache.
Moving assets like images and fonts into the build folder.
Moving third-party libraries into the build folder.
Now I want to switch to webpack for this project. I want to incrementally modernize this project, but the first step would be just building it with webpack with a similar process like the above. I would like to keep the code base as much the same as possible. I don't want to add import for all the JS files yet. There are too many. I would also like to add a babel-loader.
I have some basic concepts about webpack, but never really customized the configuration myself.
Would anyone please give me some pointers? Like which loaders/plugins would I need, etc.? Thanks!
My process to do such a transition was gradual, I had a similar Grunt configuration.
These are my notes & steps in-order to transition to Webpack stack.
The longest step was to refactor the code so it will use ES6 imports/exports (yeah, I know you have said that it is not a phase that you wanna make, but it is important to avoid hacks).
At the end each file looks like that:
//my-component.js
class MyComponentController { ... }
export const MyComponent = {
bindings: {...},
controller: MyComponentController,
template: `...`
}
//main.js
import {MyComponent} from 'my-component'
angular.module('my-module').component('myComponent', MyComponent);
In order not going over all the files and change them, we renamed all js files and added a suffix of .not_module.js.
Those files were the old untouched files.
We added grunt-webpack as a step to the old build system (based on Grunt).
It processed via Webpack all the new files (those that are without .not_module.js suffix).
That step produced only one bundle that contains all the files there were converted already, that file we have added to concat step.
One by one, each converted file gradually moved from being processed by Grunt tasks to be processed by Webpack.
You can take as a reference that webpack.config.
Good luck.
I read the Typescript Handbook and searched quite a bit but I still cannot find the proper way to do that: use existing js files as reference in my ts files and not have them in the emitted js file.
For instance, let's say my structure is like this in my web project:
- js/
- old-lib.js
- app-output.js
- new-lib-output.js
- app-src/
- newLib/
- my-lib.ts
- tsconfig.json
- app/
- my-app.ts
- tsconfig.json
In my-app.ts file, I have something like this:
namespace App
{
export class MyApp
{
... some logic which requires existing code from my old-lib.js file.
}
}
So if I use a triple-slash reference to the said js file, my output file is gonna include the source lib file as well. How do I get rid of that? I understand I can create and Interface to map declare the types and functions contained in my old js but is there a better way?
Also, following the same principle, I want to use a new lib (with different functions of course) and have it compiled separately (new-lib-output.js and app-output.js). Everywhere I look I see examples of modules importation but nobody talks about the exported js as in all examples it seems the output is all together in the same file.
My goal is to be able to reuse js files in different contexts, now always with my app but with other apps.
Thanks for any help you could provide!!
I'm a beginner at using js modules.
I'm working on a fairly simple web application. It uses typescript and angular 2, which heavily relies on modules.
Most of my app ts files 'import' one or many js modules (usually mostly angular 2 modules).
As I understand, because my app ts files have a top level 'import', they are automatically considered a js module by typescript.
However, I want any of my app ts files to be accessible by any other of my app ts files, without having to 'import' each other. But because they are now modules themselves, ts requires me to do that...
Is it possible?
It seems crazy to me that for each of my app ts file, I should have to declare every other of my app ts files that are used in there (I like to have tiny files with a single class/interface). In addition, this relies on relative paths which breaks as soon as I restructure my folder structure.
Am I thinking about this the wrong way?
You must have a js file which is an entry point to your application right?.. So in that file just import all the modules which you want to access without importing and attach them to the window object. Since the window object is available globally, you can access your module from anywhere without importing the corresponding module. For example,
Consider this scenario:
You have a module in a file called module1.ts
The entry point of your application is a file called index.ts
And you have a module2 where you require something from module1
// module1.ts
function add(first: number, second: number): number {
return first + second
}
export {add}
in your index.ts
// index.ts
import {add} from '<path to module1>/module1';
window.add = add
Now in your module2
// module2.ts
window.add(1, 2)
Since the window object is available globally you can attach as many properties to it as you like.
As far as the type resolution is concerned you can declare a window module with the add function you require in a .d.ts file as follows:
declare module window {
add: (first: number, second: number) => number
}
Declaring dependencies (e.g modules) for each file is a double-edged sword.
The advantage is that there is no 'magic' - you know exactly where each function, variable, class etc. is coming from. This makes it much easier to know what libraries / frameworks are being used and where to look to troubleshoot issues. Compare it to opposite approach that Ruby on Rails uses with Ruby Gems, where nothing is declared and everything is auto-loaded. From personal experience I know it becomes an absolute pain to try to workout where some_random_method is coming from and also what methods / classes I have access to.
You're right that the disadvantage is that it can become quite verbose with multiple imports and moving relative files. Modern editors and IDEs like WebStorm and Visual Studio Code have tools to automatically update the relative paths when you move a file and also automatically add the imports when you reference code in another module.
One practical solution for multiple imports is to make your own 'group' import file. Say you have a whole bunch of utility functions that you use in all your files - you can import them all into a single file and then just reference that file everywhere else:
//File: helpers/string-helpers.ts
import {toUppercase} from "./uppercase-helper";
import {truncate} from "./truncate-helper";
export const toUppercase = toUppercase;
export const truncate = truncate;
Then in any other file:
import * as StringHelpers from "../path-to/helpers/string-helpers";
...
let shoutingMessage = StringHelpers.toUppercase(message);
The disadvantage of this is that it may break tree shaking, where tools such as webpack remove unused code.
Is it possible
Not in any easy way. The ts file is a module and uses e.g. module.exports (if commonjs) that will need to be shimmed out. And that is just the runtime story. The TypeScript story will be harder and one way would be to make a .d.ts file for the module stating the contents as global.
Like I said. Not worth doing. Modules are the way forward instead of making something hacky.
It's not crazy at all. You are definitively thinking in the wrong way.
Actually what you don't like it's a common feature in all modern programming languages and it makes the code and structure of the app a lot clearer and simple to understand.
Without imports and going to old school way looks very crazy to me :)
You can have only chaos with so many global variables.
I'm currently working on a big JavaScript project for which we want to define our own API. I'm using RequireJS as my dependency loader and it suits me just fine, allowing me to define modules in their respective file. I do not make use of my own namespace, a module returns an instance, which can be used in other modules, i.e.:
define(
['imported_module'],
function(module){
module.doSomething();
}
)
However as the number of files grows, I'd like to decide how to structure these files in folders. Currently I use the following scheme to name my files:
[projectname].[packagename].[ModuleName]
An example could be stackoverflow.util.HashMap.js. I would like to introduce a project folder, a folder per package and rename the files to the module name, like:
stackoverflow/util/HashMap.js
This structures my code quite neatly into folders, however the filename reflects only the module now. I'd like to define some kind of routing to be able to define how RequireJS should look for files. Example:
The file
stackoverflow/util/stackoverflow.util.HashMap.js
Should be importable by the statement
define(['stackoverflow.util.HashMap'],function(HashMap){});
Has anyone experience with structuring large JavaScript projects and if so, could you share your approach?
You shouldn't specify the routing info on your js file names, those are the namespace and folder paths' jobs. So stackoverflow/util/HashMap.js is just fine. And you can use define("stackoverflow/util/HashMap", ....) to tell the dependency.
If you need to put your modules in a different folders, you can config paths for your loader, see this manual from RequireJS API.
There's no best way for structure your js files. But put the root namespace in a src folder is always a good practice. You can see the dojo source code and YUI source code and use similar ways for your project. They both are large scale Javascript projects.
actually it's better to get js lib routing to load all js using standard interface: "js.yoursite.com/lib-0.2.js" there should be a router (php or other, and able to cache queries). So there you could determine and control whole pathes that you use. Because common jquery plugin should stay at one dir, with jquery, and your own custom plugins not.
And there you control each project by it's own rules:
jquery/
plugins/
jquery.prettyPhoto.js
jquery.min.js
mySuperJS/
stable.0/ -- there your production version for 1.0 branch
module.js
0.1/
module.js
0.2/
module.js
0.3/
module.js
myOtherlib/
stable.0/ -- production version for all 0.* versions
stable.1/ -- production version for all 1.0 versions
0.1/
0.2/
0.3/
0.4/
0.4.1/
0.4.1.18/
We're using such structure around a year and it's the best for us. But sometimes we use more complex solution and separate all modules for libs, plugins, tools, components and apps.