Gulp: Creating sourcemaps for both compressed and uncompressed scripts

Recently, I've started using gulp and encountered a common issue. My goal is to compile TypeScript into JavaScript, create sourcemaps, and then run uglify. The challenge lies in having both sourcemaps for the minified and non-minified JS files.

The desired file structure looks like this:

framework.js
framework.js.map < old method
framework.min.js
framework.min.js.map

Below is my current gulp task:

var gulp = require('gulp'),
uglify = require('gulp-uglify')
ts = require("gulp-typescript")
sourcemaps = require('gulp-sourcemaps')
rename = require('gulp-rename');

var tsProject = ts.createProject("tsconfig.json");


gulp.task('typescript', function(){
    tsProject.src()
    .pipe(sourcemaps.init())
    .pipe(tsProject()).js
    .pipe(sourcemaps.write('.')) // Create sourcemap for non-minified version
    .pipe(gulp.dest("dist"))
    .pipe(uglify()) // Issues arise here 
    .pipe(rename({suffix:'.min'}))
    .pipe(sourcemaps.write('.')) // Create sourcemap for minified version.
    .pipe(gulp.dest("dist"));
});

gulp.task('default', ['typescript']);

I'm encountering an error due to running sourcemaps.write() twice to generate two different files.

tream.js:74                                                                        
  throw er; // Unhandled stream error in pipe.                                  
  ^ GulpUglifyError: unable to minify JavaScript                                       
at createError     (C:\Users\alexa\Dropbox\code\Web\mhadmin\framework\node_modules\gulp-uglify\lib\create-error.js:6:14)

If the first sourcemap.write() call is omitted, the minified version has a correct sourcemap. Any suggestions on how to resolve this?

UPDATE: This isn't a duplicate of gulp: uglify and sourcemaps as I need multiple calls to gulp.dest() for writing multiple sourcemaps.

Answer №1

The issue arises when you execute .pipe(sourcemaps.write('.')) for the first time because it adds two files to your stream:

framework.js
framework.js.map 

You proceed to write both of these files to the file system, which is acceptable. However, attempting to apply uglify() on both files causes the plugin to fail since framework.js.map does not contain valid JavaScript code.

Once you have saved framework.js.map to the file system, there is no longer a necessity to retain that file in the stream. The vinyl file object for framework.js still retains all the necessary transformations within its .sourceMap property, allowing you to eliminate framework.js.map from the stream.

To achieve this, the usage of the gulp-filter plugin becomes essential:

var filter = require('gulp-filter');

gulp.task('typescript', function(){
  return tsProject.src()
   .pipe(sourcemaps.init())
   .pipe(tsProject()).js
   .pipe(sourcemaps.write('.'))
   .pipe(gulp.dest("dist"))
   .pipe(filter('**/*.js')) // only allow JavaScript files through
   .pipe(uglify())
   .pipe(rename({suffix:'.min'}))
   .pipe(sourcemaps.write('.'))
   .pipe(gulp.dest("dist"));
});

Following the addition of .pipe(filter('**/*.js')), solely the framework.js file remains within the stream, eliminating any issues with uglify().

Answer №2

It may seem like a bit of a hack, but this method gets the job done

gulp.src('TypeScript/Test.ts')
    .pipe(plumber())
    .pipe(sourcemaps.init())
    .pipe(ts(tsOptions)).js
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('./wwwroot/test'))
    .pipe(uglify())
    .pipe(rename({ extname: '.min.js' }))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('./wwwroot/test'));

The secret lies in the plumber. Plumber prevents the process from stopping on exceptions. The main issue is why the exception occurs. In your code, you create a sourcemap using

.pipe(sourcemaps.write('.')) // Write sourcemap for non-minified version
and then attempt to uglify it. However, since the sourcemap is not JS, an exception occurs. With plumber, this exception is ignored, allowing you to achieve your goal.

However, there could be something incorrect, so I suggest seeking a more optimal solution.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having difficulty transforming shapefiles into geojson

I am in need of JavaScript code that can seamlessly convert shapefile files to geojson and vice versa, but I am struggling to find reliable tools to accomplish this task. After some research, I stumbled upon Calvin Metcalf's repository, which claims ...

Encountering a "subscribe is not a function" error while attempting to utilize a JSON file in Angular 2

My attempt to import a JSON file into my service is resulting in the following error: Error: Uncaught (in promise): TypeError: this._qs.getBasicInfo(...).subscribe is not a function(…) The current state of my service file is as follows @Injectable() ...

Create a customized selection based on input changes

<select id="gameid"> //<option is a number 1-999> </select> <select id="netid"> //<option is a number 1-999> </select> <select id="camp_id"> <script> var a = $("#gameid").val(); var b = $("#ne ...

