Exclude non-minified files from publish in `project.json` with ASP.NET Core - asp.net-core

I am trying to find a proper configuration for the publishOptions inside project.json (ASP.NET Core 1.0 / Full Framework) so that non-minified files are not published.
Official documetation doesn't help much: project.json reference.
Searching for globbing patterns, and finding some artilcles with gulp examples, I came up with this wwwroot/js/**/*!(*.min.js), but it doesn't seem to work.
Is my syntax wrong? Or, it's just that project.json and dotnet publish don't support this syntax?
"publishOptions": {
"include": [
"wwwroot",
"Views",
"Areas/**/Views",
"appsettings.json",
"web.config"
],
"exclude": [
"wwwroot/lib",
"wwwroot/js/**/*!(*.min.js)",
"wwwroot/css/*.less",
"wwwroot/_references.js"
],
"includeFiles": [],
"excludeFiles": []
},

The typical workflow for JavaScript files/libraries management is to use gulp or grunt tasks to copy over the necessary files into the wwwroot folder which may happen on certain events (prebuild, postbuild, project open, clean).
In the latest tooling, the default MVC doesn't include gulpfile.js anymore as the most common usage was to minify and bundle js files, even when no external libraries were used so gulp may be a bit overwhelming for new users.
But it can easily be brought back, when you right-click the bundleconfig.json file in the solution explorer and choose "Bundler & Minifier" > "Convert to Gulp".
This creates a gulpfile.js and package.json (nodejs dependencies) in the root of your project and adds npm folder to the "Dependencies" section of Solution Explorer. When you watch in the Windows Explorer, you'll see a node_modules folder in the project root folder. That's where npm will download all packages and it's dependencies.
The generated gulpfile.js looks like this and has a few predefined tasks. i won't use this file as example, as it is strongly based on the bundleconfig.json and it's structure and use my gulpfile.json which used to be shipped with older templates.
"use strict";
var gulp = require("gulp"),
rimraf = require("rimraf"),
concat = require("gulp-concat"),
cssmin = require("gulp-cssmin"),
uglify = require("gulp-uglify");
var webroot = "./wwwroot/";
var paths = {
app: webroot + "app/",
libs: webroot + "lib/",
js: webroot + "js/**/*.js",
minJs: webroot + "js/**/*.min.js",
css: webroot + "css/**/*.css",
minCss: webroot + "css/**/*.min.css",
concatJsDest: webroot + "js/app.min.js",
concatCssDest: webroot + "css/app.min.css"
};
gulp.task("clean:js", function (cb) {
rimraf(paths.concatJsDest, cb);
});
gulp.task("clean:libs", function (cb) {
rimraf(paths.libs, cb);
});
gulp.task("clean:css", function (cb) {
rimraf(paths.concatCssDest, cb);
});
gulp.task("clean", ["clean:js", "clean:css", "clean:libs"]);
gulp.task("min:js", function () {
return gulp.src([paths.js, "!" + paths.minJs], { base: "." })
.pipe(concat(paths.concatJsDest))
.pipe(uglify())
.pipe(gulp.dest("."));
});
gulp.task("min:css", function () {
return gulp.src([paths.css, "!" + paths.minCss])
.pipe(concat(paths.concatCssDest))
.pipe(cssmin())
.pipe(gulp.dest("."));
});
gulp.task("min", ["min:js", "min:css"]);
gulp.task("libs", function (cb) {
gulp.src([
'bootstrap/**/*.js',
'bootstrap/**/*.css',
'jquery/**/*.js`, // we can also limit this to `jquery/dist/**/*.js to only include distribution files
'jquery/**/*.css'
], {
cwd: "node_modules/**"
})
.pipe(gulp.dest(paths.libs));
});
gulp.task("app", function (cb) {
gulp.src([
'app/**.js'
])
.pipe(gulp.dest(paths.app));
});
gulp.task("default", ['clean', 'libs']);
It looks more complicated than it actually is. There are several minizier tasks (min:js, min:css) and one general minifier task min which just runs all others in sequence.
A clean task which deletes the output file(s) from wwwroot. When converting from the template, it deletes only the default wwwroot/js/site.min.js file.
Since there are no javascript libraries used in the default template, except of what's inside the wwwroot/lib folder already the packages are not handled that way.
So first thing you may want is to grab bootstrap and jquery from npm rather than the static versions provided by the template. So we add the dependencies to the package.json.
{
"name": "app",
"version": "0.0.0",
"private": true,
"dependencies": {
"bootstrap": "3.3.6",
"jquery": "2.2.0"
},
"devDependencies": {
"gulp": "3.8.11",
"gulp-concat": "2.5.2",
"gulp-cssmin": "0.1.7",
"gulp-uglify": "1.2.0",
"rimraf": "2.2.8"
}
}
The libs task from the gulpfile.js above for example will copy over all required files of a package to wwwroot. I said required, because in the packages there are often unbundled files for debugging and stuff, which we usually don't want inside wwwroot (they can grow quite big).
gulp.task("libs", function (cb) {
gulp.src([
'bootstrap/**/*.js',
'bootstrap/**/*.css'
], {
cwd: "node_modules/**"
})
.pipe(gulp.dest(paths.libs));
});
It will look for all *.js and *.css files within the bootstrap folder in node_modules folder and copy them over to path.libs which is configured as wwwroot/lib/.
The app task does the same for our own code. clean clears the folders and (i.e. before switching from debug to release build or before publishing).
Finally you can bind the tasks to certain VS Events. You need to open the "Task Runner Explorer" View (View > Other Window > Task Runner Explorer). There you can choose a task and right-click it, then "Binding" and choose one of the binding (Before Build, After Build, Clean, Projct Open). They are pretty self explaining, "Clean" means when you do "Build > Clean Solution".
Now to the publishing part. You can run certain command, when you publish your application (either via dotnet or Visual Studio).
In the project.json there is a scripts section for this.
"scripts": {
"prepublish": [ "npm install", "bower install", "gulp clean", "gulp min", "gulp libs" ],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}
Each of the entries "prepublish" is one command to be executed. In this example, before the publishing begins, npm install will be executed first in order to restore all npm dependencies. Then bower install to install the dependencies managed by bower (remove it if you don't use bower and do all via npm).
The next three commands are the interesting ones, they will execute gulp tasks. We can also simplify this by adding a "publish" task.
gulp.task("publish", ['clean', 'libs', 'min']);
"scripts": {
"prepublish": [ "npm install", "bower install", "gulp publish" ],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}
This will copy all the necessary files for publishment into the wwwroot folder, publish the files and then call the "postpublish" scripts.
That's a rough introduction in gulp. It's has a learning curve, but once you get it working it imrpoves the overall workflow.
What's not covered here is to add a watch task which may look into a certain folder (I usually use app folder in the project root) and when any file changes there run the app task, so the our code gets minifed and copied over to wwwroot and is available when we debug it.

A simple alternative is:
Rename unminified source to *.debug.js and *.debug.css
They are now easier to exclude:
"publishOptions": {
"include": [
"wwwroot"
],
"exclude": [
"wwwroot/**/*.debug.*"
]
}
IMHO unminified source should stick out and look abnormal. It is more deserving of a file name wart than minified code.
This also brings the build output files into line with the rest of the .Net build configuration. It makes it clear that your debug versions may well include extra logging and debug utilities and that its not for production.

Related

Deployment error firebase hosting - 0 files found

Description:
During the deploy of firebase hosting, I received an error stating that 0 files were found. I have included my firebase.json file for reference.
Steps to reproduce:
Run the command firebase deploy --only hosting
Observe the error message stating that 0 files were found
Expected result:
The firebase hosting should be successfully deployed with the specified files.
Actual result:
An error is thrown stating that 0 files were found.
+ hosting: Finished running predeploy script.
i hosting[hosting-project]: beginning deploy...
i hosting[hosting-project]: found 0 files in hosting
+ hosting[hosting-project]: file upload complete
i hosting[hosting-project]: finalizing version...
+ hosting[hosting-project]: version finalized
i hosting[hosting-project]: releasing new version...
+ hosting[hosting-project]: release complete
+ Deploy complete!
Notes:
I have double-checked the file path in the firebase.json file and it
appears to be correct.
I have tried rerunning the deploy command multiple times with the same result
I have also tried deploying a
different project with the same firebase.json file, but the issue
persists.
In my firebase.json file, I am not targeting the dist folder directly because I am using the predeploy script to run npm run lint and npm run build before the deployment. However, I am not ignoring the dist folder with !dist% and !dist/*, which means I am not excluding it from the deployment.
Attached files:
firebase.json
{
"firestore": {
"port": "8080"
},
"functions": [
{
"source": "functions",
"codebase": "default",
"ignore": [
"node_modules",
".git",
"firebase-debug.log",
"firebase-debug.*.log"
],
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run lint"
]
}
],
"hosting":{
"public":"hosting",
"ignore": [
"*",
"!dist/",
"!dist/*",
],
"rewrites":[
{
"source":"**",
"destination":"dist/index.html"
}
],
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run lint",
"npm --prefix \"$RESOURCE_DIR\" run build"
]
}
}
I found a solution to resolve the issue of "0 files found" during the deploy of firebase hosting. It may not be the most elegant solution, but it does work. In the "predeploy" section of the hosting configuration, I added ".." at the end of the "npm run lint" and "npm run build" commands to go back to the root folder:
"npm --prefix \"$RESOURCE_DIR\\..\" run lint",
"npm --prefix \"$RESOURCE_DIR\\..\" run build"
This allowed me to target the dist folder directly in the hosting configuration, as specified in the official documentation. Here is the modified hosting configuration:
"hosting":{
"public":"hosting/dist",
"ignore": [
"**/.*",
"**/node_modules/**"
],
"rewrites":[
{
"source":"**",
"destination":"/index.html"
}
],
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\\..\" run lint",
"npm --prefix \"$RESOURCE_DIR\\..\" run build"
]
}
I hope this helps anyone else who may be experiencing the same issue.

