theseanl / tscc

A collection of tools to seamlessly bundle, minify Typescript with Closure Compiler
MIT License
161 stars 11 forks source link

TinyMCE getting replaced with TinyMCE.default #397

Open BrianLeishman opened 3 years ago

BrianLeishman commented 3 years ago

So far I've gotten most of our 3rd party libraries to import correctly, except for TinyMCE, which is being used like this

import tinymce from 'tinymce/tinymce'

tinymce.init({
    selector: '#blog-body',
});

based on the instructions here https://www.tiny.cloud/docs/advanced/usage-with-module-loaders/

which is outputting this js

(function(){'use strict';tinymce.default.init({selector:"#blog-body"});})()
//# sourceMappingURL=app.js.map

And my tscc.spec.json

{
    "modules": {
        "app": "ts/entrypoint.ts"
    },
    "external": {
        "jquery": "$",
        "sweetalert2": "Swal",
        "ladda": "Ladda",
        "tinymce/tinymce": "tinymce"
    },
    "prefix": "public_html/js/",
    "compilerFlags": {
        "rewrite_polyfills": true,
        "language_out": "ES5_STRICT",
        "compilation_level": "ADVANCED_OPTIMIZATIONS",
        "use_types_for_optimization": true,
        "output_wrapper": "(function(){%output%})()"
    }
}

But in the browser I now get a Cannot read property 'init' of undefined error. At the beginning of my compiled js it looks correct with var r=tinymce but later in the code calls r.default.init({selector:"#blog-body"})

How can I make this not get renamed to .default so it matches the externally loaded js?

I have attached an example project that compiles with just tscc from the root tinymce-ts.zip

BrianLeishman commented 3 years ago

Almost mediately sure this isn't an issue with this repo, because tsc gives me this output

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tinymce_1 = require("tinymce/tinymce");
tinymce_1.default.init({
    selector: '#blog-body',
});
//# sourceMappingURL=entrypoint.js.map
BrianLeishman commented 3 years ago

Interesting... If I basically pull the bottom of tinymce.d.ts out and move it into my own file like this

import {TinyMCE} from 'tinymce/tinymce'

declare const tinymce: TinyMCE
tinymce.init({
    selector: '#blog-body',
});

that compiles perfectly into

(function(){'use strict';tinymce.init({selector:"#blog-body"});})()
//# sourceMappingURL=app.js.map

with tscc and tsc

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
tinymce.init({
    selector: '#blog-body',
});
//# sourceMappingURL=entrypoint.js.map
theseanl commented 3 years ago

Hi, most likely the documentation on tinyMCE is assuming that you should be using "esModuleInterop" TS compiler flag. I suppose after you specify that flag, the tsc command will succeed.

Unfortunately "esModuleInterop" is not currently supported by tsickle, and IMO the support should be addressed from tsickle's side instead of tscc. For this particular tinyMCE module, there is no problem in using it without esModuleInterop -- you can just write import * as tinyMCE from 'tinymce/tinymce' although it is stated otherwise in the docs, and this should be fine.

BrianLeishman commented 3 years ago

I think I see more of what's happening. It seems for things that are imported from the @types directory, they just get replaced with their name when compiled. But when packages are compiled, they're replaced with package.default. That seems to be the common denominator between all of my imports.

Sweetalerts (Swal) actually has a Swal.default that's just defined as Swal somewhere in their CDN package that doesn't break when compiling, but almost all of my other imports are from @types.

Even with the flatpickr package, it's written in typescript so it has it's own types, so I can't import it at all because the compiler is replacing it with flatpickr.default which doesn't exist. I wonder if there's a way to treat a "module" the same way that "just types" are getting treated.

BrianLeishman commented 3 years ago

Actually that was wrong as well, axios has a @types/axios package but it still compiles to axios.default, so it doesn't get stuck like flatpickr does. But even though flatpickr has a @types/flatpickr that mirrors the axios one, it doesn't solve the .default issue.

BrianLeishman commented 3 years ago

Actually it looks like there is supposed to be handling for this, not sure I understand when it's supposed to take effect though, or how to force it to happen https://github.com/angular/tsickle/blob/master/src/googmodule.ts#L509