Skip to content

Commit c0856db

Browse files
committed
Added Unminify command and JS options no-mangle, keep-fnames, keep-fargs; updated npm tools
1 parent d20d666 commit c0856db

File tree

4 files changed

+102
-6
lines changed

4 files changed

+102
-6
lines changed

MiniWebCompiler/ViewModels/Project.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ private void OnKeepUnminifiedFilesChanged()
128128

129129
public ProjectFile SelectedFile { get; set; }
130130

131+
public bool IsJavaScriptSelected => SelectedFile?.FilePath.EndsWith(".js") ?? false;
132+
131133
public bool? Status { get; private set; } = true;
132134

133135
#endregion Properties
@@ -228,6 +230,13 @@ private void OnHasBaselineChanged()
228230
}
229231
}
230232

233+
public DelegateCommand UnminifyCommand { get; }
234+
235+
private async void OnUnminify()
236+
{
237+
await SelectedFile?.Unminify();
238+
}
239+
231240
#endregion Commands
232241

233242
#region Status handling

MiniWebCompiler/ViewModels/ProjectFile.cs

Lines changed: 90 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public class ProjectFile : ViewModelBase
2323
private bool newError;
2424
private string fullFileName;
2525
private string fileDir;
26+
private string fullOutputFileName;
2627
private bool isAnyFileModified;
2728
private bool isCompiling;
2829
private bool needsRecompile;
@@ -253,6 +254,39 @@ await ExecAsync(
253254
}
254255
}
255256

257+
public async Task Unminify()
258+
{
259+
if (isCompiling || Status != true)
260+
{
261+
return;
262+
}
263+
264+
if (File.Exists(fullFileName))
265+
{
266+
try
267+
{
268+
switch (Path.GetExtension(fullFileName))
269+
{
270+
case ".js":
271+
await UnminifyJavaScript();
272+
break;
273+
default:
274+
return;
275+
}
276+
}
277+
catch (Exception ex)
278+
{
279+
LastLog += (!string.IsNullOrEmpty(LastLog) ? "\n\n" : "") +
280+
"Exception while unminifying\n\n" + ex.ToString();
281+
}
282+
}
283+
else
284+
{
285+
LastLog += (!string.IsNullOrEmpty(LastLog) ? "\n\n" : "") +
286+
"Compiled file not found: " + fullFileName;
287+
}
288+
}
289+
256290
#endregion Public methods
257291

258292
#region Compiling
@@ -266,7 +300,7 @@ private async Task CompileCss(bool force)
266300
using (var reader = new StreamReader(fullFileName))
267301
{
268302
int lineNumber = 0;
269-
while (!reader.EndOfStream && lineNumber < 10)
303+
while (!reader.EndOfStream && lineNumber < 20)
270304
{
271305
string line = reader.ReadLine();
272306
lineNumber++;
@@ -285,6 +319,7 @@ private async Task CompileCss(bool force)
285319
}
286320
}
287321
}
322+
fullOutputFileName = minCssFileName;
288323

