How can I compile my Typescript into a single JS file with no module loading system?
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."
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.
- 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
- 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
- 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"
}
- Provide a file for rollup to consume:
src/index.ts
`export * from './myModule';`
- 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";
- run
npm run build
ornpm 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
- tsconfig file should set moduleResolution to classic
- tsconfig file should set module to none
- 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
Related videos on Youtube
![CodyBugstein](https://i.stack.imgur.com/SNvIc.jpg?s=256&g=1)
Comments
-
CodyBugstein almost 4 years
I have a small Typescript project of about 10
ts
files. I want to compile all my files intoes5
and into a singlees5
file calledall.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, myall.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 almost 8 yearsEvery .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 almost 8 yearsAnother option is to set
"module": "amd"
, then you will need AMD loader instead of SystemJS.
-
-
CodyBugstein almost 8 yearsI am doing this but it forces me to use SystemJS
-
CodyBugstein almost 8 yearsHmmm so I can have imports within a module section but not outside?
-
Burt_Harris almost 8 yearsI 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 almost 8 yearsNote 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 almost 8 yearsOk i will try that
-
CodyBugstein almost 5 yearsbut then how do you import from one file to the other?
-
PopGoesTheWza almost 5 yearsYou don't have to use
import
lessrequire
with this settings. The outputCode.js
will be the concatenation of all valid source files. Valid source files are defined with theinclude
andfiles
properties of yourtsconfig.json
. The order in which files are concatenated can be controlled using thefiles
property and/// <reference path="some.ts" />
directives. You can look at this repository for complete sample.