support coffee-script models and client code
Load models for any filetypes registered in require.extensions. - Server side coffee-script requires a `require('coffee-script/register');` - Client side coffee-script requires Coffeeify.
This commit is contained in:
parent
3961f1c615
commit
e936deffe2
|
@ -0,0 +1,35 @@
|
||||||
|
## Server Files in Coffee-Script
|
||||||
|
|
||||||
|
In order to create application files in coffee-script, you'll need to register the coffee-script extension:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
require('coffee-script/register');
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll need to do this at any entry points for the app (e.g. the server.js file, mocha.opts, and gulp/grunt). It is recommended to leave the entry point of the app (server.js by default, specified as 'main' in package.json) as a javascript file, and then register coffee-script, and proceed with any coffee-requires.
|
||||||
|
|
||||||
|
## Client Files in Coffee-Script
|
||||||
|
|
||||||
|
You can use the Coffeeify module to include Coffee files in your browser package. Use a build script like this:
|
||||||
|
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// assuming you haven't done so already
|
||||||
|
require('coffee-script/register');
|
||||||
|
|
||||||
|
var b = browserify({
|
||||||
|
basedir: appDir,
|
||||||
|
extensions: ['.coffee'], //causes browserify to look for this extension
|
||||||
|
debug: true
|
||||||
|
});
|
||||||
|
|
||||||
|
b.transform('coffeeify'); //adds coffee compiler to the build pipeline
|
||||||
|
|
||||||
|
b.require('./app.coffee', { expose: 'browser-app' }); //requiring your file will set the entry point
|
||||||
|
boot.compileToBrowserify(appDir, b);
|
||||||
|
|
||||||
|
var bundlePath = sandbox.resolve('browser-app-bundle.js'); //remember, the final result is still '.js'
|
||||||
|
var out = fs.createWriteStream(bundlePath);
|
||||||
|
|
||||||
|
b.bundle().pipe(out);
|
||||||
|
```
|
|
@ -253,13 +253,14 @@ function findModelDefinitions(rootDir, sources) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var files = tryReadDir(srcDir);
|
var files = tryReadDir(srcDir);
|
||||||
|
|
||||||
files
|
files
|
||||||
.filter(function(f) {
|
.filter(function(f) {
|
||||||
return f[0] !== '_' && path.extname(f) === '.json';
|
return f[0] !== '_' && path.extname(f) === '.json';
|
||||||
})
|
})
|
||||||
.forEach(function(f) {
|
.forEach(function(f) {
|
||||||
var fullPath = path.resolve(srcDir, f);
|
var fullPath = path.resolve(srcDir, f);
|
||||||
var entry = loadModelDefinition(rootDir, fullPath);
|
var entry = loadModelDefinition(rootDir, fullPath, files);
|
||||||
var modelName = entry.definition.name;
|
var modelName = entry.definition.name;
|
||||||
if (!modelName) {
|
if (!modelName) {
|
||||||
debug('Skipping model definition without Model name: %s',
|
debug('Skipping model definition without Model name: %s',
|
||||||
|
@ -303,24 +304,29 @@ function resolveSourceDir(rootDir, sourceDir) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadModelDefinition(rootDir, jsonFile) {
|
function loadModelDefinition(rootDir, jsonFile, allFiles) {
|
||||||
var definition = require(jsonFile);
|
var definition = require(jsonFile);
|
||||||
|
var basename = path.basename(jsonFile, path.extname(jsonFile));
|
||||||
|
|
||||||
var sourceFile = path.join(
|
// find a matching file with `.js` or any other supported extension like `.coffee`
|
||||||
path.dirname(jsonFile),
|
var base, ext, validFileType;
|
||||||
path.basename(jsonFile, path.extname(jsonFile)));
|
var sourceFile = allFiles
|
||||||
|
.filter(function(f) {
|
||||||
|
ext = path.extname(f);
|
||||||
|
base = path.basename(f, ext);
|
||||||
|
validFileType = (ext !== '.node') && (ext !== '.json') &&
|
||||||
|
((typeof require.extensions[ext]) === 'function');
|
||||||
|
return validFileType && (base === basename);
|
||||||
|
})[0];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// resolve the file to `.js` or any other supported extension like `.coffee`
|
sourceFile = path.join(path.dirname(jsonFile), sourceFile);
|
||||||
sourceFile = require.resolve(sourceFile);
|
sourceFile = require.resolve(sourceFile);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
debug('Model source code not found: %s - %s', sourceFile, err.code || err);
|
debug('Model source code not found: %s - %s', sourceFile, err.code || err);
|
||||||
sourceFile = undefined;
|
sourceFile = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sourceFile === jsonFile)
|
|
||||||
sourceFile = undefined;
|
|
||||||
|
|
||||||
debug('Found model "%s" - %s %s', definition.name,
|
debug('Found model "%s" - %s %s', definition.name,
|
||||||
path.relative(rootDir, jsonFile),
|
path.relative(rootDir, jsonFile),
|
||||||
sourceFile ? path.relative(rootDir, sourceFile) : '(no source file)');
|
sourceFile ? path.relative(rootDir, sourceFile) : '(no source file)');
|
||||||
|
|
|
@ -34,6 +34,9 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"browserify": "^6.1.0",
|
"browserify": "^6.1.0",
|
||||||
"fs-extra": "^0.12.0",
|
"fs-extra": "^0.12.0",
|
||||||
|
"browserify": "^4.1.8",
|
||||||
|
"coffee-script": "^1.8.0",
|
||||||
|
"coffeeify": "^0.7.0",
|
||||||
"jshint": "^2.5.6",
|
"jshint": "^2.5.6",
|
||||||
"loopback": "^2.5.0",
|
"loopback": "^2.5.0",
|
||||||
"mocha": "^1.19.0",
|
"mocha": "^1.19.0",
|
||||||
|
|
|
@ -6,6 +6,31 @@ var browserify = require('browserify');
|
||||||
var sandbox = require('./helpers/sandbox');
|
var sandbox = require('./helpers/sandbox');
|
||||||
var vm = require('vm');
|
var vm = require('vm');
|
||||||
|
|
||||||
|
var compileStrategies = {
|
||||||
|
'default': function(appDir) {
|
||||||
|
var b = browserify({
|
||||||
|
basedir: appDir,
|
||||||
|
debug: true
|
||||||
|
});
|
||||||
|
|
||||||
|
b.require('./app.js', { expose: 'browser-app' });
|
||||||
|
return b;
|
||||||
|
},
|
||||||
|
|
||||||
|
'coffee': function(appDir) {
|
||||||
|
var b = browserify({
|
||||||
|
basedir: appDir,
|
||||||
|
extensions: ['.coffee'],
|
||||||
|
debug: true
|
||||||
|
});
|
||||||
|
|
||||||
|
b.transform('coffeeify');
|
||||||
|
|
||||||
|
b.require('./app.coffee', { expose: 'browser-app' });
|
||||||
|
return b;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
describe('browser support', function() {
|
describe('browser support', function() {
|
||||||
this.timeout(60000); // 60s to give browserify enough time to finish
|
this.timeout(60000); // 60s to give browserify enough time to finish
|
||||||
|
|
||||||
|
@ -28,14 +53,38 @@ describe('browser support', function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('supports coffee-script files', function(done) {
|
||||||
|
// add coffee-script to require.extensions
|
||||||
|
require('coffee-script/register');
|
||||||
|
|
||||||
|
var appDir = path.resolve(__dirname, './fixtures/coffee-app');
|
||||||
|
|
||||||
|
browserifyTestApp(appDir, 'coffee', function(err, bundlePath) {
|
||||||
|
if (err) return done(err);
|
||||||
|
|
||||||
|
var app = executeBundledApp(bundlePath);
|
||||||
|
|
||||||
|
// configured in fixtures/browser-app/boot/configure.coffee
|
||||||
|
expect(app.settings).to.have.property('custom-key', 'custom-value');
|
||||||
|
expect(Object.keys(app.models)).to.include('Customer');
|
||||||
|
expect(app.models.Customer.settings)
|
||||||
|
.to.have.property('_customized', 'Customer');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function browserifyTestApp(appDir, next) {
|
function browserifyTestApp(appDir, strategy, next) {
|
||||||
var b = browserify({
|
//set default args
|
||||||
basedir: appDir,
|
if (((typeof strategy) === 'function') && !next) {
|
||||||
debug: true
|
next = strategy;
|
||||||
});
|
strategy = undefined;
|
||||||
b.require('./app.js', { expose: 'browser-app' });
|
}
|
||||||
|
if (!strategy)
|
||||||
|
strategy = 'default';
|
||||||
|
|
||||||
|
var b = compileStrategies[strategy](appDir);
|
||||||
|
|
||||||
boot.compileToBrowserify(appDir, b);
|
boot.compileToBrowserify(appDir, b);
|
||||||
|
|
||||||
|
|
|
@ -451,6 +451,31 @@ describe('compiler', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('loads coffeescript models from `./models`', function() {
|
||||||
|
// add coffee-script to require.extensions
|
||||||
|
require('coffee-script/register');
|
||||||
|
|
||||||
|
appdir.createConfigFilesSync({}, {}, {
|
||||||
|
Car: { dataSource: 'db' }
|
||||||
|
});
|
||||||
|
appdir.writeConfigFileSync('models/car.json', { name: 'Car' });
|
||||||
|
appdir.writeFileSync('models/car.coffee', '');
|
||||||
|
|
||||||
|
var instructions = boot.compile(appdir.PATH);
|
||||||
|
|
||||||
|
expect(instructions.models).to.have.length(1);
|
||||||
|
expect(instructions.models[0]).to.eql({
|
||||||
|
name: 'Car',
|
||||||
|
config: {
|
||||||
|
dataSource: 'db'
|
||||||
|
},
|
||||||
|
definition: {
|
||||||
|
name: 'Car'
|
||||||
|
},
|
||||||
|
sourceFile: path.resolve(appdir.PATH, 'models', 'car.coffee')
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('supports `modelSources` option', function() {
|
it('supports `modelSources` option', function() {
|
||||||
appdir.createConfigFilesSync({}, {}, {
|
appdir.createConfigFilesSync({}, {}, {
|
||||||
Car: { dataSource: 'db' }
|
Car: { dataSource: 'db' }
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
loopback = require 'loopback'
|
||||||
|
boot = require '../../../'
|
||||||
|
|
||||||
|
module.exports = client = loopback()
|
||||||
|
boot(client)
|
|
@ -0,0 +1,2 @@
|
||||||
|
module.exports = (app) ->
|
||||||
|
app.set 'custom-key', 'custom-value'
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"db": {
|
||||||
|
"connector": "remote"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"Customer": {
|
||||||
|
"dataSource": "db"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = (Customer) ->
|
||||||
|
Customer.settings._customized = 'Customer'
|
||||||
|
Customer.base.settings._customized = 'Base'
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"name": "Customer",
|
||||||
|
"base": "User"
|
||||||
|
}
|
Loading…
Reference in New Issue