Typescript + Gulp + Sourcemaps wrong source path - javascript

I have a nodejs app with the following folder structure:
project
|-- src/
| |-- controllers/
| | |`-- authorize-controller.ts
| |`-- index.ts
|--dist/
| |--controllers/
| | |`-- authorize-controller.js
| | |`-- authorize-controller.js.map
| |`-- index.js
| |`-- index.js.map
`-- gulpfile.js
`-- tsconfig.json
The sourcemaps are generated. The index.js.map points to "../src/index.ts" (correct). The corresponding content of the map file is {"version":3,"sources":["../src/index.ts"],"names":[],"mappings"
But the dist\controllers\authorize-controller.js.map points to the wrong directory. It has {"version":3,"sources":["../src/controllers/authentication.controller.ts"],"names":[],. There is one ../ missing.
My gulpfile.js is:
gulp.task('compile', () => {
var tsResult = tsProject.src()
.pipe(sourcemaps.init())
.pipe(tsProject());
return tsResult.js
.pipe(sourcemaps.write('.', { includeContent: false, sourceRoot: '/src' }))
.pipe(gulp.dest('dist'));
});
My tsconfig.json is:
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"noImplicitAny": false,
"sourceMap": true,
"outDir": "dist"
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules",
"dist",
".vscode"
]
}
What am I doing wrong?
It seems the sourceRoot is ignored by gulp-sourcemaps.

Ok I found a solution to get the breakpoints hit.
I looked on the wrong part of the sourcefile. "sources":["../src/controllers/authentication.controller.ts"] is always the same and can be ignored. If I change the gulp task to use sourceRoot: '../src' it works.
At the end of the sourcemap-file, the sourceRoot is set.
This is my new gulp task:
gulp.task('compile', () => {
var tsResult = tsProject.src()
.pipe(sourcemaps.init())
.pipe(tsProject());
return tsResult.js
.pipe(sourcemaps.write('.', { includeContent: false, sourceRoot: '../src' }))
.pipe(gulp.dest('dist'));
});

My source files are located at "src" folder at the project root folder and all output with corresponding folder structure goes into "dist" folder similar to yours. Here is my "compile" task that I think can help you :
var gulp = require("gulp");
var tsc = require("gulp-typescript");
var sourcemaps = require('gulp-sourcemaps');
gulp.task("compile", function () {
var tsProject = tsc.createProject('tsconfig.json');
return gulp
.src("src/**/*.ts")
.pipe(sourcemaps.init())
.pipe(tsProject())
.pipe(sourcemaps.write(
".",
{
sourceRoot: function(file) {
var filePathSplit = file.sourceMap.file.split("/");
var backTrack = '../'.repeat(filePathSplit.length-1) || '../' ;
var filePath = backTrack+ "src/";
return filePath;
}}
))
.pipe(gulp.dest("dist"));
});
Hope this will help.

Related

Can't find module 'filepath' in nodejs

This is my folder structure.
/node_modules/
....
....
/src/
....
index.ts
export default app.listen(PORT, () => {
console.log('Server is listening on port 3000')
});
....
tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"typeRoots": [
"#types",
"./node_modules/#types"
]
},
"include" : [
"src/**/*.ts"
],
"exclude" : [
"node_modules"
]
}
/test/
hello.ts
const chaai = require('chai')
const httpChai = require('chai-http')
const server = require('../src/index')
chaai.use(httpChai)
describe('registration API', ()=>{
describe('GET /api/register', ()=>{
it("It should throw error", (done)=>{
chaai.request(server)
.post('/api/register')
// #ts-ignore
.end((err, response)=>{
response.status.should.equal(400)
done()
})
})
})
})
package.json
"scripts": {
"test": "mocha 'test/**/*.ts'"
},
application structure
root
node_modules
src
modules
module1
module2
index.ts
tsconfig.json
package.json
Now when I run npm test, it says Error: Cannot find module '../src/index'
I tried moving test folder inside src folder also. But it didn't work.
In test file, inside /test/hello.ts If I use import, says can't use import statement outside module.
And right now inside test file /test/hello.ts, I have required chai as const chaai = require('chai') and stored it in a chaai variable. But if I store it in a chai variable as const chai = require('chai'), then typescript warns Cannot redeclare block-scoped variable 'chai'.ts(2451) index.d.ts(1968, 15): 'chai' was also declared here.
How can I resolve this ?

Multiple eslintrc in grunt pointing to different folder

I have folder structure like below and using eslint I am validating my syntax rules .
I have a grunt file which runs eslint by default to all folder below src . But now I have got new scenario where I need to run few more rules to one specific folder mddx. Along With default rules mddx should run with more rules .
I know we can have multiple .eslintrc.json file , but how to configure in gruntfile.js with two task , both doing eslint but rules are diffrent.
Also pointing folder is different.
parent
|
|
|------src
| +mund
| |
| |--<jsfiles>
| +mddx
| |
| |--<jsfiles>
.eslintrc.json
|
|
gruntfile.js
|
gruntfile.js
module.exports = function(grunt) {
require('load-grunt-tasks')(grunt);
grunt.initConfig({
eslint: {
options: {
config: '.eslintrc.json',
reset: false
},
target: {
src: [
'src/**/*.js'
]
}
}
});
grunt.registerTask('default', ['eslint']);
};
I got answer so posting it .
Created .eslintrc.json file specific to folder and divided eslint into two sub task . Both has different configuration and points to different rule and
folder.
module.exports = function(grunt) {
require('load-grunt-tasks')(grunt);
grunt.initConfig({
eslint: {
default: {
options: {
configFile: '.eslintrc.json',
reset: false
},
src: [
'src/**/*.js'
]
},
mddx: {
options: {
configFile: 'src/mddx/.eslintrc.json',
reset: false
},
src: [
'src/mddx/**/*.js'
]
}
}
});
grunt.registerTask('default', ['eslint']);
};

