Skip to content

Commit

Permalink
Source map support (issue #108)
Browse files Browse the repository at this point in the history
  • Loading branch information
miripiruni committed Jul 18, 2017
1 parent da88531 commit 9167586
Show file tree
Hide file tree
Showing 14 changed files with 228 additions and 25 deletions.
11 changes: 10 additions & 1 deletion bin/bem-xjst
Expand Up @@ -35,6 +35,12 @@ require('coa').Cmd()
.short('e').long('engine')
.def('bemhtml')
.end()
.opt()
.name('sourcemap').title('Generate source map (default: false)')
.short('s').long('sourcemap')
.def(false)
.flag()
.end()
.act(function(options) {
var input = [],
deferred = q.defer();
Expand All @@ -51,7 +57,10 @@ require('coa').Cmd()

function finish(source) {
var out = bem_xjst[options.engine].generate(source, {
'no-opt': options['no-opt']
'no-opt': options['no-opt'],
from: options.input.path,
to: options.output.path,
sourceMap: options.sourceMap
});

options.output.write(out);
Expand Down
29 changes: 29 additions & 0 deletions docs/en/3-api.md
Expand Up @@ -15,6 +15,7 @@
* [Using thirdparty libraries](#using-thirdparty-libraries)
* [Extending BEMContext](#extending-bemcontext)
* [Bundling](#bundling)
* [Source maps](#source-maps)

## Choosing an engine, compiling and applying templates

Expand Down Expand Up @@ -552,4 +553,32 @@ var bundle = bemxjst.bemhtml.generate(function() {
```
Now `bundle` has a string containing the JavaScript code of the BEMHTML core and the user-defined templates.

## Source maps

There is options in `generate` method to use source maps.

* `to` {String} — output bundle file name
* `sourceMap.from` {String} — file name
* `sourceMap.prev` {String|Function|SourceMapConsumer|SourceMapGenerator} —
* previous source maps in any format

Example of generating bundle with source maps:

```js
var fs = require('fs'),
bemxjst = require('bem-xjst').bemhtml,
tmpl = 'my-block-1.bemhtml.js',
bundle = 'bundle.bemhtml.js';

var result = bemxjst.generate(fs.readFileSync(tmpl, 'utf8'), {
to: bundle,
sourceMap: { from: tmpl }
});

fs.writeFileSync(bundle, result);
```

Also [see examples](../../examples/source-maps/) about source maps and
bem-xjst.

Read next: [Input data](4-data.md)
27 changes: 27 additions & 0 deletions docs/ru/3-api.md
Expand Up @@ -14,6 +14,7 @@
* [Подключение сторонних библиотек](#Подключение-сторонних-библиотек)
* [Расширение BEMContext](#Расширение-bemcontext)
* [Создание бандла](#Создание-бандла)
* [Source maps](#source-maps)

## Выбор движка, компиляция и применение шаблонов

Expand Down Expand Up @@ -556,4 +557,30 @@ fs.writeFile('bundle.js', bundle, function(err) {
полностью готов к исполению в браузерах, node.js или любой виртуальной машине
JS.

## Source maps

В опциях шаблонизатора у вас есть возможность указать данные про карты кода

* `to` {String} — имя выходного бандла-файла
* `sourceMap.from` {String} — имя файла
* `sourceMap.prev` {String|Function|SourceMapConsumer|SourceMapGenerator} — предыдущие карты кода в любом из перечисленных форматов

Пример генерирования бандла с шаблонами и ядром bem-xjst с использованием карт кода:

```js
var fs = require('fs'),
bemxjst = require('bem-xjst').bemhtml,
tmpl = 'my-block-1.bemhtml.js',
bundle = 'bundle.bemhtml.js';

var result = bemxjst.generate(fs.readFileSync(tmpl, 'utf8'), {
to: bundle,
sourceMap: { from: tmpl }
});

fs.writeFileSync(bundle, result);
```

Так же [смотрите примеры](../../examples/source-maps/) по использованию карт кода вместе с шаблонизатором.

Читать далее: [входные данные](4-data.md)
1 change: 1 addition & 0 deletions examples/source-maps/demo1/b1.bemhtml.js
@@ -0,0 +1 @@
block('b1').tag()('blah');
1 change: 1 addition & 0 deletions examples/source-maps/demo1/demo1.html
@@ -0,0 +1 @@
<script src="bundle.bemhtml.js"></script>
11 changes: 11 additions & 0 deletions examples/source-maps/demo1/demo1.js
@@ -0,0 +1,11 @@
var fs = require('fs'),
bemxjst = require('../../../').bemhtml,
tmpl = 'b1.bemhtml.js',
bundle = 'bundle.bemhtml.js';

var result = bemxjst.generate(fs.readFileSync(tmpl, 'utf8'), {
to: bundle,
sourceMap: { from: tmpl }
});

fs.writeFileSync(bundle, result);
1 change: 1 addition & 0 deletions examples/source-maps/demo2/demo2.html
@@ -0,0 +1 @@
<script src="bundle.bemhtml.js"></script>
11 changes: 11 additions & 0 deletions examples/source-maps/demo2/demo2.js
@@ -0,0 +1,11 @@
var fs = require('fs'),
bemxjst = require('../../../').bemhtml,
tmpl = 'tmpls-with-sourcemap.bemhtml.js',
bundle = 'bundle.bemhtml.js';

var result = bemxjst.generate(fs.readFileSync(tmpl, 'utf8'), {
to: bundle,
sourceMap: { from: tmpl }
});

fs.writeFileSync(bundle, result);
72 changes: 72 additions & 0 deletions examples/source-maps/demo2/tmpls-with-sourcemap.bemhtml.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/source-maps/demo3/b3.bemhtml.js
@@ -0,0 +1 @@
block('b3').tag()('blah');
1 change: 1 addition & 0 deletions examples/source-maps/demo3/demo3.html
@@ -0,0 +1 @@
<script src="bundle.bemhtml.js"></script>
14 changes: 14 additions & 0 deletions examples/source-maps/demo3/demo3.js
@@ -0,0 +1,14 @@
var fs = require('fs'),
bemxjst = require('../../../').bemhtml,
tmpl = 'b3.bemhtml.js',
bundle = 'bundle.bemhtml.js';

var result = bemxjst.generate(fs.readFileSync(tmpl, 'utf8'), {
to: bundle,
sourceMap: {
prev: 'block(\'a\').tag()(\'a\');',
from: tmpl
},
});

fs.writeFileSync(bundle, result);
72 changes: 48 additions & 24 deletions lib/compiler.js
@@ -1,5 +1,6 @@
var fnToString = require('./bemxjst/utils').fnToString;
var readFileSync = require('fs').readFileSync;
var SourceMapFile = require('enb-source-map/lib/file');
var engines = {
bemhtml: require('./bemhtml'),
bemtree: require('./bemtree')
Expand Down Expand Up @@ -81,12 +82,14 @@ Compiler.prototype.compile = function compile(code, options) {

Compiler.prototype.generate = function generate(code, options) {
options = options || {};
code = fnToString(code);

var exportName = options.exportName || this.engineName;
var sourceMap = options.sourceMap;

if (!options.to) options.to = process.cwd();
var file = new SourceMapFile(options.to, { sourceMap: sourceMap });

code = [
code + ';',
fnToString(code) + ';',
'oninit(function(exports, context) {',
'var BEMContext = exports.BEMContext || context.BEMContext;',
// Provides third-party libraries from different modular systems
Expand All @@ -98,26 +101,42 @@ Compiler.prototype.generate = function generate(code, options) {

var deps = getDeps(options.requires);

var source = [
'var ' + exportName + ';',
'(function(global) {',
'function buildBemXjst(libs) {',
'var exports;',

'/* BEM-XJST Runtime Start */',
'var ' + exportName + ' = function(module, exports) {',
bundles[this.engineName] + ';',
'return module.exports || exports.' + exportName + ';',
'}({}, {});',

'var api = new ' + exportName + '(' + JSON.stringify(options) + ');',
file
.writeContent([
'var ' + exportName + ';',
'(function(global) {',
'function buildBemXjst(libs) {',
'var exports;',

'/* BEM-XJST Runtime Start */',
'var ' + exportName + ' = function(module, exports) {',
bundles[this.engineName] + ';',
'return module.exports || exports.' + exportName + ';',
'}({}, {});',

'var api = new ' + exportName + '(' + JSON.stringify(options) + ');',

'api.compile(function(' +
require('./bemxjst').prototype.locals.join(', ') +
') {',
'/* BEM-XJST User code here: */'
].join(EOL));

if (sourceMap && sourceMap.from) {
file.writeFileContent(sourceMap.from, getCode(code, options.runtimeLint));

if (sourceMap.prev) {
file.writeContent(
file.writeFileFromPrevMap(sourceMap.from, sourceMap.prev));
}
} else {
file.writeContent(getCode(code, options.runtimeLint));
}

'/* BEM-XJST User-code Start */',
'api.compile(function(' +
require('./bemxjst').prototype.locals.join(', ') +
') {',
getCode(code, options.runtimeLint) + ';' +
'});',
file
.write(';')
.writeContent([
'});',

'exports = api.exportApply(exports);',
'if (libs) exports.BEMContext.prototype._libs = libs;',
Expand Down Expand Up @@ -173,9 +192,14 @@ Compiler.prototype.generate = function generate(code, options) {
'})(typeof window !== "undefined" ? ' +
'window : typeof global !== "undefined" ? global : this);'

].join(EOL);
].join(EOL));

return source;
return options.sourceMap && options.sourceMap.include === false ?
{
content: file.getContent(),
sourceMap: file.getSourceMap()
} :
file.render();
};

module.exports = Compiler;
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -44,6 +44,7 @@
"license": "MPL-2.0",
"dependencies": {
"coa": "^1.0.1",
"enb-source-map": "^1.11.0",
"inherits": "^2.0.1",
"q": "^2.0.3"
},
Expand Down

0 comments on commit 9167586

Please sign in to comment.