Hi Guys,
I am coming to the end of the dev stage of an application and want to deploy to QA/UAT. As part of this process I want to run "npm run build". I followed the process outlined here https://docs.aspnetzero.com/en/aspnet-core-mvc/latest/Setting-Up-an-Azure-Pipeline-Mvc-Core for yarn and "npm run build" in DevOps. As you can see below, "npm run build" executes correctly with no errors, but the created bundles are identical to the dev versions and are not minified. I notice that this was a bug in the past #6987. Is it possible this bug has reappeared?
I'm using version 8.9.2 of the framework.
Thanks, Barry.
2020-08-04T13:43:54.4659893Z [[90m14:43:54[39m] Using gulpfile H:\Agents\1\_work\67\s\src\MyProject.Web.Mvc\gulpfile.js
2020-08-04T13:43:54.4721122Z [[90m14:43:54[39m] Starting 'build'...
2020-08-04T13:47:48.3216910Z [[90m14:47:48[39m] Finished 'build' after 3.88 min
2020-08-04T13:47:48.4513226Z ##[section]Finishing: NPM Run Build task
11 Answer(s)
-
0
hi
Can you share your
gulpfile.js
file? -
0
No problem, thanks for getting back to me. Note the small function at the end which makes the files editable. This gets around the TFS locking issue for bundle generation.
var gulp = require("gulp"); var path = require('path'); var merge = require("merge-stream"); var globby = require('globby'); var concat = require('gulp-concat'); var less = require('gulp-less'); var uglify = require('gulp-uglify-es').default; var cleanCss = require('gulp-clean-css'); var postcss = require("gulp-postcss"); var url = require("postcss-url"); var bundleConfig = require(path.resolve(__dirname, 'bundles.json')); var production = false; const { watch } = require('gulp'); var styleEntries = {}; var scriptEntries = {}; var viewScripts = globby.sync([ './wwwroot/view-resources/**/*.js', '!./wwwroot/view-resources/**/*.min.js' ]); var viewStyles = globby.sync([ './wwwroot/view-resources/**/*.css', './wwwroot/view-resources/**/*.less', '!./wwwroot/view-resources/**/*.min.css' ]); var metronicScripts = globby.sync([ './wwwroot/metronic/**/*.js', '!./wwwroot/metronic/**/*.min.js', '!./wwwroot/metronic/core/**/*.js' ]); var metronicStyles = globby.sync([ './wwwroot/metronic/**/*.css', './wwwroot/metronic/**/*.less', '!./wwwroot/metronic/**/*.min.css' ]); function processInputDefinition(input) { var result = []; for (var i = 0; i < input.length; i++) { var url = input[i]; if (url.startsWith('!')) { result.push('!' + path.resolve(__dirname, url.substring(1))); } else { result.push(path.resolve(__dirname, url)); } } return result; } function fillScriptBundles() { // User defined bundles for (var k = 0; k < bundleConfig.scripts.length; k++) { var scriptBundle = bundleConfig.scripts[k]; scriptEntries[scriptBundle.output] = globby.sync(processInputDefinition(scriptBundle.input), { noext: true }); } // View scripts for (var i = 0; i < viewScripts.length; i++) { var viewScriptName = viewScripts[i].replace('./wwwroot/', ''); scriptEntries[viewScriptName.replace('.js', '.min.js')] = [path.resolve(__dirname, viewScripts[i])]; } // Metronic scripts for (var j = 0; j < metronicScripts.length; j++) { var metronicScriptName = metronicScripts[j].replace('./wwwroot/', ''); scriptEntries[metronicScriptName.replace('.js', '.min.js')] = [path.resolve(__dirname, metronicScripts[j])]; } } function fillStyleBundles() { // User defined styles for (var k = 0; k < bundleConfig.styles.length; k++) { var styleBundle = bundleConfig.styles[k]; styleEntries[styleBundle.output] = globby.sync(processInputDefinition(styleBundle.input), { noext: true }); } // View styles for (var j = 0; j < viewStyles.length; j++) { var viewStyleName = viewStyles[j].replace('./wwwroot/', ''); if (viewStyleName.indexOf('.css') >= 0) { styleEntries[viewStyleName.replace('.css', '.min.css')] = [path.resolve(__dirname, 'wwwroot/' + viewStyleName)]; } if (viewStyleName.indexOf('.less') >= 0) { styleEntries[viewStyleName.replace('.less', '.min.css')] = [path.resolve(__dirname, 'wwwroot/' + viewStyleName)]; } } // Metronic styles for (var i = 0; i < metronicStyles.length; i++) { var metronicStyleName = metronicStyles[i].replace('./wwwroot/', ''); if (metronicStyleName.indexOf('.css') >= 0) { styleEntries[metronicStyleName.replace('.css', '.min.css')] = [path.resolve(__dirname, 'wwwroot/' + metronicStyleName)]; } if (metronicStyleName.indexOf('.less') >= 0) { styleEntries[metronicStyleName.replace('.less', '.min.css')] = [path.resolve(__dirname, 'wwwroot/' + metronicStyleName)]; } } } function getFileNameFromPath(fullPath) { return path.basename(fullPath); } function getPathWithoutFileNameFromPath(fullPath) { return path.dirname(fullPath); } function fillScriptMappings() { for (var k = 0; k < bundleConfig.scriptMappings.length; k++) { var scriptBundle = bundleConfig.scriptMappings[k]; var inputFilesToBeCopied = globby.sync(processInputDefinition(scriptBundle.input), { noext: true }); for (var j = 0; j < inputFilesToBeCopied.length; j++) { var outputFileName = path.join(scriptBundle.outputFolder, getFileNameFromPath(inputFilesToBeCopied[j])); scriptEntries[outputFileName] = [inputFilesToBeCopied[j]]; } } } function createScriptBundles() { var tasks = []; for (var script in scriptEntries) { tasks.push( createScriptBundle(script) ); } return tasks; } function createScriptBundle(script) { var bundleName = getFileNameFromPath(script); var bundlePath = getPathWithoutFileNameFromPath(script); var stream = gulp.src(scriptEntries[script]); if (production) { stream = stream .pipe(uglify()); } return stream.pipe(concat(bundleName)) .pipe(gulp.dest('wwwroot/' + bundlePath)); } function createStyleBundles() { var tasks = []; for (var style in styleEntries) { tasks.push( createStyleBundle(style) ); } return tasks; } function createStyleBundle(style) { var bundleName = getFileNameFromPath(style); var bundlePath = getPathWithoutFileNameFromPath(style); var options = { url: function (asset) { // Ignore absolute URLs if (asset.url.substring(0, 1) === '/') { return asset.url; } var outputFolder = ''; if (asset.url.match(/\.(png|svg|jpg|gif)$/)) { outputFolder = 'dist/img'; } else if (asset.url.match(/\.(woff|woff2|eot|ttf|otf)[?]{0,1}.*$/)) { outputFolder = 'dist/fonts'; } else { // Ignore not recognized assets like data:image etc... return asset.url; } var fileName = path.basename(asset.absolutePath); var outputPath = path.join(__dirname, '/wwwroot/' + outputFolder + '/'); gulp.src(asset.absolutePath).pipe(gulp.dest(outputPath)); return '/' + outputFolder + '/' + fileName; } }; var stream = gulp.src(styleEntries[style]) .pipe(postcss([url(options)])) .pipe(less({ math: 'parens-division' })); if (production) { stream = stream.pipe(cleanCss()); } return stream .pipe(concat(bundleName)) .pipe(gulp.dest('wwwroot/' + bundlePath)); } function findMatchingElements(path, array) { var result = []; for (var item in array) { if (array[item].indexOf(path) >= 0) { result[item] = array[item]; } } return result; } function watchScriptEntries() { for (var script in scriptEntries) { var watcher = watch(scriptEntries[script]); watcher.on('change', function (path, stats) { console.log(`${path} updated`); var changedBundles = findMatchingElements(path, scriptEntries); for (var changedBundle in changedBundles) { createScriptBundle(changedBundle); } }); } } function watchStyleEntries() { for (var style in styleEntries) { var watcher = watch(styleEntries[style]); watcher.on('change', function (path, stats) { console.log(`${path} updated`); var changedBundles = findMatchingElements(path, styleEntries); for (var changedBundle in changedBundles) { createStyleBundle(changedBundle); } }); } } function build() { production = true; fillScriptBundles(); fillStyleBundles(); fillScriptMappings(); var scriptTasks = createScriptBundles(); var styleTasks = createStyleBundles(); return merge(scriptTasks.concat(styleTasks)); } function buildDev() { fillScriptBundles(); fillStyleBundles(); fillScriptMappings(); var scriptTasks = createScriptBundles(); var styleTasks = createStyleBundles(); watchScriptEntries(); watchStyleEntries(); console.log('Bundles are being created, please wait...'); return merge(scriptTasks.concat(styleTasks)); } function clearReadOnlyAttribute(path) { console.log('Ensuring files are editable, please wait...'); require('child_process').exec('attrib -r "' + path + '\*.*" /s /d'); } // boneill: Make all files and folders in wwwroot editable. Fixes TFS locking issue for bundle generation. clearReadOnlyAttribute('./wwwroot/'); exports.build = build; exports.buildDev = buildDev;
-
0
Hi
The
gulpfile.js
is no problem. Have you tried the zero demo project? -
0
Hi,
OK I did some more investigation on this. It works correctly if I run it locally on my dev machine. But when run in devops, the build process completes without errors but the files are not changed. I am still trying to ascertain the cause, so if anyone else has experienced the same issue, I would be interested in hearing how it was resolved.
-
0
Hi @compassinformatics17
Is your DEV and DevOps environments has the same Node version ?
-
0
Hi Sorry for the late reply.
I'm using Yarn to handle dependencies as specified in this AspNetZero Tutorial. All works fine but the files are not changed on the azure version.
Below are a few images detailing the config and build task output in DevOps. It runs fine but the JS files are not minified in the artefact once the build completes on DevOps. I cannot see what's amiss and why the files are not being minified since all appears correct to my eyes.
Thanks, Barry.
-
0
Hi @compassinformatics17
Does the min versions of the files exist in your Azure environment before you run the
npm run build
command ? If so, can you try to delete one of those min files and run the pipeline again ? This might be related to a file write permission.Thanks,
-
0
Hello @compassinformatics17 and @ismcagdas
The gulp task in my azure pipeline previously working fine but as it was taking too much time and we didn't have frequent changes in theme, I disabled that task. But now after enabling I am facing similar issue and the files are not getting minified. In Visual Studio using Task Runner gulp file makes minified files and applies theme related changes but it does not work in the Azure DevOps pipeline.
Did you guys finally found any workaround in the pipeline task or fix? Please advise.
Thanks.
-
0
Hi @ISTeam
Could you check if files in the output folder are cleared before creating new bundles ?
-
0
Thank you for your reply @ismcagdas
Unfortunately I am not sure which output folder you are mentioning. I tried to manually delete entire wwwroot directory from the deployment folder on our on-premises machine but that didn't help.
The CI pipeline I have created last year with mostly v8.1.0 was using graphical interface in Azure DevOps as per the documentation. So, I tried to set 'Source and Output directory' cleaning suggested in this SO post answer.
After two release I verified that all the CSS/JS including min files under the wwwroot subdirectories are updated but still the header title and its padding are somewhat different in the production.
But this is how it looks in development env and
something different in production
@Update: Finally I found that it was because of Visual Settings => Subheader => Subheader style was different. In dev it was "Solid" and in production it was "Transparent" causing the padding like difference. Wondering as this was the root cause of the problem and initially we guess that this setting might be something related to background color only!
-
0
Hi @ISTeam
I'm glad that it is solved :)