How can I compile my Typescript into a single JS file with no module loading system?

16,819

Solution 1

The contents of your .ts files determines if this is possible or not...

If you avoid turning your TypeScript code a module (by avoiding top-level import or export declarations), the output from single-file compile will not include any dependency on a module loader.

For example: typescript compiler itself is written without any top-level import or export declarations, and thus compiles into a single-file .js without any loader dependency.

Note that its use of export within a namespace is not a "top level" export. Imports inside a namespace are possible but severely limited: an example here

"In TypeScript, just as in ECMAScript 2015, any file containing a top-level import or export is considered a module."

The typescript handbook

Solution 2

Use triple slash directives for the typescript-compiler (tsc)

Triple-slash references instruct the compiler to include additional files in the compilation process.

index.ts:

/// <reference path="./domHelpers.ts" />

function add(a: number, b: number): number {
    return a + b;
}

q('#sum').textContent = add(2, 5).toString();

domHelpers.ts

function q(query: string): Element {
    return document.querySelector(query);
}

function qa(query: string): NodeListOf<Element> {
    return document.querySelectorAll(query);
}

Build step:

tsc --out bundle.js ts/index.ts

Will produce bundle.js with contents

function q(query) {
    return document.querySelector(query);
}
function qa(query) {
    return document.querySelectorAll(query);
}
/// <reference path="./domHelpers.ts" />
function add(a, b) {
    return a + b;
}
q("#sum").textContent = add(2, 5).toString();

Solution 3

Here's the method I ended up using. This process will create a file that can be linked with a <script src="myModuleName.min.js"></script> tag on an HTML page for use in a browser.

  1. Install rollup and plugins (many plugins listed here are optional but this config should cover any way in which you use modules)

npm install rollup-plugin-buble rollup-plugin-commonjs rollup-plugin-node-resolve rollup-plugin-typescript rollup-plugin-uglify typescript --save-dev


  1. This example rollup configuration file shows how to prevent rollup from also bundling your dependencies. In this case, I'm using jQuery and Angular, but I don't want to include that in the package I'm providing to users--so I list them as external, and they both happen to have a global variable--this example file shows how to deal with that scenario:

rollup.config.js

'use strict';

import 'rollup';
import typescript from 'rollup-plugin-typescript';
import buble from 'rollup-plugin-buble';
import commonjs from 'rollup-plugin-commonjs';
import nodeResolve from 'rollup-plugin-node-resolve';
import uglify from 'rollup-plugin-uglify';
import {minify} from 'uglify-js';

/**
 * Default/development Build
 */
const config = {
    entry: 'src/index.ts',
    exports: 'auto',
    globals: {
        'jquery': '$',
        'angular': 'angular'
    },
    external: ['angular', 'jquery'],
    targets: [{dest: 'dist/myModuleName.js', format: 'umd', moduleName: 'myModuleName', sourceMap: true}],
    plugins: [

        typescript({
            typescript: require('typescript')
        }),
        buble(),
        nodeResolve({
            jsnext: true,
            main: true
        }),
        commonjs({
            namedExports: {
                'node_modules/jquery/dist/jquery.min.js': ['jquery'],
                'node_modules/angular/angular.min.js': ['angular']
            }
        })
    ]
}

// Minified JS Build
if (process.env.BUILD === 'minify') {
    config.targets = [{dest: 'dist/myModuleName.min.js', format: 'umd', moduleName: 'myModuleName', sourceMap: false}];
    config.plugins.push(
        uglify({}, minify)
    );
}

// Report destination paths on console
console.info(`\u001b[36m\[Rollup ${process.env.BUILD} build\]\u001b[97m \nConverting Typescript from ${
config.entry} to javascript, exporting to: ${config.targets[0].dest}`);

export default config

  1. Add scripts to package.json
    "scripts": {
        "build": "rollup -c rollup.config.js --no-conflict --environment BUILD:development",
         "minify": "rollup -c rollup.config.js --environment INCLUDE_DEPS,BUILD:minify"
    }

  1. Provide a file for rollup to consume:

src/index.ts

`export * from './myModule';`

  1. Optionally use a file to collect your modules for export if you're writing a library, these are the functions you intend to be publically available.

src/myModule.ts

export {myOtherClass, myFunction} from './myUtils/myFile';
export * from "./myUtils/myOtherFile";

  1. run npm run build or npm run build && npm run minify to also get the minified version.

Solution 4

Can you use the compiler itself? - as a post build process. TSC takes arguments allowing you to do this.

tsc --out compiledSingleFile.js one.ts two.ts

Or by using Gulp in your build pipeline -

https://www.npmjs.com/package/gulp-tsc

Solution 5

This is how i did it

  1. tsconfig file should set moduleResolution to classic
  2. tsconfig file should set module to none
  3. use Typescript namespace syntax and keep all your files in same namespace

Done !!!

this sol will only work who want no module system, with this sol you won't be able to use import export module system syntaxes

Share:
16,819

Related videos on Youtube

CodyBugstein
Author by

CodyBugstein

Aspiring computer nerd.

Updated on September 26, 2020

Comments

  • CodyBugstein
    CodyBugstein almost 4 years

    I have a small Typescript project of about 10 ts files. I want to compile all my files into es5 and into a single es5 file called all.js.

    Currently, with my tsconfig.json set up as

    {
      "compilerOptions": {
        "module": "system",
        "target": "es5",
        "outFile": "./all.js"
    }
    

    everything is getting compiled, but each file is being wrapped by

    System.register("SomeTSFile", [], function(exports_4, context_4) {
    ...
    }
    

    SystemJS looks cool but I am not in the mood to learn it now and I don't believe it is necessary. If I could get all my JS into one file, that will be perfectly sufficient for my needs.

    If I remove "module": "system",from my compiler options, my all.js file comes out completely blank. Apparently, this is because for some reason, you cannot use "modules": none when outputting to one file. (I don't get why)

    How can I compile all the TS into one JS file without having to involve SystemJS or any other complications?

    • artem
      artem almost 8 years
      Every .ts file is a module. If one .ts file references another, you can not make it work without module loading system. If you don't want it, concatenate all your .ts file into one and compile that file. This might require changing your code though.
    • artem
      artem almost 8 years
      Another option is to set "module": "amd", then you will need AMD loader instead of SystemJS.
  • CodyBugstein
    CodyBugstein almost 8 years
    I am doing this but it forces me to use SystemJS
  • CodyBugstein
    CodyBugstein almost 8 years
    Hmmm so I can have imports within a module section but not outside?
  • Burt_Harris
    Burt_Harris almost 8 years
    I don't think its that simple @CodyBugstein. Some forms of import are OK, but importing from a module isn't (if you are trying to avoid depending on a module loader.)
  • Burt_Harris
    Burt_Harris almost 8 years
    Note that you can use triple-slash directives to reference types in other typescript files without using imports, but that this does not take care of loading the other files (but of course compiling down to a single .js can make that moot.)
  • CodyBugstein
    CodyBugstein almost 8 years
    Ok i will try that
  • CodyBugstein
    CodyBugstein almost 5 years
    but then how do you import from one file to the other?
  • PopGoesTheWza
    PopGoesTheWza almost 5 years
    You don't have to use import less require with this settings. The output Code.js will be the concatenation of all valid source files. Valid source files are defined with the include and files properties of your tsconfig.json. The order in which files are concatenated can be controlled using the files property and /// <reference path="some.ts" /> directives. You can look at this repository for complete sample.