I would like to be able to use compass to pre-process my SASS into CSS in an ember-cli project.
Doing this with broccoli-sass is trivial, as bower install broccoli-sass is all that is required, as the support for it is already built in.
Doing this with broccoli-compass however, has turned out to be rather tricky... how?
Details:
This question has been asked previously, for ember-cli v0.0.23;
and it's answer appears to be outdated -
The main issue appears to be that ember-cli abstracts a lot of the stuff inBrocfile.js, and puts it into another file, preprocessor.js, using a Registry, and thus the solution would be different, to a standard looking Brocfile.js
Update:
This question has been asnwered by #saygun, and the solution allows one to use broccoli-compass to compile SCSS --> CSS. However there are a couple of caveats:
Minor issue: The existing minifyCss preprocessor in meber-cli will not work. You will need to configure compass to minify its own CSS.
Major issue: If the SCSS files reference images, the generated CSS files contain links to images where the paths are within the temporary tree folders created by Broccoli. I am not sure how to work around this, and have asked a follow up question: How to generate image sprites in ember-cli using compass?
I have recently published ember-cli-compass-compiler which is a ember-cli addon for newer ember-cli apps(>= 0.0.37).
Just install using the command:
npm install --save-dev ember-cli-compass-compiler
No other configuration is needed, it converts app/styles/appname.scss to appname.css correctly. As the name indicates, it allows you to use Compass in addition to sass as well.
you need to install broccoli-compass:
npm install broccoli-compass --save-dev
and you need to install ruby gem sass-css-importer:
gem install sass-css-importer --pre
then in your brocfile do this:
var compileCompass = require('broccoli-compass');
app.styles = function() {
var vendor = this._processedVendorTree();
var styles = pickFiles(this.trees.styles, {
srcDir: '/',
destDir: '/app/styles'
});
var stylesAndVendor = mergeTrees([vendor, styles, 'public']);
return compileCompass(stylesAndVendor, 'app' + '/styles/app.scss', {
outputStyle: 'expanded',
require: 'sass-css-importer',
sassDir: 'app' + '/styles',
imagesDir: 'images',
fontsDir: 'fonts',
cssDir: '/assets'
});
};
Related
I wanted to start a simple hello world app for Angular.
When I followed the instructions in the official quickstart the installation created 32,000 files in my project.
I figured this is some mistake or I missed something, so I decided to use angular-cli, but after setting up the project I counted 41,000 files.
Where did I go wrong? Am I missing something really really obvious?
There is nothing wrong with your configuration.
Angular (since version 2.0) uses npm modules and dependencies for development. That's the sole reason you are seeing such a huge number of files.
A basic setup of Angular contains transpiler, typings dependencies which are essential for development purposes only.
Once you are done with development, all you will need to do is to bundle this application.
After bundling your application, there will be only one bundle.js file which you can then deploy on your server.
'transpiler' is just a compiler, thanks #omninonsense for adding that.
Typical Angular2 Project
NPM Package Files (Development) Real World Files (Deployment)
#angular 3,236 1
rxJS 1,349 1*
core-js 1,341 2
typings 1,488 0
gulp 1,218 0
gulp-typescript 1,243 0
lite-server 5,654 0
systemjs-builder 6,470 0
__________________________________________________________________
Total 21,999 3
*: bundled with #angular
[ see this for bundling process ⇗ ]
There is nothing wrong with your development configuration.
Something wrong with your production configuration.
When you develop a "Angular 2 Project" or "Any Project Which is based on JS" you can use all files, you can try all files, you can import all files. But if you want to serve this project you need to COMBINE all structured files and get rid of useless files.
There are a lot of options for combine these files together:
YUI Compressor
Google Closure Compiler
For server side (I think it is best) GULP
As several people already mentioned: All files in your node_modules directory (NPM location for packages) are part of your project dependencies (So-called direct dependencies). As an addition to that, your dependencies can also have their own dependencies and so on, etc. (So-called transitive dependencies). Several ten thousand files are nothing special.
Because you are only allowed to upload 10'000 files (See comments), I would go with a bundler engine. This engine will bundle all your JavaScript, CSS, HTML, etc. and create a single bundle (or more if you specify them). Your index.html will load this bundle and that's it.
I am a fan of webpack, so my webpack solution will create an application bundle and a vendor bundle (For the full working application see here https://github.com/swaechter/project-collection/tree/master/web-angular2-example):
index.html
<!DOCTYPE html>
<html>
<head>
<base href="/">
<title>Webcms</title>
</head>
<body>
<webcms-application>Applikation wird geladen, bitte warten...</webcms-application>
<script type="text/javascript" src="vendor.bundle.js"></script>
<script type="text/javascript" src="main.bundle.js"></script>
</body>
</html>
webpack.config.js
var webpack = require("webpack");
var path = require('path');
var ProvidePlugin = require('webpack/lib/ProvidePlugin');
var CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
var UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
/*
* Configuration
*/
module.exports = {
devtool: 'source-map',
debug: true,
entry: {
'main': './app/main.ts'
},
// Bundle configuration
output: {
path: root('dist'),
filename: '[name].bundle.js',
sourceMapFilename: '[name].map',
chunkFilename: '[id].chunk.js'
},
// Include configuration
resolve: {
extensions: ['', '.ts', '.js', '.css', '.html']
},
// Module configuration
module: {
preLoaders: [
// Lint all TypeScript files
{test: /\.ts$/, loader: 'tslint-loader'}
],
loaders: [
// Include all TypeScript files
{test: /\.ts$/, loader: 'ts-loader'},
// Include all HTML files
{test: /\.html$/, loader: 'raw-loader'},
// Include all CSS files
{test: /\.css$/, loader: 'raw-loader'},
]
},
// Plugin configuration
plugins: [
// Bundle all third party libraries
new CommonsChunkPlugin({name: 'vendor', filename: 'vendor.bundle.js', minChunks: Infinity}),
// Uglify all bundles
new UglifyJsPlugin({compress: {warnings: false}}),
],
// Linter configuration
tslint: {
emitErrors: false,
failOnHint: false
}
};
// Helper functions
function root(args) {
args = Array.prototype.slice.call(arguments, 0);
return path.join.apply(path, [__dirname].concat(args));
}
Advantages:
Full build line (TS linting, compiling, minification, etc.)
3 files for deployment --> Only a few Http requests
Disadvantages:
Higher build time
Not the best solution for Http 2 projects (See disclaimer)
Disclaimer: This is a good solution for Http 1.*, because it minimizes the overhead for each Http request. You only have a request for your index.html and each bundle - but not for 100 - 200 files. At the moment, this is the way to go.
Http 2, on the other hand, tries to minimize the Http overhead, so it's based on a stream protocol. This stream is able to communicate in both direction (Client <--> Server) and as a reason of that, a more intelligent resource loading is possible (You only load the required files). The stream eliminates much of the Http overhead (Less Http round trips).
But it's the same as with IPv6: It will take a few years until people will really use Http 2
You need to ensure that you're just deploying the dist (short for distributable) folder from your project generated by the Angular CLI. This allows the tool to take your source code and it's dependencies and only give you what you need in order to run your application.
That being said there is/was an issue with the Angular CLI in regards to production builds via `ng build --prod
Yesterday (August 2, 2016) a release was done which switched the build mechanism from broccoli + systemjs to webpack which successfully handles production builds.
Based upon these steps:
ng new test-project
ng build --prod
I am seeing a dist folder size of 1.1 MB across the 14 files listed here:
./app/index.js
./app/size-check.component.css
./app/size-check.component.html
./favicon.ico
./index.html
./main.js
./system-config.js
./tsconfig.json
./vendor/es6-shim/es6-shim.js
./vendor/reflect-metadata/Reflect.js
./vendor/systemjs/dist/system.src.js
./vendor/zone.js/dist/zone.js
Note Currently to install the webpack version of the angular cli, you must run... npm install angular-cli#webpack -g
Creating a new project with angular cli recently and the node_modules folder was 270 mb, so yes this is normal but I'm sure most new devs to the angular world question this and is valid. For a simple new project it would make sense to pare the dependencies down maybe a bit;) Not knowing what all the packages depend on can be a bit unnerving especially to new devs trying the cli out for the first time. Add to the fact most basic tutorials don't discuss the deployment settings to get the exported files only needed. I don't believe even the tutorial offered on the angular official website talks about how to deploy the simple project.
Angular itself has lots of dependencies, and the beta version of CLI downloads four times more files.
This is how to create a simple project will less files ("only" 10K files)
https://yakovfain.com/2016/05/06/starting-an-angular-2-rc-1-project/
Seems like nobody have mentioned Ahead-of-Time Compilation as described here: https://angular.io/docs/ts/latest/cookbook/aot-compiler.html
My experience with Angular so far is that AoT creates the smallest builds with almost no loading time. And most important as the question here is about - you only need to ship a few files to production.
This seems to be because the Angular compiler will not be shipped with the production builds as the templates are compiled "Ahead of Time". It's also very cool to see your HTML template markup transformed to javascript instructions that would be very hard to reverse engineer into the original HTML.
I've made a simple video where I demonstrate download size, number of files etc. for an Angular app in dev vs AoT build - which you can see here:
https://youtu.be/ZoZDCgQwnmQ
You'll find the source code for the demo here:
https://github.com/fintechneo/angular2-templates
And - as all the others said here - there's nothing wrong when there are many files in your development environment. That's how it is with all the dependencies that comes with Angular, and many other modern frameworks. But the difference here is that when shipping to production you should be able to pack it into a few files. Also you don't want all of these dependency files in your git repository.
This is actually not Angular specific, it happens with almost any project that uses the NodeJs / npm ecosystem for its tooling.
Those project are inside your node_modules folders, and are the transititve dependencies that your direct dependencies need to run.
In the node ecosystem modules are usually small, meaning that instead of developing things ourselves we tend to import most of what we need under the form of a module. This can include such small things like the famous left-pad function, why write it ourselves if not as an exercise ?
So having a lot of files its actually a good thing, it means everything is very modular and module authors frequently reused other modules. This ease of modularity is probably one of the main reasons why the node ecosystem grew so fast.
In principle this should not cause any issue, but it seems you run into a google app engine file count limit. In that I case I suggest to not upload node_modules to app engine.
instead build the application locally and upload to google app engine only the bundled filesn but don't to the build in app engine itself.
If you are using angular cli's newer version use ng build --prod
It will create dist folder which have less files and speed of project will increased.
Also for testing in local with best performance of angular cli you can use ng serve --prod
if you use Angular CLI you can always use --minimal flag when you create a project
ng new name --minimal
I've just run it with the flag and it creates 24 600 files and ng build --prod produces 212 KB dist folder
So if you don't need water fountains in your project or just want to quickly test something out this I think is pretty useful
If your file system supports symbolic links, then you can at least relegate all of these files to a hidden folder -- so that a smart tool like tree won't display them by default.
mv node_modules .blergyblerp && ln -s .blergyblerp node_modules
Using a hidden folder for this may also encourage the understanding that these are build-related intermediate files that don't need to be saved to revision control -- or used directly in your deployment.
There is nothing wrong. These are all the node dependencies that you have mentioned in the package.json.
Just be careful if you have download some of the git hub project, it might have lot of other dependencies that are not actually require for angular 2 first hello world app :)
make sure you have angular dependencies
-rxjs
-gulp
-typescript
-tslint
-docker
There is nothing wrong with your development configuration.
if you use Angular CLI you can always use --minimal flag when you create a project
ng new name --minimal
I'm finding myself in an Ember-based app and are having a little trouble understanding how I should add the chai-as-promised helper library to it. I'm running this version:
$ ember --version
version: 2.4.2
node: 5.8.0
os: darwin x64
I started by installing via npm i chai-as-promised --save-dev. The library was then importable via Node. Then I have tried adding it to the ember-cli-build.js file using two different approaches:
As a file via .import(), after creating the EmberApp:
module.exports = function(defaults) {
var app = new EmberApp([...]);
app.import('./node_modules/chai-as-promised/lib/chai-as-promised.js');
Via EmberApp.toTree() to chai-as-promised's top directory:
return app.toTree('./node_modules/ember-cli-blueprint-test-helpers/');
And descending into the lib/ subdirectory of chai-as-promised:
return app.toTree('./node_modules/chai-as-promised/lib');
I also tried installing via Bower and changing the above node_modules/ based paths to bower_components ones, but still with the same result.
Am I importing it wrong? Or is there somewhere else I should import?
You need to tell ember-cli to add it to the test tree like this:
app.import("bower_components/chai-as-promised/lib/chai-as-promised.js",
{ type: 'test' });
otherwise it isn't available in the test suite but in the app. I got this to work in combination with ember-cli-mocha.
You can see how it works here: https://github.com/albertjan/ember-cli-chai-as-promised
When installing the Aurelia navigation skeleton app it is far to overwhelming with all the 3rd party modules and ready-made scripts it uses. For me who have a good picture of what most of it is in theory, have a hard time learning when I can't do it one step at a time. For this reason I would like to set up a minimal Aurelia project by myself and then add complexity to it as I go along.
Main question: Which steps are necessary to set up a simple Aurelia project?
Assumptions:
I already have a Node server backend that can serve files.
I want to use ES6/7 (Babel).
I want to use system.js for module loading.
No unit or e2e tests, no styles, no docs.
As few node and jspm modules as possible.
Please do also explain a little on each step and describe what the necessary Aurelia files is and does.
I would be very thankful for any help :)
Install the jspm command line interface. jspm is a package manager for client-side dependencies. Read up on it... it's great.
npm install jspm -g
Create a folder for the project.
mkdir minimal
cd minimal
Initialize jspm client package management...
Accept all the defaults EXCEPT use the Babel transpiler option (vs Traceur)
jspm init
Enable all the fancy cutting edge babel goodness by adding the following line to the babelOptions in your config.js (jspm init created the config.js file):
System.config({
defaultJSExtensions: true,
transpiler: "babel",
babelOptions: {
"stage": 0, <------ add this to turn on the hotness
"optional": [
"runtime"
]
},
...
Install Aurelia
jspm install aurelia-framework
jspm install aurelia-bootstrapper
Create an index.html that uses the SystemJS loader (jspm's module loader counter-part) to bootstrap Aurelia.
<!doctype html>
<html>
<head>
<title>Aurelia</title>
</head>
<body aurelia-app>
<h1>Loading...</h1>
<script src="jspm_packages/system.js"></script>
<script src="config.js"></script>
<script>
System.import('aurelia-bootstrapper');
</script>
</body>
</html>
When Aurelia bootstraps it's going to look for a default view and view-model... create them:
app.js
export class App {
message = 'hello world';
}
app.html
<template>
${message}
</template>
Install gulp and browser-sync to serve the files:
npm install gulp
npm install --save-dev browser-sync
Add a gulpfile.js
var gulp = require('gulp');
var browserSync = require('browser-sync');
// this task utilizes the browsersync plugin
// to create a dev server instance
// at http://localhost:9000
gulp.task('serve', function(done) {
browserSync({
open: false,
port: 9000,
server: {
baseDir: ['.'],
middleware: function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
next();
}
}
}, done);
});
Start the webserver.
gulp serve
Browse to the app:
http://localhost:9000
Done.
Here's what your project structure will look like when you're finished:
Note: this is just a quick and dirty setup. It's not necessarily the recommended folder structure, and the loader is using babel to transpile the js files on the fly. You'll want to fine tune this to your needs. The intent here is to show you how to get up and running in the fewest steps possible.
Check the article https://github.com/aurelia-guides/aurelia-guides.md-articles/blob/master/Building-Skeleton-Navigation-From-Scratch.md written specifically to ease the introduction to Aurelia.
I created a repo (up to date as of April 2017) that includes the absolute barebones necessary items to run Aurelia at https://github.com/nathanchase/super-minimal-aurelia
It's an ES6-based Aurelia implementation (rather than Typescript), it incorporates
code-splitting by routes (using the latest syntax in Aurelia's router to designate chunk creation according to files under a route), and it works in all evergreen browsers AND Internet Explorer 11, 10, and 9 thanks to a few necessary included polyfills.
The Aurelia documentation has a really nice chapter that explains what each part of a simple application does, one step at a time. It is probably a good start that do not overwhelm you with dependencies like Bootstrap and similar.
Also note that there is now a CLI interface to Aurelia that simplifies setting up a project from scratch.
I would definitely use the aurelia-cli for this.
Do the following:
npm install -g aurelia-cli
Then to start a new project do:
au new project-name
to run your project do:
au run --watch
I really feel the aurelia-cli "is the future" for aurelia!
I'm working with a Java Play project and still want to use the scala conversion of HTML file. Thus, I did the following
Download aurelia-core available via the basic aurelia project, which is linked from the quickstart tutorial
Fetch SystemJS using WebJars: "org.webjars.npm" % "systemjs" % "0.19.38"
Since systemjs-plugin-babel is currently unavailable as webjar, I ran npm install systemjs-plugin-babel and copied the fetched files to the assets directroy
The HTML code is like this:
<div aurelia-app="/assets/aurelia/main">
...loading data...
</div>
<script src="#routes.Assets.versioned("lib/systemjs/dist/system.js")" type="text/javascript"></script>
<script src="#routes.Assets.versioned("javascripts/aurelia-core.min.js")" type="text/javascript"></script>
<script>
System.config({
map: {
'plugin-babel': '#routes.Assets.versioned("javascripts/systemjs-plugin-babel/plugin-babel.js")',
'systemjs-babel-build': '#routes.Assets.versioned("javascripts/systemjs-plugin-babel/systemjs-babel-browser.js")'
},
transpiler: 'plugin-babel',
packages: {
'/assets/aurelia': {
defaultExtension: 'js'
}
}
});
System.import('aurelia-bootstrapper');
</script>
Use main.js etc. from the quickstart tutorial
I use grunt-urequire plugin to compile my project-1's modules into single file (let's call it project-1.js). Config looks like this:
urequire: {
umd: {
template: 'UMD',
path: 'src',
dstPath: 'dist/umd'
},
dev: {
template: 'combined',
path: 'src',
main: 'Main',
dstPath: 'dist/<%= pkg.name %>-<%= pkg.version %>.js'
},
min: {
derive: ['dev', '_defaults'],
dstPath: 'dist/<%= pkg.name %>-<%= pkg.version %>.min.js',
optimize: 'uglify2'
},
_defaults: {
useStrict: true,
noConflict: true,
bundle: {
dependencies: {
exports: {
root: {
'Main': 'Project1'
}
}
}
}
}
}
Project-1 depends on project-2 which is also managed by grunt-urequire. In package.json:
"devDependencies": {
"project2": "^0.1",
...
}
Now I want to embed project-2 dependency into project-1 on build so that one could just do
<script src="project-1.js"></script>
in browser and don't include project-2 manually.
I know browserify supports this, but can I do it using urequire?
uRequire doesn't embed external dependencies (like jquery, underscore etc) into the combined.js file, unlike browserify which is the only option (as far as I know) and its also the default behavior of r.js.
This is partly intentional, cause its better to load (either using RequireJS or <script/>) these external libraries from a CDN: your user's browser might have already cached them last time it loaded your app (or someone else's app). And next time your myApp.js changes, it will download only that and not a monolithic bundle that contains all the same external libs all over again.
uRequire actually goes a long way to make sure these are loaded externally, whether on nodejs (using plain node's require) or the browser, using AMD or the exported global properties (like window.$, window._ or whatever the external library is mapped to).
I would imagine you can easily override this behavior: just place project-2.js whenever you build it onto the source folder of project-1, and just use it in project-1 as a normal dependency.
Alternatively you can again build/convert all project-2 files as AMD (not combined) into the source folder of project-1 and use them as being part of it.
Finally, you could just symlink the project-2 source into project-1, its supported on unix/linux for decades and also on Windows 7 onwards. Then uRequire will convert the sources from both projects only once and build as a single output.
Ideally I would like to have virtual sources (see https://github.com/anodynos/uRequire/issues/40) so you can leave both projects separate (i.e not build one into the other), but build both as one output.
If you want to version the 2 projects on the same git repository because they are updated together and have the same release lifecycle, you can have a build script in 2 parts:
First part is to compile project2 (project2/src)
Second part is to compile project1 (project1/src)
During the compilation of project2, you can copy the distributed JS of project2 into project1/src so that it is automatically.
If you have different release lifecycles, you can use some grunt tool to download the dependency from a CDN / NPM and put it into the project1/src folder before packaging project 1
This is somehow what is done by Browserify by using NPM, but it would probably be the same with Bower, components or custom JS code to download the dependencies. I would recommend using a tool like NPM however because it also download transitive dependencies (if one day project2 introduces a dependency, you won't have to touch project1 build...)
Finally, I don't know uRequire but maybe you could be inspired by this project, which embeds dependencies in the packaged version (eventie)
In my project I would like to use jquery-mobile via bower.
Before I can use it I have to run npm install and grunt subsequently inside of bower_components/jquery-mobile before I can use the minified .js and .css files.
This is quite tedious and if I had to do this for every library that I use, I guess I would fallback to just downlading the files and add them to my project.
So is there a more elegant way to get to those "final" files via bower dependency?
My bower.json
"dependencies": {
...
"jquery-mobile": "latest",
}
The fact of having to run npm/grunt process (or not) is up to each author. In the case of jQuery Mobile, probably some external user has registered it without noticing that it needs to run Grunt tasks; Bower unfortunately allows everyone to register packages (is that bad or good? :S).
Also, there may exist some Grunt task to install bower dependencies and run their Grunt tasks aswell; if there aren't, it's not too complicated to create one.
Anyway, as it seems that you're in a "hurry" for those final, compiled files, there is jquery-mobile-bower, which has been created and registered into Bower a few hours ago.
bower install jquery-mobile-bower
Let's just hope that this gets maintained and up-to-date.
Just so you're aware, there is an official jQuery mobile Bower package available. It can be installed via:
bower install jquery-mobile
Its GitHub endpoint can be found here.
I'm not sure if my solution is optimal, but I removed jquery-mobile from bower.json and I'm installing and building it with Grunt, using grunt-contrib-clean, grunt-git and grunt-run plugins. I came up with this, because I don't want to use jquery-mobile-bower, because it's an unofficial repo.
Here's an example Gruntfile.js:
module.exports = function (grunt) {
grunt.initConfig({
clean: {
jquerymobile: 'bower_components/jquery-mobile'
},
gitclone: {
jquerymobile: {
options: {
repository: 'https://github.com/jquery/jquery-mobile.git',
branch: 'master',
directory: 'bower_components/jquery-mobile'
}
}
},
run: {
options: {
cwd: "bower_components/jquery-mobile"
},
jquerymobile_npm_install: {
cmd: "npm",
args: [
'install'
]
},
jquerymobile_grunt: {
cmd: "grunt"
}
}
});
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-git');
grunt.loadNpmTasks('grunt-run');
grunt.registerTask('default', [
'clean',
'gitclone',
'run'
]);
};
More details can be found here https://github.com/jquery/jquery-mobile/issues/7554