Troubleshooting: Dealing with ng-click and invalid functions

Prior to resolving the issue, I encountered a component (within an HTML template) containing a ng-click that was invoking a nonexistent function. Is there a method to enable a strict mode (similar to 'use strict' in JS) or something equivalent t ...

Having difficulty with express.index when trying to send a JSON object

Express is my tool of choice for creating a simple web page. The code in my index.js file looks like this: exports.index = function(req, res){ res.render( 'index', { title: 'Expressssss', Tin: va ...

Update the user information by using its unique identifier at a specific location

I am currently working on editing user data with a specific MongoDB instance. When I click on the user's details, a modal popup appears with an update button below it. My goal is to have the user data updated when this button is clicked for the partic ...

How to locate and remove an object in Angular 6

What is the method to remove an object from a list of objects using an id number in Angular 6 with TypeScript? EntityService.ts import { Injectable } from '@angular/core'; import { Entity } from '../../models/entity'; @Injectable({ ...

Utilizing bindCallback effectively in RXJS6 and DWR: A comprehensive guide

Currently, I am utilizing bindCallback in a way that is now considered deprecated as seen below: const someMapping = (data) => { return { ... }}; public someCall(id) { // Foo.someFunction is function with callbacks return this.toObservable(Foo.som ...

Issue with getStaticProps not updating fetched values in Next.js production environment

I am currently working on building a blog using Next.js. Since the back-end is taken care of by another team, I am utilizing fetch API calls in getStaticProps to retrieve my articles, even though it may be considered best practice to interact with the data ...

The plugin's element is not compatible with jQuery methods

This particular plugin is designed to enhance the appearance of checkbox inputs. It creates a more visually appealing version of standard checkboxes. However, I have encountered an issue with one of the variables in the code. Let's discuss the theLab ...

Executing Javascript code in Web2Py works on a local environment, but faces issues when the

Trying to incorporate a simple JavaScript code in a web2py VIEW to fetch an external URL has presented some challenges: <script src="http://widgets.aapc.com/countdown/aapc_cdwidgetbox_220.js"></script> The script runs smoothly locally but fai ...

The React useState Props error message TS2322: Cannot assign type 'string' to type 'number'

I'm attempting to pass Props to React useState Hooks. Both of my props are required and should be numbers, but I keep receiving a Typescript error stating: Type 'string' is not assignable to type 'number'. TS2322 However, I am ...

npm postinstall script - running a script provided by a dependency

Regrettably, my search has not yielded any recent information on this issue. Consider the scenario where I have 2 packages: @my/package and @my/parent. Now, within @my/parent, I attempt to use a postinstall script like so: postinstall: "node ./node_modul ...

I am facing restrictions in TypeScript when trying to modify RX JS responses

Can someone help me with a quick solution to this Angular 4 issue? title:string; content: string; comment: string; constructor( private http: HttpClient) {} posts: {title: string, content: string, comments: String[]}[] = []; ngOnInit() { this. ...

What is the best way to transform the request query id = ' [12eetftt76237,jhgasduyas7657] ' into an array of elements or strings like [12eetftt76237,jhgasduyas7657]?

Hey there, I am working on a project using hapijs and typescript. I have a requirement to send an array of IDs as parameters through the request URL. Here is an example of the URL: localhost:3444/?id='[askjajk78686,ajshd67868]' I attempted to u ...

Setting a loader for when a component renders for the first time in Nuxt 3

In my nuxt 3 project, I am utilizing the element plus library to create a page with 3 tabs. Each tab's content is divided into its own component, and I have set conditions to initially render only the first tab component. However, when switching to th ...

The String retrieved from the API response does not support displaying line breaks, whereas a hard-coded string can successfully display line breaks

Greetings, My frontend is built on Angular 8, with a Java API service serving as the backend. I need to fetch a String from the backend, which will contain '\n' line breaks. For example: "Instructions:\n1. Key in 122<16 digit ...

What is the best way to save JavaScript array information in a database?

Currently working on developing an ecommerce website. My goal is to have two select tags, where the options in the second tag are dynamically populated based on the selection made in the first tag. For example, if "Electronics" is chosen in the first tag f ...

Use jQuery to activate the radio button inside a div whenever it is triggered by a change

How can I check which radio button list is clicked and then send a jQuery ajax call for the clicked item? Currently, I have tables with the IDs plan1, plan2, plan3 generated using PHP. Each table has a radio button list. Using jQuery each, how can I achiev ...

Creating a sorting function in VueJS requires a few key steps

I'm working on implementing a sorting function in my VueJS code that includes the following options: Price: Low to High, Price: High to Low. Here is my template: <div name="divSortBy"> <span> Sort by: & ...