New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to build a project webpack with namespaces? #18240

Closed
acopalipsis opened this Issue Sep 4, 2017 · 11 comments

Comments

Projects
None yet
6 participants
@acopalipsis

acopalipsis commented Sep 4, 2017

Batman.ts

namespace hero {
    export class Batman {}
}

Superman.ts

namespace hero {
    export class Superman {}
}

hero.ts

export const Batman = hero.Batman;
export const Superman = hero.Superman;

webpack compile

... webpack helpers

/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
const Batman = hero.Batman;
/* harmony export (immutable) */ __webpack_exports__["Batman"] = Batman;

const Superman = hero.Superman;
/* harmony export (immutable) */ __webpack_exports__["Superman"] = Superman;



/***/ })
/******/ ]);
});

If you remove the namespaces, then the project compiles as expected. But with namespaces is compiled only hero.ts. What's the matter?

I need the Declaration of the wrapped contents into namespaces. And important condition is to collect project webpack.

@DanielRosenwasser

This comment has been minimized.

Member

DanielRosenwasser commented Sep 5, 2017

Hey there, this issue tracker isn't meant to work as a support forum. These questions tend to be better suited for StackOverflow. You may want to open a question up there instead. Thanks!

For the record, you have namespaces that are in global files (i.e. files that have no import/export), but Webpack operates on modules. Namespaces don't merge across module boundaries, so you'll just get funky behavior. Our advice is just not to use namespaces; use modules.

@acopalipsis

This comment has been minimized.

acopalipsis commented Sep 5, 2017

@DanielRosenwasser The fact that I'm writing a library which has only one entry point. That is, in order for it to work correctly, the Declaration must export only one module, and the description must be in a namespace. But generators .d.ts declare module for each module. But this is not correct. To rewrite by hand the modules namespace is not very desirable. What to do in such cases?

On so on complex issues-rare issues quoting the documentation, which I know by heart. And the answer You gave me, I already know. I thought that there is something not documented, especially for such cases.

@kitsonk

This comment has been minimized.

Contributor

kitsonk commented Sep 5, 2017

Typically when people have a single entry point, the import the sub-modules into the main module which provides the single entry point. Again this isn't TypeScript thing, it is more how to properly structure web application code.

@acopalipsis

This comment has been minimized.

acopalipsis commented Sep 5, 2017

@kimamula I understand it! But the Declaration is generated for each module at a time as you need only one, which is the entry point. hide other modules by using namespace. But namespace doesn't work with modules. I do not understand why typescript is not provided.

Batman.ts

export class Batman {}

Superman.ts

 export class Superman {}

hero.ts

 export {default as Batman} from "Batman";
 export {default as Superman} from "Superman";

hero.d.ts

declare module "hero/Batman" { // visible in autocomplete, but the import fails
 export default class Batman {}
}

declare module "hero/Superman" { // visible in autocomplete, but the import fails
 export default class Superman {}
}

declare module "hero" {
 export {default as Batman} from "Batman";
 export {default as Superman} from "Superman";
}

You can say anything, but this declaration will still be wrong.

@kitsonk

This comment has been minimized.

Contributor

kitsonk commented Sep 5, 2017

I don't think you understand modular/UMD declarations and instead of trying to force ambient/global declarations where they are not required or needed.

UMD declarations were introduced in TypeScript 2.0 and are the best way to deal with distributing modular code as a library. When you emit modules with the --declaration flag, TypeScript will emit a single declaration file per module. When you are authoring TypeScript downstream, when you attempt to import the module, using something like node resolution, TypeScript will resolve the .d.ts file the corresponds with the import and handle the appropriate name-spacing without you having to be explicit about it.

You keep saying "we aren't listening" or "don't understand" but honestly, I am the project lead for a large library built on TypeScript with hundreds of modules in 20+ packages (@dojo). I might actually know what I am talking about.

@acopalipsis

This comment has been minimized.

acopalipsis commented Sep 5, 2017

I don't think you understand modular/UMD declarations and instead of trying to force ambient/global declarations where they are not required or needed.

I began to write in js, even when es5 was not and went through the entire evolution of the modules until today. But I don't understand why typescript perverted es6 modules. why was it necessary to introduce a namespace and others? I would be very grateful if You would my code showed how to do that in typescript.

When you emit modules with the --declaration flag, TypeScript will emit a single declaration file per module.

Yes, but the entry point one! Autocompletion will display me as "Batman" and "hero/Batman". First way will result in an error. You can create ten large projects, but the knowledge they will not add, if You're so confident. And can give You advice functions validators made to stand in a separate file, instead of writing them as a schoolboy in the file, where the declared class.

@kitsonk

This comment has been minimized.

Contributor

kitsonk commented Sep 5, 2017

But I don't understand why typescript perverted es6 modules.

The namespace syntax was a solution to an early spec solution of ES Modules. TypeScript continued to adapt as the standard evolved, but to avoid breaking syntax backwards compatibility was preserved. That is not the way to structure your code these days as both I and Daniel have indicated.

You ask for help and then suggest that I am not capable of helping you (and essentially insult me). Clearly I am not capable of helping you. Good luck in your endeavours.

@acopalipsis

This comment has been minimized.

acopalipsis commented Sep 5, 2017

@kitsonk I'm sorry that You are offended by the words of the school code. But it's true.You have to config the build I saw nothing special, except for obsolete grunt. So Your words about denial of care seem to me to be a whimsical attempt to hurt me. nevertheless, the problem exists, but I guess You really don't realize it. I spent the whole day reading github and so, but on similar issues, I see only links to very different topics.

@AnimaMundi

This comment has been minimized.

AnimaMundi commented Jun 9, 2018

😄

@Samoji

This comment has been minimized.

Samoji commented Jul 24, 2018

@acopalipsis the most efficient way I found is this one:

// Batman.ts
namespace hero {
    export class Batman {}
}

// this will expose to global scope everything you exported in the namespace
window.hero = { ...window.hero, ...hero } 

same for Superman

// Superman.ts
namespace hero {
    export class Superman {}
}

window.hero = { ...window.hero, ...hero };
@aminnairi

This comment has been minimized.

aminnairi commented Sep 9, 2018

I have exactly the same problem as OP described. I even got further by setting the compilerOptions.stripInternal to true in the hope that /** @internal */ annotations were recognized. But they were not.

I finally decided to not use namespace and modules at all and just use TypeScript as a typechecker more than a module resolver. It's just so frustrating that these little annotations do not work. I think it would be perfect to have something like that:

// internalLogic1.ts
/** @internal */
export function internalLogic1() {
}
// internalLogic2.ts
/** @internal */
export function internalLogic2() {
}
// awesomeHelper.ts
import { internalLogic1 } from './internalLogic1'
import { internalLogic2 } from './internalLogic2'

export function awesomeHelper() {
  internalLogic1()
  internalLogic2()
}

And only have the following output (with ts-loader):

$ ls dist
awesomeHelper.js
awesomeHelper.d.ts

What is currently happening is that the bundle get compiled correctly, but we end up with that structure:

$ ls dist
awesomeHelper.js
awesomeHelper.d.ts
internalLogic1.d.ts
internalLogic2.d.ts

Which is not the expected behavior for someone who want to make a library for Node & Web targets. Which is why Webpack is helping in this way with the umd target. But TypeScript keeps generating those definition for all modules, whether they are part of the /** @internal */ or not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment