Closed AshleyGrant closed 7 years ago
@AshleyGrant did you find a workaround for this issue?
I haven't.
Resources only support html, CSS and JavaScript currently. Bundling other resources would require both bundling and runtime support.
On Jul 31, 2016 4:14 AM, "Ashley Grant" notifications@github.com wrote:
I haven't.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/aurelia/cli/issues/248#issuecomment-236417429, or mute the thread https://github.com/notifications/unsubscribe-auth/AAIBnRGadtXkbNZkbw19eoBAZnw3Ruccks5qbFlRgaJpZM4JYNwX .
We need to come up with a solution for this, not being able to properly support bundling bootstrap is going to be a sticking point. In the JSPM skeletons, we leave it unbundled and include the files with the exported app. Can we support something like that and still support loading the bootstrap css w/a require?
Anything is possible. Build a solution for it and we'll get it in.
This problem affects any other style framework, like Semantic-ui (same problem here)! Questions: As a workaround, you can't put your css imports on html with link instead require? Or will be a problem because of bundle?
As long as you include those files in the set of files you ship, that'll work no problem.
Yes, removing bootstrap from aurelia.json and adding <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.css">
to index.html works around the problem. Of course you have to include this node_modules folder with your deployment.
len-ro I fixed the issue by adding the bootstrap lib using its cdn to the app.html. It is not the best solution but it works with what we have now.
or just copy the fonts folder to '/bootstrap/fonts', that's where bootstrap is looking for them. you can create a task to automate that and add it to the build task.
+1 for getting this addressed.
Here's my workaround, it adds one function and one import to the buid task.
It copies the other resources (which are not .js
, .css
and .html
) to a folder with the same name as the dependency name. IMO - this is what aurelia-cli should do by default, no runtime support necessary.
Edit: added @patriktornros fixes,
this is in TypeScript, if you are translating this to JS - be careful with the closure scope inside the .pipe( rename(
aurelia_project/tasks/build.ts
import * as gulp from 'gulp'; import transpile from './transpile'; import processMarkup from './process-markup'; import processCSS from './process-css'; import {build} from 'aurelia-cli'; import * as project from '../aurelia.json'; import * as rename from 'gulp-rename'; export default gulp.series( copyOtherResources, readProjectConfiguration, gulp.parallel( transpile, processMarkup, processCSS ), writeBundles ); function copyOtherResources(done){ let stream, bundle = project.build.bundles.find(function(bundle){return bundle.name==="vendor-bundle.js";}); for( let i=0; i<bundle.dependencies.length; i++ ){ let dependency = bundle.dependencies[i], collectedResources = []; if( dependency.path && dependency.resources ){ let path = dependency.path.replace("../","./"); for( let n=0; n<dependency.resources.length; n++ ){ let resource = dependency.resources[n], ext = resource.substr(resource.lastIndexOf('.') + 1); if( ext!=='js' && ext!='css' && ext!='html' && ext!=='less' && ext!='scss'){ collectedResources.push(path+resource) dependency.resources.splice(n, 1); n--; } } if( collectedResources.length ){ let s = gulp.src( collectedResources, {passthrough: true, base: path} ) .pipe( rename( function(path){path.dirname = dependency.name +'/'+ path.dirname;return path;} )); stream = stream?stream.pipe(s):s; } } } if( stream ) stream.pipe(gulp.dest('.')); done(); } function readProjectConfiguration() { return build.src(project); } function writeBundles() { return build.dest(); }
The required dependencies are specified in aurelia.json
like this:
"prepend": ["node_modules/jquery/dist/jquery.js"],
"dependencies": [
{
"name":"lib/semantic",
"path":"../semantic/dist/",
"main":"semantic",
"exports": "$",
"resources":["semantic.css","themes/default/assets/fonts/icons.woff2"]
}
]
, I use prepend
as a workaround for issue #257
The above code would have been much more simple and easy to implement if the aurelia-cli build code did not rename the extension for non-html/css/js resources to .js
Also it would be nice to have a destination property for the dependency, where the files will be copied, the code above is using the name
for this purpose.
@geleto cant get the dependency.name into the pipe rename?
@patriktornros , check if every object in the dependencies array (in aurelia.json, app bundle) has a name property: { "name":"lib/semantic", "path":"../semantic/dist/", "main":"semantic", "exports": "$", "resources":["semantic.css","themes/default/assets/fonts/icons.woff"] }
If yes - put this line
console.log("Dependency: "+JSON.stringify(dependency));
before path.dirname=
and check the output:
@geleto needed to change
BUT still the browser is looking for a .wof.js looks ok in the rename function !!!?
@patriktornros
1&2 are ok, 3 might be needed if your paths do not end with /
I don't think 4 will fix the closure scope, unless you use another function to declare a new scope, to fix it just use 'let' to declare dependency
:
let dependency = appBundle.dependencies[i]
I have updated the code in my initial post.
The runtime should not try to load the resource at all - because we remove it ( see dependency.resources.splice(n, 1)
). The only place where your browser should be looking for the woff file is in the font-face declaration from your library css:
Call console.log( JSON.stringify( appBundle, null, " " ) );
before done() to make sure that all dependencies that do not start with css/js/html/less/scss have been removed from the configuration.
Make sure copyOtherResources is before readProjectConfiguration.
Please, address this. I'm new to Aurelia and am trying to use uikit, but same with fonts. As a newbie, I dont know how to apply the workahound.
In case it's unclear, here is all the steps for the easiest (manual) way to get bootstrap working. Use the same settings as the readme in aurelia CLI covers for aurelia.json dependencies section (here also including the theme css):
"dependencies": [
"jquery",
{
"name": "bootstrap",
"path": "../node_modules/bootstrap/dist",
"main": "js/bootstrap.min",
"deps": ["jquery"], "exports": "$", "resources": [
"css/bootstrap.css",
"css/bootstrap-theme.css"]
},
In the component you use bootstrap use the following require
<require from="bootstrap/css/bootstrap.css"></require>
then copy node_modules/bootstrap/dist/fonts into the root of your project. Then fonts will load. This would require you to deploy the following files and folders to a server:
Solution example: https://github.com/aurelia-ui-toolkits/aurelia-materialize-bridge/issues/284#issuecomment-250112393 (and link to SO).
Download files:
Copy files:
Add new prepare-font-glyphicons.js
in tasks folder with code:
import gulp from 'gulp';
import merge from 'merge-stream';
import changedInPlace from 'gulp-changed-in-place';
import project from '../aurelia.json';
export default function prepareFontGlyphicons() {
let source = 'src';
let taskCss = gulp.src(`${source}\\css\\font-glyphicons.css`)
.pipe(changedInPlace({firstPass:true}))
.pipe(gulp.dest(`${project.platform.output}\\css`));
let taskFonts = gulp.src(`${source}\\fonts\\*`)
.pipe(changedInPlace({firstPass:true}))
.pipe(gulp.dest(`${project.platform.output}\\fonts`));
return merge(taskCss, taskFonts);
}
Edit \tasks\build.js
and add following lines:
import prepareFontGlyphicons from './prepare-font-glyphicons'; // <<<<<<<<<<
export default gulp.series(
readProjectConfiguration,
gulp.parallel(
transpile,
processMarkup,
processCSS,
// my tasks
prepareFontGlyphicons // <<<<<<<<<<
),
writeBundles
);
Add in index.html
line:
<link rel="stylesheet" href="scripts/css/font-glyphicons.css">
Maybe I missed some lines, but someone should have pointed out trying to bundle font/image inside requirejs bundle would not solve this issue.
What you put in bundle is only visible to requirejs. When a browser sees a css file requesting a font or image resource, it would not use JavaScript require(...)
to get it.
Those font files must be copied out as @JayDi85 showed. Maybe aurelia.json
can make the task generic and easier.
I also find this one very crucial. I'm quite new to all this Javascript building and bundling and often struggeling even with simple tasks like including a css framework. This can get really annoying - especially because the actual programming with aurelia is so easy and you are just held up from doing the funny stuff ;)
To make life easier I adapted @geleto's approach so I can continue building my app a bit more conveniently. Although this is definitely just a very hacky workaround, others might benefit from it as well, so I added it to the end of this post. It adds the copied resource folders to .gitignore in order to avoid committing them unintendedly. I also rewrote the copying part, because sometimes things went wrong an folders where nested incorrectly.
For the future there should be a dedicated location for these additional resources that could be excluded from the repository and deployed to the server, but I have not been able to figure that out, because the modules expect their resources to be located in a specific path. The artistry for people more versatile than me would be to come up with a build-in but flexible system to manage resources of all types.
My aurelia.json (note this is also Typescript):
import * as gulp from 'gulp';
import transpile from './transpile';
import processMarkup from './process-markup';
import processCSS from './process-css';
import { build } from 'aurelia-cli';
import * as project from '../aurelia.json';
import * as fs from 'fs';
import * as readline from 'readline';
import * as os from 'os';
export default gulp.series(
copyAdditionalResources,
readProjectConfiguration,
gulp.parallel(
transpile,
processMarkup,
processCSS
),
writeBundles
);
function copyAdditionalResources(done){
readGitIgnore();
done();
}
function readGitIgnore() {
let lineReader = readline.createInterface({
input: fs.createReadStream('./.gitignore')
});
let gitignore: Array<String> = [];
lineReader.on('line', (line) => {
gitignore.push(line);
});
lineReader.on('close', (err) => {
copyFiles(gitignore);
})
}
function copyFiles(gitignore: Array<String>) {
let stream,
bundle = project.build.bundles.find(function (bundle) {
return bundle.name === "vendor-bundle.js";
});
// iterate over all dependencies specified in aurelia.json
for (let i = 0; i < bundle.dependencies.length; i++) {
let dependency = bundle.dependencies[i];
let collectedResources = [];
if (dependency.path && dependency.resources) {
// run over resources array of each dependency
for (let n = 0; n < dependency.resources.length; n++) {
let resource = dependency.resources[n];
let ext = resource.substr(resource.lastIndexOf('.') + 1);
// only copy resources that are not managed by aurelia-cli
if (ext !== 'js' && ext != 'css' && ext != 'html' && ext !== 'less' && ext != 'scss') {
collectedResources.push(resource);
dependency.resources.splice(n, 1);
n--;
}
}
if (collectedResources.length) {
if (gitignore.indexOf(dependency.name)< 0) {
console.log('Adding line to .gitignore:', dependency.name);
fs.appendFile('./.gitignore', os.EOL + dependency.name, (err) => { if (err) { console.log(err) } });
}
for (let m = 0; m < collectedResources.length; m++) {
let currentResource = collectedResources[m];
if (currentResource.charAt(0) != '/') {
currentResource = '/' + currentResource;
}
let path = dependency.path.replace("../", "./");
let sourceFile = path + currentResource;
let destPath = './' + dependency.name + currentResource.slice(0, currentResource.lastIndexOf('/'));
console.log('Copying resource', sourceFile, 'to', destPath);
// copy files
gulp.src(sourceFile)
.pipe(gulp.dest(destPath));
}
}
}
}
}
function readProjectConfiguration() {
return build.src(project);
}
function writeBundles() {
return build.dest();
}
The best way to handle CSS frameworks is usually to do the same thing you've always done before. Just add a link tag to the page. That's the way they are designed to be used and sometimes you need them loaded before the app anyway.
@EisenbergEffect I get your point for the specific case of a bulky CSS framework like bootstrap from which you will probably only use one per app, but I also think you're overlooking the actual problem. It's not really about how you include those resources in your app in the end. Whether you add a link, script, require or whatever tag to the page, or import it into your Javascript doesn't really matter. That's a question of personal taste. It's more about finding a comprehensible concept for the whole build, bundle and deployment process, copying files to correct locations and all those things. Of course, it's not a lot of work to care for some of the essential dependencies on your own, but it should be desired to automate these processes as much and as well as possible to avoid mistakes and increase productivity. In the most cases those dependencies are installed with a package manager from some kind of external repository anyway. This is the basis to treat them similar like you are already doing with Javascript dependencies. I don't get why I should copy them manually and probably break the whole app because of a wrong versioned path in some hidden place of the program. Not to forget, that for the case of a CSS framework, the Aurelia CLI docs actually make you believe that everything will work fine if you just add it to the aurelia.json file, which is simply not true. You must consider, that things that might be absolutely trivial for you as an renowned expert, might not be for beginners or even average web developers. Therefore I find those things should be weighted even heavier than new features for the framework itself. As far as I understand your philosophy and the philosophy of Aurelia as a platform has always been to take everyone on the boat, no matter of the level of experience.
P.S.: Don't get me wrong and please don't be offended. I know you're juggling many balls at once and I highly appreciate the work with Aurelia. Also, English is not my first language, so there might be a lack of sensitivity in some places ;) Your comment just read as if there was no interest to take care of these things at all, that's why I felt I had to write an answer.
Of course there is interest in addressing this. However, it's lower priority than other things on the list for the CLI, in part because a simple link tag will fix the problem and is much easier than the work we would have to do to solve this inside the CLI.
Thanks for the workaround @MannikJ Here is the ES6 version of MannikJ's fix.
import gulp from 'gulp';
import transpile from './transpile';
import processMarkup from './process-markup';
import processCSS from './process-css';
import { build } from 'aurelia-cli';
import project from '../aurelia.json';
import fs from 'fs';
import readline from 'readline';
import os from 'os';
export default gulp.series(
copyAdditionalResources,
readProjectConfiguration,
gulp.parallel(
transpile,
processMarkup,
processCSS
),
writeBundles
);
function copyAdditionalResources(done){
readGitIgnore();
done();
}
function readGitIgnore() {
let lineReader = readline.createInterface({
input: fs.createReadStream('./.gitignore')
});
let gitignore = [];
lineReader.on('line', (line) => {
gitignore.push(line);
});
lineReader.on('close', (err) => {
copyFiles(gitignore);
})
}
function copyFiles(gitignore) {
let stream,
bundle = project.build.bundles.find(function (bundle) {
return bundle.name === "vendor-bundle.js";
});
// iterate over all dependencies specified in aurelia.json
for (let i = 0; i < bundle.dependencies.length; i++) {
let dependency = bundle.dependencies[i];
let collectedResources = [];
if (dependency.path && dependency.resources) {
// run over resources array of each dependency
for (let n = 0; n < dependency.resources.length; n++) {
let resource = dependency.resources[n];
let ext = resource.substr(resource.lastIndexOf('.') + 1);
// only copy resources that are not managed by aurelia-cli
if (ext !== 'js' && ext != 'css' && ext != 'html' && ext !== 'less' && ext != 'scss') {
collectedResources.push(resource);
dependency.resources.splice(n, 1);
n--;
}
}
if (collectedResources.length) {
if (gitignore.indexOf(dependency.name)< 0) {
console.log('Adding line to .gitignore:', dependency.name);
fs.appendFile('./.gitignore', os.EOL + dependency.name, (err) => { if (err) { console.log(err) } });
}
for (let m = 0; m < collectedResources.length; m++) {
let currentResource = collectedResources[m];
if (currentResource.charAt(0) != '/') {
currentResource = '/' + currentResource;
}
let path = dependency.path.replace("../", "./");
let sourceFile = path + currentResource;
let destPath = './' + dependency.name + currentResource.slice(0, currentResource.lastIndexOf('/'));
console.log('Copying resource', sourceFile, 'to', destPath);
// copy files
gulp.src(sourceFile)
.pipe(gulp.dest(destPath));
}
}
}
}
}
function readProjectConfiguration() {
return build.src(project);
}
function writeBundles() {
return build.dest();
}
This code runs successfully with the fowling config in aurlia.json
...
{
"name": "font-awesome",
"main":"",
"path": "../node_modules/font-awesome",
"resources": [
"css/font-awesome.css",
"/fonts/fontawesome-webfont.woff2",
"/fonts/FontAwesome.otf",
"/fonts/fontawesome-webfont.eot",
"/fonts/fontawesome-webfont.svg",
"/fonts/fontawesome-webfont.ttf"
]
}
...
This issue can now be solved by adding a copy instruction in the aurelia.json.
aurelia.json - valid if the project was created by aurelia-cli 0.25.0 or greater
"bundles": [ ... ],
"copyFiles": {
"node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2": "bootstrap/fonts"
"node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.woff": "bootstrap/fonts",
"node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf": "bootstrap/fonts"
}
If the project was created by an older CLI version, you will have to create the copy task inside the tasks folder -> https://github.com/aurelia/cli/blob/master/lib/resources/tasks/copy-files.js. After that, call the copy task in the build.js/ts task -> https://github.com/aurelia/cli/blob/master/lib/resources/tasks/build.js#L15
@EisenbergEffect I think you can close this issue.
I'm using 0.26.1. It already has a copy-files.ts that is called in build.ts. How do I make it work in this case?
@pbrickell Add the following lines in aurelia.json, after the bundles
property:`
"bundles": [ ... ],
"copyFiles": {
"node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2": "bootstrap/fonts"
"node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.woff": "bootstrap/fonts",
"node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf": "bootstrap/fonts"
}
Run the application again.
@fabioluz That didn't work for me. The following did though
"bundles": [ ... ], "copyFiles": { "./node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2": "./fonts", "./node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.woff": "./fonts", "./node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf": "./fonts" }
@pbrickell Are you sure the fonts
folder hasn't been created? I tried here in a brand new project and it worked. Also, why are you using ./fonts
? Shouldn't it be ./bootstrap/fonts
?
@fabioluz
With your original I ended up with a bootstrap/fonts folder at the same level as src but in the browser I was seeing 401 errors for http://ei16.ei.lan:9000/fonts/glyphicons-halflings-regular.* Seeing this I changed my target to match, hence "./fonts". It then works.
I think this may stem from how I am handling my bootstrap.css. To get the bootstrap.css loaded I have copied it to src/bootstrap.scss and required it with <require from="./bootstrap.css"></require>
I don't know if that is idiomatic. It was the only way I get the css loaded at all.
@pbrickell Try to load bootstrap as described in the http://aurelia.io/hub.html#/doc/article/aurelia/framework/latest/the-aurelia-cli/10. I'm pretty sure it will work :)
I get 404 for that url.
I found the item in the docs. That's exactly what I have in my aurelia.json
This conversation may be relevant https://gitter.im/aurelia/Discuss?at=58c01140de504908226068e7
@pbrickell ping me on gitter channel. I can help you better there.
A final note, Thanks to Fabio for all the help.
Turns out bootstrap requires jquery and for jquery to be appear before bootstrap in aurelia.json.
After fixing that everything works perfectly according Fabio's here https://github.com/aurelia/cli/issues/248#issuecomment-285447958
I'm submitting a bug report
Please tell us about your environment:
Node Version: 6.3.0
NPM Version: 3.10.5
Current behavior: Adding bootstrap's glyphicons file(s) causes the CLI to fail while bundling.
This configuration for bootstrap fails:
Here is the error messaged displayed: