I'm wondering how to embed these frameworks in my app.
Short answer:
Use aliases?
If it can be automated, I don't see any harm in copying.
Long answer:
Listed below are some of the tools and techniques I use.
Bower is a package manager for the web. It offers a generic, unopinionated solution to the problem of front-end package management, while exposing the package dependency model via an API that can be consumed by a more opinionated build stack. There are no system wide dependencies, no dependencies are shared between different apps, and the dependency tree is flat.
Grunt: The JavaScript Task Runner.
Install Bower packages. Smartly.
... Also worth mentioning:
Submodules allow you to keep a Git repository as a subdirectory of another Git repository.
Real world example ...
Within my Gruntfile.js
, I have a bower
task:
bower : {
install : {
options : {
targetDir : './files/plugins', // A directory where you want to keep your Bower packages.
cleanup : true, // Will clean target and bower directories.
layout : 'byComponent', // Folder structure type.
verbose : true, // Debug output.
},
},
},
... the above requires a bower.json
(next to the Gruntfile
):
{
"name": "simple-bower",
"version": "0.0.0",
"dependencies": {
"normalize-css": "2.1.3",
"foo": "https://github.com/baz/foo.git"
},
"exportsOverride": {
"foo": {
"scss": "foo/scss/",
"css": "foo/*.css"
}
}
}
When the above bower
task is run, I get a folder structure that looks like (organized by "component"):
plugins/
normalize-css/
(component)
foo/
(component)
css/
scss/
foo.scss
partials/
_variables.scss
_functions.scss
_mixins.scss
_other.scss
Note: Using exportsOverride
option, I was able to "grab" resources other than the main
resource that was specified via the endpoint's (foo
, in this case) bower.json
.
Based on the above setup, I now have a folder called plugins/
(like, I assume, your vendor/
folder) and I can now point my Gruntfile tasks at said directory and/or files.
But if the library has images or less/sass/stylus/css files attached I'm always struggling how to handle them ...
Alias technique #1:
Question: Based on the above Bower install, how does one include normalize.css
as a SASS partial?
One solution is to create an alias (cwd
= my project's scss/
folder):
$ ln -s ../plugins/normalize-css/normalize.css _normalize.scss
From there, I can treat the alias as an SCSS partial and @import
into my scss
files as I please.
Alias technique #2:
Question: Based on the above Bower install, how does one include foo
's scss
partials?
Assuming foo.scss
includes all of the partials, it's not going to work as a direct alias because the @imports
are relative.
Why not alias the whole folder then?
$ ln -s ../plugins/foo/scss ./foo
Now I can easily include the 3rd party dependency's scss
partials (or just foo.scss
) in my project's build process without having to do much leg work.
Copying technique ...
Copy all third party assets into my folder structure?
I see no problems with this approach either. Optimally, you'd automate the copy with a task like:
grunt-contrib-copy
One approach could be a copy
target that runs via an init
task which would copy source files to the locations you specify in your build directory. From there, you'd run your other/process tasks to generate/build/copy the development/production files like you would normally.
Here's the copy task from one of my latest projects:
copy : {
// Copies `normalize.css` from `plugins/` into the root-level `/demo/` folder:
dev : {
filter : 'isFile',
expand : true,
cwd : './files/plugins/',
src : '**',
dest : '../demo/',
flatten: true,
},
// Copies source `scss` files into my distribution folder:
prod : {
filter : 'isFile',
expand : true,
cwd : './files/styles/',
src : [
'**/*',
'!demo.scss',
],
dest : '../<%= pkg.name %>/scss/',
},
// Copies images into the root-level `/demo/` folder:
all : {
expand : true,
cwd : './files/images/',
src : '**',
dest : '../demo/',
},
},
Direct linking technique?
Depending on your needs, there's not much stopping you from relatively linking to 3rd party assets in your vendor/
folder. I'd say if direct linking doesn't work (due to some sort of relative import or something), then the above two aliasing options are good alternatives. Personally, I find that aliasing is nice because it keeps my path strings clean.
Minimize and/or uglify?
Should I include third party assets (stylesheets, javascript) in my own files and minimize them together?
I say, for production environment, definitely yes.
My personal approach is to have two build processes, one for "dev" and one for "prod". The former links to source files whereas the latter links to the min/uglified files.
I've given a basic outline of my build process here:
Have Grunt generate index.html for different setups
For me, the goal is to have a "dev" build for development (where I can easily use to hunt for bugs) and a "prod" build for production (keeping in mind, that new bugs may get introduced when the source files have been combined/minified/uglified).
Grunt tasks I use on a regular basis to generate my min/ugly files:
- grunt-contrib-jshint
- grunt-contrib-uglify
- grunt-contrib-sass
- grunt-contrib-less
- grunt-contrib-htmlmin
Note: I always strive to include un-minified/uglified versions of 3rd party code in my builds; if I decide to use already compressed files, I skip the compression step (for these files) in my build process and just do the file concatenation instead.
3rd party uses different preprocessor/other?
If I use stylus and the framework uses sass I have to install a lot of further dependencies.
That's definitely a predicament. A few solutions I can think of:
Just prepare yourself for these eventualities. It's usually not too hard to install packages (homebrew helps), so once you're system is setup it should be easier the next time you encounter this type of situation. From there, it shouldn't be hard to find a Grunt task to incorporate the source files into your build. A lot of times I'll use a temp/
folder to store "inbetween" build files, and then I'll use other tasks to combine/minify/uglify said code with other code (for example, let's say I want to combine the sass
/less
generated files ... just slap them into /temp
and combine them at some point during my build process).
Find a version of that framework that's using the tools you prefer. For example, Twitter's Bootstrap uses less
; well, luckily, there happens to be a sass
version. Problem solved (hopefully). :)
If it exists, and if you can get away with it, use the "generated" version of the framework. For example, I try to include a generated source file for every project I create ... I dunno about you, but I like having the option of viewing/using an already generated version of a plugin, especially if said plugin can work out-of-the-box in my project.
Other? I'm currently out of ideas on this one.
With all that said, I am by no means an authority on this topic ... The above is just what works for me. My personal preference for when it comes to this stuff is to strike a balance between simple and complex.