Configuring gulp with Angular & system.js - javascript

I have been searching through the web and found various tutorials covering this subject. However, most of the ones i have come across i cannot understand well enough, have been outdated, or do not cover the subject in enough detail.
I am simply trying to set up a gulpfile that will:
Compile a Typescript project
Copy required modules (Angular)
So that the result is a working Angular app. At this point, i am able to compile TS to JS, however, when i load main.js into index.html, i get the following error:
Uncaught ReferenceError: System is not defined
at main.js:1
With the code i have so far, i expected to receive the output of the aMethod function. If i remove "module": "system" from tsconfig, i am able to get the ouput in the node console, however.
I have added angular and its dependencies, together with system.js as npm packages.
My questions are:
What am i doing wrong at this point, since i cannot get any output from my transpiled TS app?
How do i utilize system.js with gulp, to create a task that will copy the #angular modules (core etc.) to my build dir, so my app can make us of Angular?
What are the advantages, when transpiling, to transpile the various typescript files into a single javascript file?
Thank you in advance. Any help is, as always, much appreciated.
Project files
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "system",
"moduleResolution": "node",
"experimentalDecorators": true,
"removeComments": false
},
"include": [
"src/app/**/*"
],
"exclude": [
"gulpfile.js",
"node_modules"
]
}
gulpfile.js
const gulp = require("gulp");
const del = require("del");
const ts = require("gulp-typescript");
const tsProject = ts.createProject("tsconfig.json");
const appDir = "build/js";
// Tasks
gulp.task("clean", function() {
del([appDir]);
});
gulp.task("compile", function() {
return tsProject.src()
.pipe(tsProject())
.js
.pipe(gulp.dest(appDir));
});
gulp.task("build", ['clean', 'compile'], function() {
});
main.ts
import { Test } from "./class";
let t1 = new Test();
t1.aMethod("test");
class.ts
export class Test
{
aMethod(s: string)
{
console.log(s);
}
}
index.html
<DOCTYPE html>
<html class="no-js">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Angular & Python App</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script src="js/main.js"></script>
</body>
</html>

Try this:
Copy all required dependencies to build directory and then build.
Create your gulp compile like this:
var typeScriptsPath = "src/**/*.ts";
const sourcemaps = require('gulp-sourcemaps');
const tsc = require("gulp-typescript");
/**
* Compile TypeScript sources and create sourcemaps in build directory.
*/
gulp.task("compile", () => {
let tsResult = gulp.src(typeScriptsPath)
.pipe(sourcemaps.init())
.pipe(tsc(tsProject));
return tsResult.js
.pipe(sourcemaps.write(".", {
sourceRoot: '/src'
}))
.pipe(gulp.dest("build"));
});
/**
* copy all dependencies to build directory
*/
gulp.task("libs", () => {
return gulp.src([
'core-js/client/shim.min.js',
'systemjs/dist/system-polyfills.js',
'systemjs/dist/system.src.js',
'systemjs/dist/system.js',
'reflect-metadata/Reflect.js',
'rxjs/**/*.js',
'rxjs/**/*.js.map',
'zone.js/dist/*.min.js',
'#angular/*/bundles/**',
'jquery/dist/*min.js',
'lodash/lodash.min.js',
'bootstrap/dist/js/*min.js',
'bootstrap/dist/css/*min.css',
'moment/min/*min.js',
'underscore/underscore-min*',
'angular2-cookie/**',
'moment/**'
], {
cwd: "node_modules/**"
}) /* Glob required here. */
.pipe(gulp.dest("build/lib"));
});
gulp.task("build", ['compile', 'libs'], () => {
console.log("Building the project ...");
});

You should use systemjs-builder to build main.ts file as same as systemjs file build it. So, your gulp file should be something like this:
var Builder = require('systemjs-builder');
var builder = new Builder('', 'systemjs.config.js');
gulp.task('dist',['compile', 'bundle']);
gulp.task('compile', shell.task([
'tsc'
]));
gulp.task('bundle', ['bundle:vendor', 'bundle:app'], function(){
return gulp.src(['./dist/*.js'], {base:"."})
.pipe(uglify({
compress: true,
mangle: true
}))
.pipe(gulp.dest('./'));
});
gulp.task('bundle:app', function () {
return builder
.buildStatic('app/main.js', './dist/main.bundle.js')
.catch(function (err) {
console.log('App bundle error');
console.log(err);
});
});
gulp.task('bundle:vendor', function () {
return builder
.buildStatic('app/vendor.js', './dist/vendor.bundle.js')
.catch(function (err) {
console.log('Vendor bundle error');
console.log(err);
});
});
where vendor.js file contains all angular vendors libraries like: 'zone', 'reflect' and 'core-js-shim'.
Now you can call gulp dist task to compile all your file.