gulp-browserify output different than it should be

I am using gulp with browserify to concatenate, babelify, and browserify several js libraries. This is in my gulpfile.js:
gulp.task('scripts', function () {
var b = browserify({
entries: ['src/scripts/modernizr.js', 'src/scripts/main.js'],
debug: true
}).transform(babelify, { presets: ["latest"] });
return b.bundle()
.pipe(source('main.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
// Add transformation tasks to the pipeline here.
// .pipe(uglify())
.on('error', gutil.log)
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest('build/js/'));
});
And my package.json:
"browserify": {
"transform": [
[
"babelify",
{
"presets": [
"es2015"
]
}
]
]
}
In my main.js this is how I am including the libraries:
var $ = window.jquery;
import tinymce from 'tinymce/tinymce';
import 'tinymce/themes/modern/theme';
// import spica from 'spica';
// import localsocket from 'localsocket';
var spica = require('spica');
var localsocket = require('localsocket');
import Pjax from 'pjax-api';
However I’m getting the following error in the console:
pjax-api.js:8Uncaught Error: Cannot find module 'spica'
at s (http://localhost:8000/static/articles/build/js/main.js:1:148)
at http://localhost:8000/static/articles/build/js/main.js:1:305
at s (http://localhost:8000/static/articles/build/js/main.js:12699:28)
at http://localhost:8000/static/articles/build/js/main.js:12708:24
at Object.r.42.../../../lib/dom (http://localhost:8000/static/articles/build/js/main.js:14446:27)
at s (http://localhost:8000/static/articles/build/js/main.js:12706:21)
at http://localhost:8000/static/articles/build/js/main.js:12708:24
at Object.r.41../gui (http://localhost:8000/static/articles/build/js/main.js:14429:25)
at s (http://localhost:8000/static/articles/build/js/main.js:12706:21)
at http://localhost:8000/static/articles/build/js/main.js:12708:24
at Object.r.4../layer/interface/service/api (http://localhost:8000/static/articles/build/js/main.js:12738:25)
at s (http://localhost:8000/static/articles/build/js/main.js:12706:21)
at http://localhost:8000/static/articles/build/js/main.js:12708:24
at Object.r.pjax-api../src/export (http://localhost:8000/static/articles/build/js/main.js:15017:22)
at s (http://localhost:8000/static/articles/build/js/main.js:12706:21)
at e (http://localhost:8000/static/articles/build/js/main.js:12715:9)
at Object.3 (http://localhost:8000/static/articles/build/js/main.js:12717:2)
at s (http://localhost:8000/static/articles/build/js/main.js:1:254)
at http://localhost:8000/static/articles/build/js/main.js:1:305
at Object.8.jquery (http://localhost:8000/static/articles/build/js/main.js:67062:16)
at s (http://localhost:8000/static/articles/build/js/main.js:1:254)
at e (http://localhost:8000/static/articles/build/js/main.js:1:425)
at http://localhost:8000/static/articles/build/js/main.js:1:443
This is my directory structure:
articles
|--gulpfile.js
|--package_json
|--build
| |--img
| |--css
| |--js
| | |--main.js
|--src
| |--img
| |--styles
| |--scripts
| | |--main.js
|--node_modules
| |--spica
| |--localsocket
| |--pjax-api
| |--etc.
What is going wrong?
The full output of main.js is too big to paste, but here it is in a gist. And here is the rest of my code in another gist.
Do you have the spica-package installed? If not, try this:
npm install --save-dev spica
if your 'spica' is present in the same directory where main.js is present then its fine or else
You have to specify
like this ,
var spica = require(dir_path/spica.js)
share your directory structure so i can provide you exact syntax.

How do I generate a sourcemap with babel using this directory structure?

gulp.task('build:server:js', function(){
return gulp.src("server/**/*.js")
.pipe(sourcemaps.init())
.pipe(babel({
"presets": ["es2015", "react", "stage-0"]
}))
.pipe(sourcemaps.write('.', {
includeContent: false,
sourceRoot: function(file) {
var from = file.path;
var to = path.resolve(__dirname+'/../server');
var dest = path.relative(from, to) + '/../server';
console.log("from %s\nto: %s\ndest: %s\n", from, to, dest);
return dest;
}
}))
.pipe(gulp.dest("dist/server/"));
});
gulp tasks are in ./tasks folder, not ./ -- the build is generated in ./dist folder and should point back to ./path/to/src.js.
The dist folder has same structure as root project folder. (ie: ./server/core/routes.js for example ends up in ./dist/server/core/routes.js when transpiled along with the .maps file.

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