Gulp: Splitting Files Into Separate Locations - coffeescript

I'd like to separate my JavaScript files from my Coffee-Script files!
This is my current file structure:
engine
world
behaviour.coffee
behaviour.js
character
behaviour.coffee
behaviour.js
engine.coffee
engine.js
This is the structure I would prefer:
src
engine
world
behaviour.coffee
character
behaviour.coffee
engine.coffee
and:
dest
engine
world
behaviour.js
character
behaviour.js
engine.js
my actual gulp file looks like this:
gulp = require 'gulp'
coffee = require 'gulp-coffee'
gulp.task 'all-coffee-files', ->
gulp.src './**/*.coffee'
.pipe coffee()
.pipe gulp.dest (file) ->
file.base
gulp.task 'watch', ->
gulp.watch './**/*.coffee', ['all-coffee-files']
What edits do I have to make in order to achieve this splitting?
Thank you very much!

Not really familiar with coffescript syntax, but the following should work:
gulp = require 'gulp'
coffee = require 'gulp-coffee'
gulp.task 'all-coffee-files', ->
gulp.src './src/**/*.coffee'
.pipe coffee()
.pipe gulp.dest('./dest/')
gulp.task 'watch', ->
gulp.watch './src/**/*.coffee', ['all-coffee-files']
This sources everything in ./src/ and places the resulting .js files in ./dest/, while keeping the directory structure intact.

Related

Create a zip with no root directory with universal sbt-native-packager

I use universal sbt-native-packager to generate a zip file distribution.
sbt universal:packageBin
The generated zip file, once extracted, contains everything inside a main directory named as my zip file:
unzip my-project-0.0.1.zip
my-project-0.0.1/bin
my-project-0.0.1/lib
my-project-0.0.1/conf
...
How can I create a zip that has no root folder, so that when extracted it will have a structure like that?
bin
lib
conf
Thanks
I'm not confident enough with sbt and scala to submit a pull request.
bash scripting has to be excluded right now, so my current (and ugly) solution is this one:
packageBin in Universal := {
val originalFileName = (packageBin in Universal).value
val (base, ext) = originalFileName.baseAndExt
val newFileName = file(originalFileName.getParent) / (base + "_dist." + ext)
val extractedFiles = IO.unzip(originalFileName,file(originalFileName.getParent))
val mappings: Set[(File, String)] = extractedFiles.map( f => (f, f.getAbsolutePath.substring(originalFileName.getParent.size + base.size + 2)))
val binFiles = mappings.filter{ case (file, path) => path.startsWith("bin/")}
for (f <- binFiles) f._1.setExecutable(true)
ZipHelper.zip(mappings,newFileName)
IO.move(newFileName, originalFileName)
IO.delete(file(originalFileName.getParent + "/" + originalFileName.base))
originalFileName
}
The solution proposed on github seems to be way nicer than mine even tough it doesn't work for me:
https://github.com/sbt/sbt-native-packager/issues/276
Unfortunately it looks like the name of that top-level directory is fixed to be the same as the name of the distributable zip (check out line 24 of the ZipHelper source on GitHub).
So unless you feel like making it configurable and submitting a pull request, it might just be easier to modify the resulting zip on the command line (assuming some flavour of UNIX):
unzip my-project-0.0.1.zip && cd my-project-0.0.1 && zip -r ../new.zip * && cd -
This will create new.zip alongside the existing zipfile - you could then mv it over the top if you like.

Browserify a mix of coffeescript and livescript files

I have a main coffee file and a mix of other coffee and livescript files.
# main.coffee
require 'LiveScript'
one = require './one.coffee'
two = require './two.ls'
console.log one.fun(), two.fun()
# one.coffee
module.exports.fun = -> 1
# two.ls
module.exports.fun = -> 2
I can run
coffee main.coffee
But trying to run
browserify -t coffeeify main.coffee
Gives an error:
module.exports.fun = -> 2
^
ParseError: Unexpected token >
The only workaround I see is to compile ls files to js first. Is there a simpler, direct way to mix ls and coffee files?
require 'LiveScript' is only sufficient for Node.js. Browserify does not support require.extensions, and is trying to parse the LiveScript as JavaScript.
You need a transform for LiveScript as well, for example Liveify.
You might try Webpack. With proper loaders, e.g. livescript-loader, coffee-loader and others, you can compose your program with different js flavors.

Concatenating and minifying RequireJS with Grunt