Related

Can't access exported functions in bundled .js file using esbuild

I want to create a library using TypeScript. It should be available for Node and Browser environments.
I started with the package.json file and installed esbuild as a dependency and typescript as a dev dependency. The result is
{
"name": "my-lib",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc && esbuild ./dist/lib/index.js --bundle --minify --sourcemap --outfile=./bundle/index.js"
},
"dependencies": {
"esbuild": "0.14.36"
},
"devDependencies": {
"typescript": "4.6.3"
}
}
The tsconfig.json file contains
{
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"esModuleInterop": true,
"lib": [ "dom", "esnext" ],
"module": "commonjs",
"outDir": "dist",
"resolveJsonModule": true,
"strict": true,
"target": "es2019",
},
"include": [
"./**/*.ts"
],
"exclude": [
"./dist"
]
}
Inside the root directory I have a lib directory holding an index.ts file which exports all the "public" functions, e.g.
const sum = function (a: number, b: number): number { return a + b; };
export { sum };
Besides that I have a test directory right next to the lib directory, holding some .ts files. I want to test the build script and added the following index.html to the root directory
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript' src='./bundle/index.js'></script>
</head>
<body>
<div>
Loading bundle...
</div>
</body>
</html>
<script type="text/javascript">
window.onload = () => {
console.log('ready');
const result = sum(1, 2);
console.log({ result });
const anotherResult = window.sum(1, 2);
console.log({ anotherResult });
};
</script>
Unfortunately I get an Uncaught ReferenceError because it is not able to find the function sum. The folder structure before running npm install && npm run build is
Does someone know what's wrong or missing here?
If you want include your bundled javascript into html file via script tag (as in your example), you should add sum variable to page global variables scope like that:
const sum = function (a: number, b: number): number { return a + b; };
window.sum = sum;
// or `globalThis.sum = sum;`
Defining variable in global page scope makes it sure that no minification or renaming processes in bundler will break your app.
It would be better for you to check the concept of Commonjs and ECMAScript Module(ESM) before working. The compilerOptions.module in tsconfig.json is Commonjs, which is the bundling method used by Node.js. This does not work with browser. This is because the browser does not have the require method which can recognize the exports object and the module object, which is available globally in Node.js.
Therefore, when creating modules that support browsers, usually bundle them in UMD format using Webpack. If you don't support older browsers, you can think of bundling in the ESM way, even without a Webpack.
First, modify tsconfig.json as follows:
{
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"esModuleInterop": true,
"lib": [ "dom", "esnext" ],
"module": "esnext", // update
"outDir": "dist",
// "resolveJsonModule": true,
"strict": true,
"target": "es2019",
},
"include": [
"./**/*.ts"
],
"exclude": [
"./dist"
]
}
Next, modify the following HTML as follows:
<!DOCTYPE html>
<html>
<head>
<script type="module">
import {sum} from './dist/index.js';
window.onload = () => {
console.log('ready');
const result = sum(1, 2);
console.log({ result });
const anotherResult = sum(1, 2);
console.log({ anotherResult });
};
</script>
</head>
<body>
<div>
Loading bundle...
</div>
</body>
</html>
You can create library that work in your browser after npm install && npm run build.
If your library can be imported from another bundler (like a webpack), you want it to work in a browser, and you want to implement it using tsc only, see the following link.
Your code is fine, the problem is that you are using bad export. Exports a function that is never used and that is why the error. Then I show you how to solve this.
You must first bear in mind that nothing is exported in the index.ts. Rather the index.ts receives functions from other JS modules. Then create a Sum.TS file that will be a module where you will write the following code:
sum.ts
const sum = function (a: number, b: number): number { return a + b; };
export { sum };
In Index.ts imports the sum function of the module sum.ts the file must remain like this:
index.ts
import { sum } from "./sum";
sum
In this way you already have the sum function available to use in the index.html.
When you export functions these are not available in the compiled code. Only imports are available in the compiled code.
If you want to use the index.ts to store public functions the code should be like this:
const sum = function (a: number, b: number): number { return a + b; };
sum
update
Just change your index.ts to this:
const sum = function (a: number, b: number): number { return a + b; };
sum
and your index.html to this:
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript' src='./bundle/index.js'></script>
</head>
<body>
<div>
Loading bundle...
</div>
</body>
</html>
<script type="text/javascript">
window.onload = () => {
console.log('ready');
const result = sum(1, 2);
console.log({ result });
const anotherResult = sum(1, 2);
console.log({ anotherResult });
};
</script>
Don't export functions in index.ts as you won't be able to do them in the browser.

