Skip to content

Commit e4bee66

Browse files
author
Sergii.Kliuchnyk
committed
convert returns vm.Script
1 parent 58c6efe commit e4bee66

15 files changed

Lines changed: 868 additions & 868 deletions

.npmignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
./bin
2+
./data
3+
./tests

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
language: node_js
22
node_js:
3-
- "7"
3+
- "8"

README.md

Lines changed: 79 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const Layout = require('./layout');
99
<Layout>
1010
<ul class="users">
1111
{users.map(user => (
12-
<li key={user}>{user.name}</li>
12+
<li key={user}>{user.name}</li>
1313
))}
1414
</ul>
1515
</Layout>
@@ -56,7 +56,7 @@ const Layout = require('./layout');
5656
<Layout>
5757
<ul class="users">
5858
{users.map(user => (
59-
<li key={user}>{user.name}</li>
59+
<li key={user}>{user.name}</li>
6060
))}
6161
</ul>
6262
</Layout>
@@ -68,37 +68,37 @@ const React = require('react');
6868
const requireJSX = require('express-engine-jsx/require');
6969
const Context = require('express-engine-jsx/Context');
7070

71-
module.exports = function (props, context) {
72-
var locals = context && context.locals || {};
73-
var __components = [];
74-
71+
module.exports = function (props) {
72+
const __components = [];
73+
const context = React.useContext(EngineContext);
74+
const locals = context.locals || {};
75+
7576
with (locals) {
76-
with (props) {
77-
const Layout = requireJSX('./layout');
78-
79-
__components.push(
77+
with (props) {
78+
const Layout = requireJSX('./layout');
79+
80+
__components.push(
81+
React.createElement(
82+
Layout,
83+
null,
8084
React.createElement(
81-
Layout,
82-
null,
83-
React.createElement(
84-
'ul',
85-
{className: 'users'},
86-
users.map(user => (
87-
React.createElement(
88-
'li',
89-
{key: user},
90-
user.name
91-
)
92-
))
93-
)
85+
'ul',
86+
{className: 'users'},
87+
users.map(user => (
88+
React.createElement(
89+
'li',
90+
{key: user},
91+
user.name
92+
)
93+
))
9494
)
95-
);
96-
}
95+
)
96+
);
97+
}
9798
}
99+
98100
return __components;
99101
};
100-
101-
module.exports.contextType = Context;
102102
```
103103

104104
and now this component can be rendered to html with `ReactDOM.renderToStaticMarkup()`.
@@ -122,13 +122,19 @@ return __components;
122122

123123
```javascript
124124
const express = require('express');
125-
const {join} = require('path');
126125
const app = express();
126+
const engine = require('express-engine-jsx');
127127

128-
require('express-engine-jsx').attachTo(app, {
129-
cache: join(__dirname, 'cache'), // required and should be absolute path to cache dir for compiled js files
130-
views: join(__dirname, 'views'), // required and should be absolute path to views dir with jsx files
131-
doctype: "<!DOCTYPE html>\n" // optional and this is default value
128+
server.set('views', '/path/to/views');
129+
server.set('view engine', 'jsx');
130+
server.engine('jsx', engine);
131+
132+
// optionaly
133+
engine.setOptions({
134+
doctype: "<!DOCTYPE html>\n", // prepended string to every output html
135+
templatePath: '/path/to/template.jsx', // path to base tamplete of component for all jsx templates. Default is "express-engine-jsx/template.jsx",
136+
replace: (html) => {return html}, // Modify final html with this callback
137+
parserOptions: {}, // See https://babeljs.io/docs/en/babel-parser#options
132138
});
133139
```
134140

@@ -146,103 +152,89 @@ It's a function which takes three arguments:
146152

147153
* `path` - path to jsx file
148154
* `locals` - object with properties which will be local variables in jsx file
149-
* `callback` - Node style callback which will receive html string as second argument
155+
* `callback` - optional Node style callback which will receive html string as second argument
150156

151-
Also it has method `attachTo` which takes two arguments:
157+
If you pass to `engine` only path and locals then it will return html.
152158

153-
* `server` - Express instance
154-
* `options` - object which will be merged to [options](#options)
159+
Also it has method `setOptions` which can modify [options](#options)
155160

156161
### options
157162

158163
```javascript
159164
const options = require('express-engine-jsx/options');
160165
```
161166

162-
Object which has three properties:
167+
Object with optional properties:
163168

164-
* `cache` - absolute path to cache directory
165-
* `views` - absolute path to views directory
166169
* `doctype` - string which will be prepended to output html, default value is `"<!DOCTYPE html>\n"`
167-
* `replace` - optional function which will take output html (without doctype) and it should return new html
168-
* `template` - string wrapper of compiled jsx, default value is
169-
170-
```javascript
171-
const React = require('react');
172-
const requireJSX = require('express-engine-jsx/require');
173-
const Context = require('express-engine-jsx/Context');
174-
175-
module.exports = function (props, context) {
176-
var locals = context && context.locals || {};
177-
var __components = [];
178-
179-
with (locals) {
180-
with (props) {
181-
BODY
182-
}
183-
}
184-
185-
return __components;
186-
};
187-
188-
module.exports.contextType = Context;
189-
```
190-
Where `BODY` will be replaced with your compiled jsx code
191-
192-
This options used by [require](#require)
170+
* `replace` - function which will take output html (without doctype) and it should return new html
171+
* `templatePath` - path to wrapper of compiled jsx, default value is `express-engine-jsx/template.jsx`. Undefined variable `BODY` will be replaced with your compiled jsx code.
172+
* `parserOptions` - options for [babel.parser](https://babeljs.io/docs/en/babel-parser#options)
193173

194174
### require
195175

196176
```javascript
197177
const requireJSX = require('express-engine-jsx/require');
198178
```
199179

200-
This is a function which you can use as regular `require` but this one can run jsx files. It checks if path is jsx file and if it is then `requireJSX` will [convert](#convert) this file to js file and put in [cache](#options) dir and then run it.
180+
This is a function which you can use as regular `require` but this one can run jsx files. It checks if path is jsx file and if it is then `requireJSX` will [convert](#convert) this file to js code and then run it.
181+
182+
Every compiled jsx file will be cached to `requireJSX.cache` object where key will be path to jsx file and value will be [vm.Script](https://nodejs.org/api/vm.html#vm_class_vm_script).
183+
You can delete any key in this cache, requireJSX will recompile jsx file on next call.
201184

202185
### convert
203186

204187
```javascript
205188
const convert = require('express-engine-jsx/convert');
206189
```
207190

208-
It is a function which can convert jsx view files to js files. It takes only two arguments:
191+
It is a function which can convert jsx view files to [vm.Script](https://nodejs.org/api/vm.html#vm_class_vm_script).
192+
```js
193+
const script = convert('/path/to/view.jsx');
209194

210-
* `jsxPath` - path to jsx file
211-
* `jsPath` - path where js file should be saved
212-
213-
## How to update cache
195+
const context = {
196+
module: {
197+
exports: {}
198+
},
199+
__dirname: script.dirname,
200+
require: requireJSX,
201+
};
202+
203+
script.runInNewContext(context);
214204

215-
Best way is to watch jsx files with you favorite tool like gulp or grunt and use [convert](#convert) to update cached files.
205+
const ViewComponent = context.module.exports;
206+
```
216207

208+
## attr-map
209+
210+
```javascript
211+
const attrMap = require('express-engine-jsx/attr-map');
212+
```
213+
214+
This is an object where keys are names of html attributes in lower case like `class` and values are valid React html attributes like `className`.
215+
You can modify this object if I forget about some attributes.
216+
217217
## How to integrate to other engine
218218

219219
For example how to integrate to [ejs](https://www.npmjs.com/package/ejs)
220220

221221
```javascript
222222
const express = require('express');
223223
const app = express();
224-
const options = require('express-engine-jsx/options');
225-
const requireJSX = require('express-engine-jsx/require');
226-
const pt = require('path');
227-
228-
options.cache = __dirname + '/cache';
229-
options.views = __dirname + '/views';
230-
231-
app.locals.component = function (path, props) {
232-
var currentEjsFile = this.filename;
233-
var currentDirectory = pt.dirname(currentEjsFile);
234-
var Component = requireJSX(currentDirectory + '/' + path);
224+
const engine = require('express-engine-jsx');
225+
const {dirname, resolve} = require('path');
235226

236-
props = Object.assign({}, this, props || {});
227+
app.locals.component = function (path, props = {}) {
228+
props = Object.assign({}, this, props);
237229

238-
return ReactDOM.renderToStaticMarkup(Component(props));
230+
return engine(resolve(dirname(this.filename), path), props);
239231
};
240232
```
241233

242234
Now we can use `component()` in ejs files like this
243235

244236
```ejs
245-
<div><%- component('button', {title: 'Submit'}) %></div>
237+
<div><%- component('path/to/jsx-view', {prop: 'value'}) %></div>
246238
```
247239

248240
## Problem with more than one component in template root
@@ -267,7 +259,7 @@ First - use `;`
267259

268260
```jsx harmony
269261
<div>first</div>;
270-
<div>second</div>
262+
<div>second</div>;
271263
```
272264

273265
Second - use `<Fragment>`

attr-map.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"acceptcharset":"acceptCharset","accesskey":"accessKey","allowfullscreen":"allowFullScreen","allowtransparency":"allowTransparency","autocomplete":"autoComplete","autofocus":"autoFocus","autoplay":"autoPlay","cellpadding":"cellPadding","cellspacing":"cellSpacing","charset":"charSet","classid":"classID","class":"className","colspan":"colSpan","contenteditable":"contentEditable","contextmenu":"contextMenu","controlslist":"controlsList","crossorigin":"crossOrigin","datetime":"dateTime","enctype":"encType","formaction":"formAction","formenctype":"formEncType","formmethod":"formMethod","formnovalidate":"formNoValidate","formtarget":"formTarget","frameborder":"frameBorder","hreflang":"hrefLang","htmlfor":"htmlFor","httpequiv":"httpEquiv","inputmode":"inputMode","keyparams":"keyParams","keytype":"keyType","marginheight":"marginHeight","marginwidth":"marginWidth","maxlength":"maxLength","mediagroup":"mediaGroup","minlength":"minLength","novalidate":"noValidate","radiogroup":"radioGroup","readonly":"readOnly","rowspan":"rowSpan","spellcheck":"spellCheck","srcdoc":"srcDoc","srclang":"srcLang","srcset":"srcSet","tabindex":"tabIndex","usemap":"useMap","accentheight":"accentHeight","alignmentbaseline":"alignmentBaseline","allowreorder":"allowReorder","arabicform":"arabicForm","attributename":"attributeName","attributetype":"attributeType","autoreverse":"autoReverse","basefrequency":"baseFrequency","baseprofile":"baseProfile","baselineshift":"baselineShift","calcmode":"calcMode","capheight":"capHeight","clippath":"clipPath","clippathunits":"clipPathUnits","cliprule":"clipRule","colorinterpolation":"colorInterpolation","colorinterpolationfilters":"colorInterpolationFilters","colorprofile":"colorProfile","colorrendering":"colorRendering","contentscripttype":"contentScriptType","contentstyletype":"contentStyleType","diffuseconstant":"diffuseConstant","dominantbaseline":"dominantBaseline","edgemode":"edgeMode","enablebackground":"enableBackground","externalresourcesrequired":"externalResourcesRequired","fillopacity":"fillOpacity","fillrule":"fillRule","filterres":"filterRes","filterunits":"filterUnits","floodcolor":"floodColor","floodopacity":"floodOpacity","fontfamily":"fontFamily","fontsize":"fontSize","fontsizeadjust":"fontSizeAdjust","fontstretch":"fontStretch","fontstyle":"fontStyle","fontvariant":"fontVariant","fontweight":"fontWeight","glyphname":"glyphName","glyphorientationhorizontal":"glyphOrientationHorizontal","glyphorientationvertical":"glyphOrientationVertical","glyphref":"glyphRef","gradienttransform":"gradientTransform","gradientunits":"gradientUnits","horizadvx":"horizAdvX","horizoriginx":"horizOriginX","imagerendering":"imageRendering","kernelmatrix":"kernelMatrix","kernelunitlength":"kernelUnitLength","keypoints":"keyPoints","keysplines":"keySplines","keytimes":"keyTimes","lengthadjust":"lengthAdjust","letterspacing":"letterSpacing","lightingcolor":"lightingColor","limitingconeangle":"limitingConeAngle","markerend":"markerEnd","markerheight":"markerHeight","markermid":"markerMid","markerstart":"markerStart","markerunits":"markerUnits","markerwidth":"markerWidth","maskcontentunits":"maskContentUnits","maskunits":"maskUnits","numoctaves":"numOctaves","overlineposition":"overlinePosition","overlinethickness":"overlineThickness","paintorder":"paintOrder","pathlength":"pathLength","patterncontentunits":"patternContentUnits","patterntransform":"patternTransform","patternunits":"patternUnits","pointerevents":"pointerEvents","pointsatx":"pointsAtX","pointsaty":"pointsAtY","pointsatz":"pointsAtZ","preservealpha":"preserveAlpha","preserveaspectratio":"preserveAspectRatio","primitiveunits":"primitiveUnits","refx":"refX","refy":"refY","renderingintent":"renderingIntent","repeatcount":"repeatCount","repeatdur":"repeatDur","requiredextensions":"requiredExtensions","requiredfeatures":"requiredFeatures","shaperendering":"shapeRendering","specularconstant":"specularConstant","specularexponent":"specularExponent","spreadmethod":"spreadMethod","startoffset":"startOffset","stddeviation":"stdDeviation","stitchtiles":"stitchTiles","stopcolor":"stopColor","stopopacity":"stopOpacity","strikethroughposition":"strikethroughPosition","strikethroughthickness":"strikethroughThickness","strokedasharray":"strokeDasharray","strokedashoffset":"strokeDashoffset","strokelinecap":"strokeLinecap","strokelinejoin":"strokeLinejoin","strokemiterlimit":"strokeMiterlimit","strokeopacity":"strokeOpacity","strokewidth":"strokeWidth","surfacescale":"surfaceScale","systemlanguage":"systemLanguage","tablevalues":"tableValues","targetx":"targetX","targety":"targetY","textanchor":"textAnchor","textdecoration":"textDecoration","textlength":"textLength","textrendering":"textRendering","underlineposition":"underlinePosition","underlinethickness":"underlineThickness","unicodebidi":"unicodeBidi","unicoderange":"unicodeRange","unitsperem":"unitsPerEm","valphabetic":"vAlphabetic","vhanging":"vHanging","videographic":"vIdeographic","vmathematical":"vMathematical","vectoreffect":"vectorEffect","vertadvy":"vertAdvY","vertoriginx":"vertOriginX","vertoriginy":"vertOriginY","viewbox":"viewBox","viewtarget":"viewTarget","wordspacing":"wordSpacing","writingmode":"writingMode","xchannelselector":"xChannelSelector","xheight":"xHeight","xlinkactuate":"xlinkActuate","xlinkarcrole":"xlinkArcrole","xlinkhref":"xlinkHref","xlinkrole":"xlinkRole","xlinkshow":"xlinkShow","xlinktitle":"xlinkTitle","xlinktype":"xlinkType","xmlnsxlink":"xmlnsXlink","xmlbase":"xmlBase","xmllang":"xmlLang","xmlspace":"xmlSpace","ychannelselector":"yChannelSelector","zoomandpan":"zoomAndPan"}

bin/build-attr-map.js

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
var fs = require('fs');
2-
var list = fs.readFileSync(process.argv[2]).toString();
3-
list = JSON.parse(list);
4-
list = list
1+
const fs = require('fs');
2+
const {resolve} = require('path');
3+
4+
const namesPath = resolve(__dirname, '..', 'data', 'attr-names.json');
5+
const mapPath = resolve(__dirname, '..', 'attr-map.json');
6+
7+
let list = fs.readFileSync(namesPath).toString();
8+
9+
list = JSON.parse(list)
510
.filter(function (attr) {
611
return /[A-Z]/.test(attr);
712
})
813
.reduce(function (hash, attr) {
9-
hash[attr.toLowerCase()] = attr;
14+
hash[attr === 'className' ? 'class' : attr.toLowerCase()] = attr;
1015

1116
return hash;
12-
}, {})
13-
;
14-
fs.writeFileSync(process.argv[3], JSON.stringify(list));
17+
}, {});
18+
19+
fs.writeFileSync(mapPath, JSON.stringify(list));

0 commit comments

Comments
 (0)