289324
if (!force && AreFilesUpToDate(minCssFileName, minCssFileName + ".map"))
290325
{
@@ -337,11 +372,14 @@ private async Task CompileJavaScript(bool force)
337372
string iifeParams = "";
338373
string iifeArgs = "";
339374
bool noIife = false;
375+
bool mangle = true;
376+
bool keepFargs = false;
377+
bool keepFnames = false;
340378
string buildDir = "";
341379
using (var reader = new StreamReader(fullFileName))
342380
{
343381
int lineNumber = 0;
344-
while (!reader.EndOfStream && lineNumber < 10)
382+
while (!reader.EndOfStream && lineNumber < 20)
345383
{
346384
string line = reader.ReadLine();
347385
lineNumber++;
@@ -366,6 +404,21 @@ private async Task CompileJavaScript(bool force)
366404
{
367405
noIife = true;
368406
}
407+
match = Regex.Match(line, @"^\s*/\*\s*no-mangle\s*\*/", RegexOptions.IgnoreCase);
408+
if (match.Success)
409+
{
410+
mangle = false;
411+
}
412+
match = Regex.Match(line, @"^\s*/\*\s*keep-fargs\s*\*/", RegexOptions.IgnoreCase);
413+
if (match.Success)
414+
{
415+
keepFargs = true;
416+
}
417+
match = Regex.Match(line, @"^\s*/\*\s*keep-fnames\s*\*/", RegexOptions.IgnoreCase);
418+
if (match.Success)
419+
{
420+
keepFnames = true;
421+
}
369422
match = Regex.Match(line, @"^\s*/\*\s*build-dir\((.*)\)\s*\*/", RegexOptions.IgnoreCase);
370423
if (match.Success && buildDir == "")
371424
{
@@ -384,6 +437,7 @@ private async Task CompileJavaScript(bool force)
384437
}
385438
}
386439
}
440+
fullOutputFileName = minFileName;
387441

388442
if (!force && AreFilesUpToDate(minFileName, minFileName + ".map"))
389443
{
@@ -440,15 +494,21 @@ await ExecAsync(
440494

441495
if (Status != false)
442496
{
443-
string mapParam = "--source-map \"url='" + onlyMinFileName.Replace('\\', '/') + ".map'\"";
497+
string mangleParam = mangle ? " --mangle" : "";
498+
string mapParam = " --source-map \"url='" + onlyMinFileName.Replace('\\', '/') + ".map'\"";
444499
if (File.Exists(Path.Combine(fileDir, bundleFileName) + ".map"))
445500
{
446501
// The url part must refer to the file without the build directory because
447502
// both files (min.js and map) will be in the same directory.
448-
mapParam = "--source-map \"content='" + bundleFileName.Replace('\\', '/') + ".map',url='" + onlyMinFileName.Replace('\\', '/') + ".map'\"";
503+
mapParam = " --source-map \"content='" + bundleFileName.Replace('\\', '/') + ".map',url='" + onlyMinFileName.Replace('\\', '/') + ".map'\"";
449504
}
505+
string addParams = "";
506+
if (keepFargs)
507+
addParams += " --keep-fargs";
508+
if (keepFnames)
509+
addParams += " --keep-fnames";
450510
await ExecAsync(
451-
"uglifyjs " + bundleFileName + " --compress --mangle --output \"" + minFileName + "\" --comments \"/^!/\" " + mapParam,
511+
"uglifyjs " + bundleFileName + " --compress" + mangleParam + " --output \"" + minFileName + "\" --comments \"/^!/\"" + mapParam + addParams,
452512
fileDir,
453513
utf8: true);
454514

@@ -499,7 +559,7 @@ private async Task CompileScss(bool force)
499559
using (var reader = new StreamReader(fullFileName))
500560
{
501561
int lineNumber = 0;
502-
while (!reader.EndOfStream && lineNumber < 10)
562+
while (!reader.EndOfStream && lineNumber < 20)
503563
{
504564
string line = reader.ReadLine();
505565
lineNumber++;
@@ -519,6 +579,7 @@ private async Task CompileScss(bool force)
519579
}
520580
}
521581
}
582+
fullOutputFileName = minCssFileName;
522583

523584
if (!force && AreFilesUpToDate(minCssFileName, minCssFileName + ".map"))
524585
{
@@ -619,6 +680,29 @@ fileValue is string fileStr &&
619680

620681
#endregion Compiling
621682

683+
#region Unminifying
684+
685+
private async Task UnminifyJavaScript()
686+
{
687+
string unminifiedFileName = Regex.Replace(fullOutputFileName, @"\.min\.js$", ".unmin.js");
688+
689+
//string mapParam = " --source-map \"url='" + unminifiedFileName.Replace('\\', '/') + ".map'\"";
690+
string mapParam = "";
691+
if (File.Exists(Path.Combine(fileDir, fullOutputFileName) + ".map"))
692+
{
693+
//mapParam = " --source-map \"content='" + fullOutputFileName.Replace('\\', '/') + ".map',url='" + unminifiedFileName.Replace('\\', '/') + ".map'\"";
694+
mapParam = " --source-map \"content='" + fullOutputFileName.Replace('\\', '/') + ".map'\"";
695+
}
696+
await ExecAsync(
697+
"uglifyjs " + fullOutputFileName + " --beautify --output \"" + unminifiedFileName + "\"" + mapParam,
698+
fileDir,
699+
utf8: true);
700+
701+
PostprocessMapFile(unminifiedFileName + ".map");
702+
}
703+
704+
#endregion Unminifying
705+
622706
#region Process helper methods
623707

624708
private bool AreFilesUpToDate(params string[] outputs)

MiniWebCompiler/Views/MainWindow.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@
154154
</Button>
155155
<Button Margin="6,0,0,0" MinWidth="75" IsEnabled="{Binding IsProjectSelected}" Command="{Binding SelectedProject.CompileAllCommand}">Compile all</Button>
156156
<ToggleButton Margin="6,0,0,0" IsEnabled="{Binding IsProjectSelected}" IsChecked="{Binding SelectedProject.HasBaseline}">Baseline</ToggleButton>
157+
<Button Margin="6,0,0,0" IsEnabled="{Binding SelectedProject.IsJavaScriptSelected}" Command="{Binding SelectedProject.UnminifyCommand}">Unminify</Button>
157158
</StackPanel>
158159
</Grid>
159160

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ JavaScript configuration
2929
------------------------
3030
JavaScript files are run through `rollup` to bundle them into a single file, if any imports of other files are detected in the source file. The bundled code is wrapped into an immediately invoked function expression (IIFE). The parameters of that function and the arguments when calling it can be specified with comment lines like `/* iife-params($) */` and `/* iife-args(jQuery) */` near the top of the file. The code between the parentheses is inserted into the generated file. The comment `/* no-iife */` disables the use of an IIFE and basically concatenates all the files together.
3131

32+
JavaScript mangling by `uglify-js` can be configured with the following comments: `/* no-mangle */` disables mangling completely (nothing is renamed), `/* keep-fnames */` disables renaming functions, `/* keep-fargs */` disables renaming function arguments (parameter names). These options can be used together with the “Unminify” command to debug compressing or mangling errors in your JavaScript code. It will take the .min.js file and beautify it into a .unmin.js file in the same (output) directory.
33+
3234
The build output files can be written to a separate directory to keep your source code folder tidy. Use a comment like `/* build-dir(...) */` and anything in the parentheses is the relative path to your build output files. The build directory is created if it doesn’t exist. This configuration also works for CSS files, but note that you cannot use relative `url()` references without manually copying the build file to the correct directory.
3335

3436
### Example

0 commit comments

Comments
 (0)