I have a project written in CoffeeScript that uses AngularJS. My vendor dependancies are installed using Bower and my file structure is like this:
- assets
- js
- app
- model
- *.coffee
- factory
- *.coffee
...
- app.coffee
- config.coffee
- routes.cofeee
- vendor
- angular
- lodash
...
- dist
What I'm trying to do is the following:
I'm trying to work out how I can use RequireJS's r.js to optimise my app files so that I essentially get a concatenated file all ordered nice (so vendor dependancies, my config and routes, and they my app files).
Integrate this into my Grunt file.
I've tried using the r.js optimiser but maybe I've being too silly as all it seems to do is copy my app files (minus the vendor dependancies) into the dist folder; it does, however, manage to optimise the coffee generated js files.
Has anyone got any experience with this?
I figured it out: r.js works by reading your mainConfigFile and any modules you name within your configuration, the important note here is that r.js only looks at the first require/define within your named modules and goes off to seek them; so, for example, I had one named module called app:
require ['config'], (cfg) ->
require ['angular'], (A) ->
A.module cfg.ngApp, []
require ['routes'], () ->
require [
'factory/a-factory',
'service/a-service',
'controller/a-controller'
], () ->
A.bootstrap document, [cfg.ngApp]
The problem here was that r.js never got past the first require statement and thus the concatenation wasn't working. When I changed this to, say (my app.coffee):
require ['config'], (cfg) ->
require ['angular'], (A) ->
A.module cfg.ngApp, []
require ['bootstrap'], (bootstrap) ->
bootstrap()
And my bootstrap.coffee:
define [
'config',
'angular',
'routes',
'factory/a-factory',
'service/a-service',
'controller/a-controller'
], (cfg, A, routes) ->
class Bootstrap
constructor: () ->
routes()
A.bootstrap document, [cfg.ngApp]
This meant that I only needed to define angular and bootstrap in my r.js configuration as includes and then r.js would do the rest, like so:
baseUrl: 'assets/js/app',
mainConfigFile: 'assets/js/app/config.js',
name: 'app',
include: [
'../vendor/requirejs/require',
'bootstrap'
],
out: 'assets/js/dist/app.js'
And now it all works fine! ~~It's a shame that I have to tell r.js to include requirejs though, maybe I've done something silly there?~~
Blimey, I'm such a dingus!
So in my HTML I was loading my concatenated script as:
<script src="assets/js/dist/app.js"></script>
When really it should be loaded like this:
<script src="assets/js/vendor/requirejs/require.js" data-main="assets/js/dist/app"></script>
D'oh!
From r.js doc
https://github.com/jrburke/r.js/blob/master/build/example.build.js#L322
Nested dependencies can be bundled in requireJS > v1.0.3
//Finds require() dependencies inside a require() or define call. By default
//this value is false, because those resources should be considered dynamic/runtime
//calls. However, for some optimization scenarios, it is desirable to
//include them in the build.
//Introduced in 1.0.3. Previous versions incorrectly found the nested calls
//by default.
findNestedDependencies: false,

CoffeeScript --compile order in sub-directories

Is there any way to define CoffeeScript compilation order in sub-directories?
Please consider the following example:
Files:
src/App.coffee
src/view/B.coffee
src/view/a/A.coffee
Where class A extends B.
coffee --join js/app.js --compile src/view/ src/App.coffee
This throws an error in the browser:
Uncaught TypeError: Cannot read property 'prototype' of undefined
If I rename folder a to z, the error is gone and everything works fine.
src/view/z/A.coffee
I would expect the compiler to read all .coffee files from src/view/ before it goes into src/view/ sub-directories. Again, is there any way to do that?
Edit:
PC Windows 7,
CoffeeScript version 1.3.3
The only solution I think is to create the compile order manually within a build script.
You would create an ordered collection with filenames, where as the loop iterates and concatenates a new big string, which can be compiled as one file.
Create a Cakefile with following content, check Syntax first. And run with cake build. That should work, cake comes with CoffeeScript.
fs = require 'fs'
{exec} = require 'child_process'
viewsDir = "src/view"
coffeeFiles = [
'B'
'A'
]
task 'build'
# loops through coffeeFiles.
for file, index in coffeeFiles then do (file, index) ->
fs.readFile "#{viewsDir}/#{file}", 'utf8', (err, content) ->
appCoffee[index] = content
compile() if --remaining is 0
compile = ->
fs.writeFile 'js/app.coffee', appCoffee.join('\n\n'), 'utf8', (err) ->
throw err if err
exec 'coffee --compile js/app.coffee', (err, stdout, stderr) ->
throw err if err
console.log stdout + stderr
# you can skip deleting the app.coffee file
fs.unlink 'js/app.coffee', (err) ->
throw err if err
console.log 'Created app.coffe, compiled to app.js and removes app.coffee'
# maybe additional taks
# invoke 'test'
Documented also in Wiki of Coffeescript https://github.com/jashkenas/coffee-script/wiki/[HowTo]-Compiling-and-Setting-Up-Build-Tools
Before first loop you could also make it loop through different directories. And just list filenames in coffeeFiles to be processed before the others not in listed and the rest could be added to list with fs.readDir().
We created a simple module to solve a similar problem:
https://github.com/Vizir/rehab
Just put #_require [filename].coffee on your file and you're done.
We are using it in productions with complex dependency graphs.

copy task in Cakefile

I am trying to copy all the files in a list of directories and paste them into an output directory. The problem is whenever I use an *, the output says there is no file or directory by that name exists. Here is the specific error output:
cp: cannot stat `tagbox/images/*': No such file or directory
cp: cannot stat `votebox/images/*': No such file or directory
If I just put the name of a specific file instead of *, it works.
here is my Cakefile:
fs = require 'fs'
util = require 'util'
{spawn} = require 'child_process'
outputImageFolder = 'static'
imageSrcFolders = [
'tagbox/images/*'
'votebox/images/*'
]
task 'cpimgs', 'Copy all images from the respective images folders in tagbox, votebox, and omnipost into static folder', ->
for imgSrcFolder in imageSrcFolders
cp = spawn 'cp', [imgSrcFolder, outputImageFolder]
cp.stderr.on 'data', (data) ->
process.stderr.write data.toString()
cp.stdout.on 'data', (data) ->
util.log data.toString()
You are using the * character, probably because that works for you in your shell. Using * and other wildcard characters that expand to match multiple paths is called "globbing" and while your shell does it automatically, most other programs including node/javascript/coffeescript will not do it by default. Also the cp binary itself doesn't do globbing, as you are discovering. The shell does the globbing and then passes a list of matching files/directories as arguments to cp. Look into the node module node-glob to do the globbing and give you back a list of matching files/directories, which you can then pass to cp as arguments if you like. Note that you could also use a filesystem module that would have this type of functionality built in. Note however that putting async code directly into a Cakefile can be problematic as documented here.