I'm a late arrival to the Bower scene. I thought I'd try it with my current Express project. I installed it, and created the .bowercc and bower.json file per instructions. I installed a Bootstrap skin I planned on using, which brought with it jQuery. The thing is, you get tons of files, and I'd like to use just the minified versions of JS, CSS and fonts.
After scowering the net, I found a lot about using gulp or grunt to sift through the files, and pipe them to the /public folder Express provides. My question is: how do you do it properly? How do I get just the files I need there? Or am I better off foregoing bower and just downloading the zip file, picking up the end result and placing in the /public folder?
Looking at the comments, it seems like the answer is yes - manual job is required to get your components distributeables to your public folder. Using gulp will automate it, but basically it'd be a hit-and-miss at first, requiring some fine tuning. In case someone lands on this question, here's the solution I went with:
1) Provide package overrides in the bower.json file to ake sure only the minified files are exposed:
{
"name": "charlie",
"dependencies": {
"bootstrap-material-design": "~0.3.0"
},
"overrides": {
"bootstrap-material-design": {
"main": ["**/dist/js/*.min.js", "**/dist/css/*.min.css", "**/dist/fonts/*"]
},
"jquery": {
"main": "**/dist/jquery.min.js"
}
}
}
2) Use the main-bower-files gulp package to grab those "mains" and distribute them to the final locations. Here's my gulpfile.json (just the bower part:
var bower = require('main-bower-files');
var gulpFilter = require('gulp-filter');
var uglify = require('gulp-uglify');
var minifyCSS = require('gulp-minify-css');
var clean = require('gulp-clean');
var debug = require('gulp-debug');
var getDist = function(vendor) {
var publicDir = 'public';
var dist = vendor ? publicDir + '/vendor' : publicDir;
return {
dir: dist,
css: dist + '/css/',
js: dist + '/js/',
fonts: dist + '/fonts/'
};
};
gulp.task('cleanVendor', function() {
return gulp.src(getDist(true).dir, {read: false})
.pipe(clean());
});
gulp.task('bower', ['cleanVendor'], function() {
var dist = getDist(true);
var jsFilter = gulpFilter('**/*.js');
var cssFilter = gulpFilter('**/*.css');
var fontsFilter = gulpFilter(['**/*.woff*', '**/*.eot', '**/*.svg', '**/*.ttf']);
return gulp.src(bower())
.pipe(fontsFilter)
.pipe(gulp.dest(dist.fonts))
.pipe(fontsFilter.restore())
.pipe(jsFilter)
.pipe(gulp.dest(dist.js))
.pipe(jsFilter.restore())
.pipe(cssFilter)
.pipe(gulp.dest(dist.css))
.pipe(cssFilter.restore());
});
3) In your HTML file, include /vendor/js/blah.min.js or /vendor/css/blah.min.css
Note: the annoying part was that I had to specify every font extension in the fontsFilter. I tried using '**/fonts/*' but main-bower-files returns a flat list of files, and if you provide the {base: 'mybase'} parameter, it returns a tree, meaning you get the entire tree structure per file - anyone who can come up with a fix, is invited to submit an answer.
Related
I created an app with vue-cli and then I build the dist folder for production.
The app is deployed on IIS with flask backend and works fine.
The problem occurs when I have to make some changes and I have to redo the deployment. After this, users call me because app doesn't work but if I clear the chrome cache, the app works fine again.
How can I fix this problem? Is there a method to clear chrome cache automatically when I release a new application version?
Thanks
my dist folder
deployment: copy and paste folder dist on IIS
if files in dist folder are correct, maybe the problem is in axios cache? i have make some changes also to rest apis
I had the same problem and changing (incrementing) the version number in package.json before running the build command fixed it.
For example by default the version number is set to "0.1.0"
package.json file:
{
"name": "project-name",
"version": "0.1.1",
"private": true,
...
}
If you use vue-cli, then it has built-in webpack configs for building dist. And in fact it adds hash-names to output files.
But if it was removed somehow, you can add it back to webpack config like
output: {
filename: '[name].[hash].bundle.js'
}
And your app will looks like this:
And even more, you do not need to handle how all this stuff will be added to html, coz webpack will figure it out for you.
You need to add a version query to your js file. This is how a browser can know if the file has changed and needs to download the new version.
So something like:
<script src="main.js?v=1.1"></script>
<script src="main.js?v=1.2"></script>
etc...
Assuming this is nothing to do with service worker/PWA, the solution could be implemented by returning the front-end version.
axiosConfig.js
axios.interceptors.response.use(
(resp) => {
let fe_version = resp.headers['fe-version'] || 'default'
if(fe_version !== localStorage.getItem('fe-version') && resp.config.method == 'get'){
localStorage.setItem('fe-version', fe_version)
window.location.reload() // For new version, simply reload on any get
}
return Promise.resolve(resp)
},
)
You can also ensure the fe-version is returned based on any sort of uniqueness, here I have used the commit SHA.
Full Article here: https://blog.francium.tech/vue-js-cache-not-getting-cleared-in-production-on-deploy-656fcc5a85fe
You can't access the browser's cache, that would be huge a security flaw.
To fix it, you must send some headers with your flask responses telling the browser not to cache you app.
This is an example for express.js for you to get the idea:
setHeaders: function (res, path, stat) {
res.set('Cache-Control', 'no-cache, no-store, must-revalidate') // HTTP 1.1
res.set('Pragma', 'no-cache') // HTTP 1.0
res.set('Expires', '0') // Proxies
}
You can read a lot more about caching in here.
This is an older post, but since I could not find the solution for this problem online, ill just post this here in case someone else might find it usefull.
I added the hash to the appllication chunk files via the webpack.mix.js file by adding:
mix.webpackConfig({
output: {
chunkFilename: 'js/[name].js?id=[chunkhash]',
},
})
This adds a fingerprint to the actual chunks and not just the app.js file. You can add a version name to the app.js file aswell by adding version(['public/js/app.js']); at the end of the file, or add filename: '[name].js?[hash]' to the output block.
My complete webpack.mix.js:
const mix = require('laravel-mix');
mix.webpackConfig({
output: {
chunkFilename: 'js/main/[name].js?id=[chunkhash]',
}
}).js('resources/js/app.js', 'public/js').vue()
.postCss('resources/css/app.css', 'public/css', [
//
]).version(['public/js/app.js']);
In my laravel blade file I used
<script src="{{ mix('js/app.js') }}"></script>
to load the app.js file with the correct version fingerprint.
The answer for me was caching at my DNS provider level.
Basically, I'm using Cloudflare DNS proxy and they are caching the website so in development mode I was not getting the code updates.
I had to clear the cache many times to get anything to change. I had to wait a significant period of time before anything update.
Turned it off and it stopped doing that.
the method I want to suggest
<script src="{{ asset('js/app.js?time=') }}{{ time() }}" defer></script>
add below script in publc/index.html
<head>
...
<script type="text/javascript" language="javascript">
var timestamp = (new Date()).getTime();
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "<%= BASE_URL %>sample.js?t=" + timestamp;
document.head.appendChild(script);
</script>
...
</head>
could you try ?
vm.$forceUpdate();
Also it's possible that the component it self needs a unique key :
<my-component :key="unique" />
We have a *.sln that includes an ASP.NET Core RC2 *.csproj for client html only (ASP.NET Controllers are in another *.csproj).
This gives the following folder/file structure:
SolutionRoot/
ClientProjectRoot/ <- project root, npm root folder
wwwroot_dev/ <- location of src dev files,
wwwroot/ <- where gulp concats, minimifies, optimises, and root of static pages
bower_packages/
node_modules/
package.json
bower.json
.bowerrc <- where 'directory' is set to 'wwwroot/bower_packages/'
gulpfile.js
Requirements I'd like to meet are:
The csproj is only client artifacts, with no asp.net C# code, so that we can give the whole project to external devs with UI expertise, and slot it back into the solution when done.
The wwwroot/index.html file should be accessible as http://example.com/index.html -- not http//example.com/wwwroot.html
CSS and JS should be minified, and in wwwroot, and html picked up from there (ie wwwroot_dev is there just for editing purposes but never served from directly).
No idea where bower packages should be -- part of this question.
The gulpfile has tasks defined, which correctly minify the css and scripts found in wwwroot_dev into app.min.js and app.min.css within wwwroot.
It's the html files, passed through gulp-inject and wiredep that get their relative pathing wrong. They both include wwwroot in the output.
My files so far are:
.bowerrc:
{
"directory":"wwwroot/bower_components"
}
And in gulpfile.js, the html task looks as follows:
gulp.task('dist:html',['dist:scripts'],function(){
//get the dest js and css that previous tasks have already minifieded:
var sources = gulp.src(
['wwwroot/scripts/**/*.js', 'wwwroot/scripts/**/*.css'],
{read:false}
);
return gulp
.src("wwwroot/scripts/**/*.html", {})
.pipe(plugins.inject(sources, {relative:true}))
.pipe(plugins.wiredep(sources,{relative:true}))
.pipe(gulp.dest("wwwroot/");
});
The output is (wrong) as it mentions wwwroot/, when it simply be ../js/ etc:
<!-- bower:js -->
<script src="../wwwroot/bower_components/jquery..."></script>
<!-- endbower -->
<!-- inject:js -->
<script src="/wwwroot/js/main.min.js"></script>
<!-- endinject -->
I serve from wwwroot:
gulp.task('serve',function(){
return gulp
.src('wwwroot')
.pipe(plugins.webserver(
{ directoryListing:false,open:"http://localhost:8000/"}))
}
I've tried lots of different inject and wiredep option flags (relative:true, ignorePath, cwd, -- but wwwroot is always mentioned. Can't get rid of it!)
So my question is...
a) is my directory structure approximately right -- or totally flawed
b) if basically right, what tweak can I do to get the paths generated by inject and wiredep to be relatively right?
Thank you!
Try this
gulp.task('render', function () {
var target = gulp.src('./Views/Shared/_Layout.cshtml');
var sources = gulp.src([path.wwwroot + "/**/*.js", path.wwwroot + "/**/*.css"], { read: false });
return target.pipe(inject(sources, {
transform: function (filepath) {
//Delete wwwroot
for (var i = 0; i < arguments.length; i++) {
if (typeof (arguments[i]) == 'string')
arguments[i] = arguments[i].replace("/wwwroot", '');
}
return inject.transform.apply(inject.transform, arguments);
}
}))
.pipe(gulp.dest('./Views/Shared'));
Had the same issue, solved it based on this solution:
https://stackoverflow.com/a/34581414
gulp.task('inject', function () {
var target = gulp.src('src/_Layout.cshtml');
return target.pipe(inject(
gulp.src(paths.wwwroot + 'css/**/*.css', { read: false }),
{
transform: function (filePath) {
var newPath = filePath.replace('/wwwroot', '');
return '<link rel="stylesheet" href="' + newPath + '"/>';
}
})
)
.pipe(gulp.dest('Views/Shared'));
});
I have app.js that looks like:
var noflo = require("noflo");
var graph = noflo.graph.createGraph("PrintValueGraph");
graph.addNode("output", "Print");
graph.addInitial(100,"output","in");
var network = noflo.createNetwork(graph);
And I have a Print.coffee script in the same dir, that has the same code as Output.coffee on the noflo-core folder.
I get the error: no process defined for inbound node output.
Do u have any idea, what the problem is?
Thanks
You must declare the Print component in the package.json
"noflo": {
"components": {
"Print": "./Print.coffee"
}
}
Components need to be registered in the package.json (or component.json for the browser) for the NoFlo ComponentLoader to find them.
See example: https://github.com/c-base/ingress-table/blob/master/package.json#L41
There is also the grunt-noflo-manifest package that can automate this for you.
The convention is to keep your components in a components/ subdirectory inside your project.
I got my less files compiled in css perfectly by grunt and I see result in .tmp/public/styles
So now livereload with grunt-contrib-watch should be made naturally in sails generated project ?
Or do I have to make a special configuration ?
I found that in tasks/pipeline.js file but not sure of what to do.
// CSS files to inject in order
//
// (if you're using LESS with the built-in default config, you'll want
// to change `assets/styles/importer.less` instead.)
var cssFilesToInject = [
'styles/**/*.css'
];
I saw in the file tasks/README.md :
###### `sails lift`
Runs the `default` task (`tasks/register/default.js`).
And in the file default.js we got :
module.exports = function (grunt) {
grunt.registerTask('default', ['compileAssets', 'linkAssets', 'watch']);
};
But watch.js file is missing in the folder...
What should it be ?
Watch does only looking for files that have changed and execute less, sass, injection and so on - but it doesn't make a reload.
You can add this in task/config/watch.js
I am trying to get broccolijs to compile a directory of less files using broccoli-less. I have altered the "preprocess" function as follows:
var compileLess = require('broccoli-less')
var pickFiles = require('broccoli-static-compiler')
function preprocess (tree) {
tree = filterTemplates(tree, {
extensions: ['hbs', 'handlebars'],
compileFunction: 'Ember.Handlebars.compile'
})
tree = filterCoffeeScript(tree, {
bare: true
})
tree = compileLess(tree, {
compress: false,
})
return tree
}
In my project folder I have a directory called 'less' which I include in Brocfile.js:
var lessStyles = 'less'
lessStyles = pickFiles(lessStyles, {
srcDir: '/',
files: ['main.less'],
destDir: 'appkit'
})
lessStyles = preprocess(lessStyles)
var sourceTrees = [app, styles, vendor, lessStyles]
if (env !== 'production') {
sourceTrees.push(tests)
}
sourceTrees = sourceTrees.concat(findBowerTrees())
Trying to build this project yields the error:
$ broccoli serve
Serving on http://localhost:4200
path.js:360
throw new TypeError('Arguments to path.join must be strings');
^
TypeError: Arguments to path.join must be strings
at path.js:360:15
at Array.filter (native)
at Object.exports.join (path.js:358:36)
at tryPathIndex (/home/kyrre/beekeeper-frontend/node_modules/broccoli-less/node_modules/less/lib/less/index.js:223:37)
at callback.type (/home/kyrre/beekeeper-frontend/node_modules/broccoli-less/node_modules/less/lib/less/index.js:226:29)
at Object.oncomplete (fs.js:107:15)
Sounds like you're probably looking for broccoli-less-single instead of broccoli-less
From the README:
This plugin is designed to compile a single, primary input file into a
single output file, with a tree of #importd dependencies. This differs
from broccoli-less, which compiles each .less file individually into a
.css file and doesn't support #imports or a single output file
depending on multiple inputs.
As an aside, it looks like you're working with Ember.js -- if so, I would strongly recommend using ember-cli instead of rolling your own build pipeline. It easily supports less and provides lots of other features.