.npmignore ignored when installing local module

All our server projects contain a git submodule folder (let's say modules), which contains our custom modules/components.
Such module dependencies are installed locally (see serverApp/package.json) so that we don't have to include the whole submodule folder to the final rpm. What I'm having trouble with is limiting the number of files included in node_modules.
The submodule structure looks like the following:
modules
|--loader
|--dist => compiled js files here that are created when installing the module
|--ts => contains typescript files that shouldn't be included in node_modules
|--package.json
|--tsconfig.json
|--more modules
|--.gitignore
Adding an .npmignore file inside modules/loader doesn't seem to help as the whole folder is copied.
modules/loader/tsconfig.json:
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"declaration": true,
"outDir": "./dist",
"strict": true
}
}
modules/loader/package.json:
{
"name": "loader",
"version": "1.2.0",
"private": true,
"description": "",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"preinstall": "npm run build",
"build": "../../node_modules/typescript/bin/tsc",
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"#types/lodash": "^3.9.3",
"#types/nomnom": "0.0.28",
"#types/yamljs": "^0.2.30",
"lodash": "^3.9.3",
"nomnom": "^1.8.1",
"yamljs": "^0.2.1"
},
"devDependencies": {
"typescript": "~2.3.4"
}
}
serverApp/package.json:
{
"name": "my-server-app",
"version": "2.3.0",
"description": "",
"main": "myServerApp.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"license": "private",
"dependencies": {
"loader": "file:modules/loader"
},
"devDependencies": {
"grunt": "^0.4.5",
"grunt-cli": "^0.1.13"
}
}
I'm not sure if it has to do with the fact that we have a .gitignore file or because the module is not published and installed locally.
npm version => 5.3.0
EDIT
Doesn't work with specifying the "files" in modules/loader/package.json either
As after checkout the issue I found out below useful points which need to mention out :
We use a .npmignore file to keep stuff out of your package.
If there's no .npmignore file, but there is a .gitignore file, then npm will ignore the stuff matched by the .gitignore file.
If you want to include something that is excluded by your .gitignore file, you can create an empty .npmignore file to override it.
Like git, npm looks for .npmignore and .gitignore files in all subdirectories of your package, not only the root directory.
Similar to .gitignore file .npmignore also follow these rules
Blank lines or lines starting with # are ignored & Standard glob patterns work.
You can end patterns with a forward slash / to specify a directory.
You can negate a pattern by starting it with an exclamation point !.
By default, the following paths and files are ignored, so there's no need to add them to .npmignore explicitly
Additionally, everything in node_modules is ignored, except for bundled dependencies. npm automatically handles this for you, so don't bother adding node_modules to .npmignore.
Testing whether your .npmignore or files config works
If you want to double check that your package will include only the files you intend it to when published, you can run the npm pack command locally which will generate a tarball in the working directory, the same way it does for publishing.
And you can also checkout same issue here Consider methodologies for reducing the number of files within node_modules #14872
Thanks.
Did you checked with node 0.6.13 / npm 1.1.9? This issue is common in npm 1.1.4 .
have a look on this link
You mentioned that you do not want to include "whole submodule" into the "final rpm", by which I presume the package you will finally prepare. I reproduced similar setup and added a '.npmignore' to ignore "submodule" which I installed using npm install --save ./task_in where 'task_in' was my module kept along side of the main package's('task') 'package.json'.
And when the final package was prepared using npm pack while being in the 'task' folder, I got a package(a tar file) without the folder('task_in') as indicated in the '.npmignore'.
While working, though, I found that the module 'task_in' folder was copied to 'node_modules' which is automatically not included in the final package( refer here). Also, while the package is prepared, ".gitignore" is over-ridden by ".npmignore".
So, this is my "two cents" and I hope it helps you.