Importing hash-set module not working for typescript/systemjs?

I'm working on an aurelia project, using typescript to create the javascript. Now I tried to add another custom library, 'hash-set' (using jspm install npm:hash-set --save). However I can't seem to actually use this package (using systemjs as loader).
My document structure is like:
\
dist\
src\
app.html
app.js
main.js
jsp_packages\
npm\
hash-set#1.0.1\
node_modules\
index.html
config.js
package.json
tsconfig.json
The important files (I think, please state in the comments if I miss something):
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test</title>
</head>
<body aurelia-app="src/main">
<script src="jspm_packages/system.js"></script>
<script src="config.js"></script>
<script>
SystemJS.import('aurelia-bootstrapper');
</script>
</body>
</html>
app.ts
This is compiled to app.js as prebuilt step. Using es2015 as target configuration.
import {hashSet} from 'hash-set';
export class App {
public myText: string;
hashFn(value) {
return value.toString();
}
constructor() {
alert("oh");
const h = hashSet;
const StringSet = hashSet(this.hashFn);
alert('oh2');
}
}
config.js
System.config({
defaultJSExtensions: true,
transpiler: false,
paths: {
"*": "dist/*",
"github:*": "jspm_packages/github/*",
"npm:*": "jspm_packages/npm/*"
},
meta: {
"bootstrap": {
"deps": [
"jquery"
]
}
},
map: { /*lots of aurelia and other library stuff*/
"hash-set": "npm:hash-set#1.0.1"
}
}
});
And it's also listed in package.json # {"jspm":{"dependencies":"hash-set": "npm:hash-set#^1.0.1"}}}
Now when I try to run above code (typescript compiles to app.js as prebuilt step), the app.js/app.ts loads, as expected. (frankly removing the hash-set specific code makes everything work as expected).
However during construction "oh" is shown, but "oh2" is never. Debugging over the code shows that "hashSet" is "undefined". Which leads me to believe that that systemjs isn't including the hash-set correctly?
Am I missing something?
EDIT: digging into the generated js (app.js) file I notice something weird:
define(["require", "exports", "hash-set"], function (require, exports, hash_set_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class App {
hashFn(value) {
return value.toString();
}
constructor() {
alert('oh');
const h = hash_set_1.hashSet;
const StringSet = hash_set_1.hashSet(this.hashFn);
alert('oh2');
}
}
exports.App = App;
});
//# sourceMappingURL=app.js.map
While debugging, hash_set_1 is actually of the type I expect hash_set_1.hashSet to be. Actually manually editing the javascript to not use hash_set_1.hashSet but rather just hash_set_1 works.
Trying
import hashSet from 'hash-set'; (notice lack of {}) changes the generated javascript offending line to const StringSet = hash_set_1.default(this.hashFn); which is still not correct (default isn't defined either).
If you look at the code, you'll see it is exported as:
module.exports = function hashSet(hashFn) {
Doing import { hashSet } from 'hash-set'; cannot work because the export would have to be module.exports.hashSet = ....
It should work if you do:
import hashSet = require("hash-set");

Systemjs-Builder - Cannot configure properly - Bundling Typescript into a package

I want to build a quick nodejs script to package a Typescript app as SystemJS modules, a lot like what Angular2 bundles look like.
I tried different configurations but I can't seem to put my finger on it, and haven't found clear enough documentation as of yet.
Note that for this "test", I am not using Gulp or Jspm at all, just systemjs-builder for the time being (and don't plan on using jspm at all either)
Here's what my "project" looks like:
---- Project's Root
-------- index.ts // export * from './modules/index' and eventually more
-------- modules
------------ index.ts // export * from './menu/index'
------------ menu
---------------- menu.component.ts // export class
---------------- menu.service.ts // export class
I want to package this under a single file, where I will have multiple SystemRegister modules that can be consumed in an app thereafter
I tried the following without success:
var Builder = require('systemjs-builder');
// optional constructor options
// sets the baseURL and loads the configuration file
var builder = new Builder('./modules');
builder.bundle('./modules/index.ts', {
/* SystemJS Configuration Here */
baseURL: './modules',
transpiler: 'typescript',
typescriptOptions: {
"module": "system",
"emitDecoratorMetadata": true,
"experimentalDecorators": true
},
defaultExtension: 'ts',
packages: {
'modules': {
defaultExtension: 'ts'
}
}
}, 'infrastructure.js')
.then(function() {
console.log('Build complete');
})
.catch(function(err) {
console.error(err);
})
First of all, the defaultExtension options doesn't seem to work at all
So when I do import {something} from 'filePath'; (without extension), it tries to load filePath, instead of filePath.ts;
Second, if I try adding the .ts extension in my imports (which I don't want to do), it complains that the code is invalid (unexpected token #, unexpected token menuItem and so forth)
Anyone have a good example or some explanations on how this is supposed to work?
Thank you
here you have an example: angular typescript skeleton
build task looks like this:
const path = require('path');
const Builder = require('jspm').Builder;
const builder = new Builder();
const packageJson = require(path.join(config.projectDir, 'package.json'));
return beginBuild()
.then(buildSFX)
.catch((err) => console.log('Build Failed', err));
function beginBuild() {
builder.reset();
return builder.loadConfig(path.join(config.projectDir, packageJson.jspm.configFile))
}
function buildSFX() {
const appName = packageJson.name;
const distFileName = `${appName}.min.js`;
const outFile = path.join(config.distDir, distFileName);
const moduleName = 'app';
const buildConfig = {
format: 'global',
minify: true,
sourceMaps: true
};
return builder.buildStatic(moduleName, outFile, buildConfig);
}
and jspm conf looks like this:
System.config({
defaultJSExtensions: true,
transpiler: "typescript",
typescriptOptions: {
"tsconfig": "src/tsconfig.json"
},
paths: {
"github:*": "vendor/jspm_packages/github/*",
"npm:*": "vendor/jspm_packages/npm/*",
"app": "src/index"
}
/// ...
}
Why do you want to bundle typescript? Bundling is a method used for optimizing the delivery of source code to the browser. The browser doesn't know typescript, it only knows javascript (unless you do on the fly transpiling).

RequireJs bundling with modules

I recently saw an example of how requirejs bundles work(http://vimeo.com/97519516) and got excited. So I'm trying to get the bundling feature to work with my setup and am banging my head on the wall.
Troubleshooting done so far.
The main.js file will be created properly without bundling and defining the comp1 component in the main.js top depenendecy. But when I nest the comp1 dependency and add the bundling options the page1 and page2 bundle never gets created. So it doesn't seem to be an issue with the rest of the configuration. I have also tried this a few different ways. Removing the module and and putting everything in the root of the config. Moving the bundles to the all-config.js. Any ideas on what I could be doing wrong.
all-config.js
(function() {
if (typeof requirejs != 'function') {
requirejs = function(config) { requirejs = config; };
}
requirejs({
pathes: {
comp1: "path1",
comp2: "path2,
router: "path3"
}
});
build.json
{
"baseUrl": "./",
"appDir": "../src/main/webapp",
"dir": "build",
"mainConfigFile": "app/all-config.js",
modules: [
{
"include": [
"app/lib/require/require.js"
],
bundles":{
"page1" : ["comp1"],
"page2" : ["comp2"]
}
}
]
}
main.js
require(['jquery', 'router'],function($){
//load app
require(["comp1"],function(comp1){
var app = new comp1();
});
});
Gruntfile
module.exports = function(grunt){
var stripper = require('strip-json-comments');
var buildOptionsFile = grunt.file.read( 'build.json' );
var buildOptions = JSON.parse(stripper(buildOptionsFile) );
grunt.initConfig({
requirejs: {
compile: {
options: buildOptions
}
}
});
.....
};
Any ideas on how to get this to work?

Keep original typescript source maps after using browserify

Background: I am compiling 2 dependent TypeScript files to js, which produces also source maps (one source map per file) using tsc 1.0
I'm using -m commonjs and then use browserify to generate a single bundle.js
However I noticed that I get the original source map references twice in the bundle, which doesn't seem to work.
Passing --debug doesn't seem to do the trick either.
I had a feeling this issue: https://github.com/substack/node-browserify/issues/325 is somewhat related, but I couldn't figure out how the issue was resolved.
Also https://github.com/substack/browser-pack was suggested, but again I don't fully understand how to use it, is it a replacement to browserify?
Bottom line, I would like to merge the 2 js files but "merge" the js to ts source maps using browserify. Is that possible?
tsify is a browserify plugin that is better and replaces e.g. typescriptifier.
npm install tsify browserify watchify
You use tsify like this:
browserify src/index.ts -p tsify --debug -o build/index.js
Notice that this supports browserify --debug switch, no extra tricks required. So you can also use it with watchify like this:
watchify src/index.ts -p tsify --debug -o build/index.js
Using the minifyify browserify plugin I believe you can use TypeScript with Browserify and retain the source maps. After compiling the TypeScript files you should be able to pass the "entry" file (the one that imports the other one via commonjs syntax) through browserify with the minifyify plugin.
var browserify = require('browserify'),
bundler = new browserify();
bundler.add('entry.js');
bundler.plugin('minifyify', {map: 'bundle.js.map'});
bundler.bundle({debug: true}, function (err, src, map) {
if (err) console.log(err);
fs.writeFileSync('bundle.js', src);
fs.writeFileSync('bundle.js.map', map);
});
Here is my working solution:
var settings = {
projectName : "test"
};
gulp.task("bundle", function() {
var mainTsFilePath = "src/main.ts";
var outputFolder = "bundle/src/";
var outputFileName = settings.projectName + ".min.js";
var pkg = require("./package.json");
var banner = [
"/**",
" * <%= pkg.name %> v.<%= pkg.version %> - <%= pkg.description %>",
" * Copyright (c) 2015 <%= pkg.author %>",
" * <%= pkg.license %>",
" */", ""
].join("\n");
var bundler = browserify({
debug: true,
standalone : settings.projectName
});
// TS compiler options are in tsconfig.json file
return bundler.add(mainTsFilePath)
.plugin(tsify)
.bundle()
.pipe(source(outputFileName))
.pipe(buffer())
.pipe(sourcemaps.init({ loadMaps: true }))
.pipe(uglify())
.pipe(header(banner, { pkg : pkg } ))
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest(outputFolder));
});
I created example project.
You can run it with $(npm bin)/gulp build --env=dev for development environment and source maps will be generated.
There is gulpfile.js:
'use strict';
var path = require('path'),
gulp = require('gulp'),
del = require('del'),
typescript = require('gulp-typescript'),
sourcemaps = require('gulp-sourcemaps'),
browserify = require('browserify'),
source = require('vinyl-source-stream'),
buffer = require('vinyl-buffer'),
uglify = require('gulp-uglify'),
gutil = require('gulp-util'),
inject = require('gulp-inject'),
babel = require('gulp-babel'),
argv = require('yargs').argv;
var devEnvironment = 'dev',
prodEnvironment = 'prod',
environment = argv.env || prodEnvironment,
isDevelopment = environment === devEnvironment;
var projectPath = __dirname,
srcDir = 'src',
srcPath = path.join(projectPath, srcDir),
buildDir = path.join('build', environment),
buildPath = path.join(projectPath, buildDir),
distDir = 'dist',
distRelativePath = path.join(buildDir, distDir),
distPath = path.join(buildPath, distDir);
var tsSrcPath = path.join(srcPath, 'typescript'),
tsGlob = path.join(tsSrcPath, '**', '*.ts'),
tsBuildPath = path.join(buildPath, 'tsc');
var indexHtmlName = 'index.html',
indexJsName = 'index.js';
var distIndexJsPath = path.join(distPath, 'index.js'),
distIndexHtmlPath = path.join(distPath, indexHtmlName);
var tsProject = typescript.createProject('tsconfig.json');
console.log('Environment: ' + environment);
gulp.task('clean', function () {
return del([buildPath]);
});
gulp.task('tsc', ['clean'], function () {
var stream = gulp.src([tsGlob]);
if (isDevelopment) {
stream = stream
.pipe(sourcemaps.init());
}
stream = stream
.pipe(typescript(tsProject))
.pipe(babel({
presets: ['es2015']
}));
if (isDevelopment) {
stream = stream.pipe(sourcemaps.write({sourceRoot: tsSrcPath}));
}
return stream.pipe(gulp.dest(tsBuildPath));
});
gulp.task('bundle', ['tsc'], function () {
var b = browserify({
entries: path.join(tsBuildPath, indexJsName),
debug: isDevelopment
});
var stream = b.bundle()
.pipe(source(indexJsName))
.pipe(buffer());
if (!isDevelopment) {
stream = stream.pipe(uglify());
}
return stream
.on('error', gutil.log)
.pipe(gulp.dest(distPath));
});
gulp.task('build', ['bundle'], function() {
return gulp.src(path.join(srcPath, indexHtmlName))
.pipe(inject(gulp.src([distIndexJsPath], {read: false}), {ignorePath: distRelativePath, addRootSlash: true}))
.pipe(gulp.dest(distPath));
});
You should pay attention to lines:
stream = stream.pipe(sourcemaps.write('', {sourceRoot: tsSrcPath})); - write inline source maps with sourceRoot pointing to your typescript sources path. Inline maps are written directly to .js files generated by tsc to build/dev/tsc.
debug: isDevelopment - in development environment make browserify generate his own source maps for resulting bundle build/dev/dist/index.js file so it will have source maps referencing .js files from build/dev/tsc which in turn have source maps referencing .ts files from src/typescript.
With this setup you will be able to see and debug .ts files in browser:
I faced similar issue when trying to debug my Angular2 app running in Chrome in Visual Studio Code (Using Debugger for Chrome extension)
I use gulp as my task runner and my setup is as follows:
Typescript files -> tsc -> intermediate es5 js -> browserify (plus uglify in production build) -> compiled bundle
My directory structure is as follows:
|- src
|- my .ts files here
|- main.ts - my entry file
|- dist
|- intermediate files go here
|- web
|- app.js - final bundle
|- app.js.map - final bundle map
|- gulpfile.js
gulpfile.js:
var gulp = require('gulp'),
tsc = require('gulp-typescript'),
browserify = require('browserify'),
uglify = require('gulp-uglify'),
sourcemaps = require('gulp-sourcemaps'),
source = require('vinyl-source-stream'),
buffer = require('vinyl-buffer');
gulp.task('tsc', [], () => {
return gulp.src(['src/**/*.ts'])
.pipe(sourcemaps.init())
.pipe(tsc({
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": [ "es2015", "dom" ],
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
}))
.pipe(sourcemaps.write(null, {
"sourceRoot": function(file) {
let parts = file.relative.split('\\');
let root = Array(parts.length + 1).join('../') + 'src';
return root;
}
}))
.pipe(gulp.dest('dist/'));
});
gulp.task('bundle', ['tsc'], () => {
let b = browserify({
entries: 'dist/main.js',
debug: true,
});
return b.bundle()
.pipe(source('app.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sourcemaps.write('./', {
"sourceRoot": "../",
}))
.pipe(gulp.dest('web/'));
})
gulp.task('default', ['bundle']);
Explanation/reasoning:
For some reason browserify doesn't read and parse .js.map files linked in .js file (via special comment at the end) but it does when the source map is embedded in js file. So, by passing null instead of path to sourcemaps it will embed it at the end of generated .js file.
Next issue I noticed was that sourcemaps doesn't automatically follow directory structure (add '../' to sourceRoot when it goes to next directory level), so I made a quick function to complement this. Keep in mind that it only works on Windows - on Linux you'd have to change split character.
function(file) {
let parts = file.relative.split('\\'); // put '/' here on Linux
let root = Array(parts.length + 1).join('../') + 'src';
return root;
}
Certainly there is a way to detect correct path separator, I'm debugging only on Windows thus it's not important for my purposes.
I hope it helps someone, cause I've spent whole Sunday morning tracking down this problem.

Categories