Move browserify workflow into gulp task [vueify, browserify, babelify]

I'm trying to migrate the following browserify workflow into a single gulp task:
package.json:
"scripts": {
"build": "browserify src/main.js > dist/build.js"
},
...
"browserify": {
"transform": [
"vueify",
"babelify"
]
}
.babelrc file:
{
"presets": ["es2015"]
}
Since gulp-browserify is now longer maintained, I used this recipe to get the whole workflow into a single gulp task:
gulp.task('build', function () {
var b = browserify({
entries: './src/main.js',
debug: true,
transform: [vueify, babelify.configure({presets: ["es2015"]})]
});
return b.bundle()
.pipe(source('build.js'))
.pipe(buffer())
.on('error', gutil.log)
.pipe(gulp.dest('./dist/'));
});
Unfortunately, the generated build.js files are different and only the build.js file generated by the command npm run build is running my Vue.js App properly.
I just managed to get past this problem myself. After spending a bit of time in the debugger I found that the array of transforms used by browserify contained 'babelify' and 'vueify' twice.
What happens then is probably that the transforms are applied like so: bablify -> vueify -> babelify -> vueify. I didn't spend much time figuring out exactly how that blew up my stuff since the problem is easy enough to get rid of.
Either specify browserify transforms in package.json OR in your gulp file. Not both.

Pulling files from a directory into the root folder for NPM

I am publishing a library to NPM.
When I build the library, the resulting artifact is placed in the dist folder located in the root of my project as index.js.
When users install from NPM I would like index.js to be present in the root of the folder created in their node_modules folder. Presently, it remains in a directory named dist.
How can I do this?
My packages.json:
{
"name": "my-package",
"version": "0.0.9",
"files": ["dist/*"],
"main": "index.min.js",
"private": false,
"dependencies": {},
"devDependencies": {},
"repository": "git#github.com:username/my-package.git"
}
I had exactly the same problem.
I solved it not by copying the files up, but by copying the files I needed down into the ./dist/ folder and then doing an npm publish from there; NPM then treats that folder as a complete package and everything works very nicely. The only files I needed to copy from the root folder were:
package.json
README.md
Because we're going to copy these files down into the ./dist/ folder before we do the publish, we do NOT want the package.json file to reference ./dist/. So remove the package.json's files entry completely, because we don't need to tell it which files we'll take - we're going to take everything in the ./dist/ folder. I'm using TypeScript so I also have a typings entry, and again no reference to ./dist/.
{
"name": "my-package",
"version": "0.0.9",
"main": "index.min.js",
"typings": "index.d.ts",
"private": false,
"dependencies": {},
"devDependencies": {},
"repository": "git#github.com:username/my-package.git"
}
Now for the publish step. I built a gulp task that will perform the publish for me, making it nice and automated (except for incrementing the package version #).
From gulp I'll use Node's spawn() to kick-off the npm process. However, because I'm actually working on Windows I used "cross-spawn" rather than the normal built-in Node.js spawn (which I learned the hard way didn't work when I had spaces in my path!).
Here's my gulp file, with the TypeScript bits removed:
var gulp = require('gulp');
var del = require('del');
var spawn = require('cross-spawn'); // WAS: require('child_process').spawn;
var config = {
src: { tsFiles: './src/**/*.ts' },
out: { path: './dist/' }
}
gulp.task('clean', () => {
return del('dist/*');
});
gulp.task('build', ['clean'], () => {
....
});
gulp.task('publish', ['build'], (done) => {
// Copy the files we'll need to publish
// We just use built-in gulp commands to do the copy
gulp.src(['package.json', 'README.md']).pipe(gulp.dest(config.out.path));
// We'll start the npm process in the dist directory
var outPath = config.out.path.replace(/(\.)|(\/)/gm,'');
var distDir = __dirname + '\\' + outPath + '\\';
console.log("dist directory = " + distDir);
// Start the npm process
spawn('npm', ['publish'], { stdio:'inherit', cwd:distDir } )
.on('close', done)
.on('error', function(error) {
console.error(' Underlying spawn error: ' + error);
throw error;
});
});
Notice when we call spawn() we pass in a 3rd argument which is the options. The main entry here is the cwd:distDir, which tells spawn to run the npm process from the ./dist/ directory. Because using spawn can cause problems I've hooked into the spawn error handling. As I was troubleshooting my use of spawn() I found the following StackOverflow article very helpful.
This worked like a charm; my published package has all the files in the root directory and the ./dist/ folder is not published.

Durandal.js optimizer not working (empty main-built.js)

I'm trying to get Durandal.js optimizer working on my test project, but it seems to generate nothing to main-built.js. I use the following command from node.js command prompt, in durandal/amd folder:
optimizer.exe --verbose true
Result is
Using default base configuration.
Configuring for deploy with almond (custom).
{
"name": "durandal/amd/almond-custom",
"inlineText": true,
"stubModules": [
"durandal/amd/text"
],
"paths": {
"text": "durandal/amd/text"
},
"baseUrl": "C:\\Users\\Tommi Gustafsson\\Documents\\Visual Studio 2012\\Projects\\DurandalTests\\DurandalTest1\\TestApp",
"mainConfigFile": "C:\\Users\\Tommi Gustafsson\\Documents\\Visual Studio 2012\\Projects\\DurandalTests\\DurandalTest1\\TestApp\\main.js",
"include": [
"main-built",
"main",
"bindings/tinymce-binding",
"durandal/app",
"durandal/composition",
"durandal/events",
"durandal/http",
"text!durandal/messageBox.html",
"durandal/messageBox",
"durandal/modalDialog",
"durandal/system",
"durandal/viewEngine",
"durandal/viewLocator",
"durandal/viewModel",
"durandal/viewModelBinder",
"durandal/widget",
"durandal/plugins/router",
"durandal/transitions/entrance",
"raphael-amd/eve.0.3.4",
"raphael-amd/raphael.2.1.0.amd",
"raphael-amd/raphael.2.1.0.core",
"raphael-amd/raphael.2.1.0.svg",
"raphael-amd/raphael.2.1.0.vml",
"viewmodels/flickr",
"viewmodels/modal1",
"viewmodels/myPage",
"viewmodels/shell",
"viewmodels/welcome",
"text!views/detail.html",
"text!views/flickr.html",
"text!views/modal1.html",
"text!views/myPage.html",
"text!views/shell.html",
"text!views/welcome.html"
],
"exclude": [],
"keepBuildDir": true,
"optimize": "uglify2",
"out": "C:\\Users\\Tommi Gustafsson\\Documents\\Visual Studio 2012\\Projects\\DurandalTests\\DurandalTest1\\TestApp\\main-built.js",
"pragmas": {
"build": true
},
"wrap": true,
"insertRequire": [
"main"
]
}
Deleting old output file.
Tracing dependencies for: durandal/amd/almond-custom
Then, when I check main-built.js, it is empty. Can anyone help me what is the problem? I have several AMD modules in the test project, including Raphael.js AMD modules.
My requirejs configuration looks like this:
requirejs.config({
paths: {
'text': 'durandal/amd/text',
'eve': './raphael-amd/eve.0.3.4',
'raphael.core': './raphael-amd/raphael.2.1.0.core',
'raphael.svg': './raphael-amd/raphael.2.1.0.svg',
'raphael.vml': './raphael-amd/raphael.2.1.0.vml',
'raphael': './raphael-amd/raphael.2.1.0.amd',
'tinymce': "../Scripts/tinymce/jquery.tinymce.min"
}
});
In the same amd folder, where optimizer is stored, try running node r.js -o app.build.js. I've seen r.js sometimes choke about some dependencies, which resolves without problem when loading via require.js. For whatever reason the error messages won't show up when using optimizer --verbose. Typically the error message provides enough information to see where this occurs and if you've to update require.contig.paths or a specific define dependency.