Comparing version 9.0.1 to 9.1.0
23
index.js
var through = require('through') | ||
var compiler = require('./lib/compiler') | ||
compiler.loadConfig() | ||
module.exports = function vueify (file, options) { | ||
if (!/.vue$/.test(file)) { | ||
return through() | ||
} | ||
module.exports = function vueify (file, options) { | ||
if (!/.vue$/.test(file)) return through() | ||
compiler.applyConfig(options) | ||
compiler.applyConfig({ | ||
sourceMap: options._flags.debug | ||
}) | ||
var data = '' | ||
var stream = through(write, end) | ||
stream.vueify = true | ||
function dependency(file) { | ||
function dependency (file) { | ||
stream.emit('file', file) | ||
} | ||
function write(buf) { | ||
function emitStyle (e) { | ||
stream.emit('vueify-style', e) | ||
} | ||
function write (buf) { | ||
data += buf | ||
@@ -24,5 +33,7 @@ } | ||
compiler.on('dependency', dependency) | ||
compiler.on('style', emitStyle) | ||
compiler.compile(data, file, function(error, result) { | ||
compiler.compile(data, file, function (error, result) { | ||
compiler.removeListener('dependency', dependency) | ||
compiler.removeListener('style', emitStyle) | ||
if (error) { | ||
@@ -29,0 +40,0 @@ stream.emit('error', error) |
@@ -5,5 +5,6 @@ var fs = require('fs') | ||
var hash = require('hash-sum') | ||
var assign = require('object-assign') | ||
var Emitter = require('events').EventEmitter | ||
var vueCompiler = require('vue-template-compiler') | ||
var sourceMap = require('source-map') | ||
var convert = require('convert-source-map') | ||
@@ -13,5 +14,9 @@ var genId = require('./gen-id') | ||
var compilers = require('./compilers') | ||
var options = require('./compilers/options') | ||
var rewriteStyle = require('./style-rewriter') | ||
var compileTemplate = require('./template-compiler') | ||
// determine dynamic script paths | ||
var hotReloadAPIPath = normalize.dep('vue-hot-reload-api') | ||
var insertCSSPath = normalize.lib('insert-css') | ||
var hasBabel = true | ||
@@ -24,8 +29,5 @@ try { | ||
var splitRE = /\r?\n/g | ||
var resolvedPartsCache = Object.create(null) | ||
// determine dynamic script paths | ||
var hotReloadAPIPath = 'vue-hot-reload-api' //normalize.dep('vue-hot-reload-api') | ||
var insertCSSPath = normalize.lib('insert-css') | ||
// expose compiler | ||
@@ -35,2 +37,5 @@ var compiler = module.exports = new Emitter() | ||
// options | ||
var options = compiler.options = {} | ||
// load user config | ||
@@ -65,3 +70,3 @@ compiler.loadConfig = function () { | ||
// parse the component into parts | ||
var parts = vueCompiler.parseComponent(content) | ||
var parts = vueCompiler.parseComponent(content, { pad: true }) | ||
@@ -96,8 +101,16 @@ // check for scoped style nodes | ||
var output = '' | ||
var map = null | ||
// styles | ||
var style = resolvedParts.styles.join('\n') | ||
if (style) { | ||
style = JSON.stringify(style) | ||
output += | ||
'var __vueify_style_dispose__ = require("' + insertCSSPath + '").insert(' + style + ')\n' | ||
// emit style | ||
compiler.emit('style', { | ||
file: filePath, | ||
style: style | ||
}) | ||
if (!options.extractCSS) { | ||
style = JSON.stringify(style) | ||
output += | ||
'var __vueify_style_dispose__ = require("' + insertCSSPath + '").insert(' + style + ')\n' | ||
} | ||
} | ||
@@ -107,4 +120,7 @@ // script | ||
if (script) { | ||
if (options.sourceMap) { | ||
map = generateSourceMap(script, output) | ||
} | ||
output += | ||
';(function(){' + script + '})()\n' + | ||
';(function(){\n' + script + '\n})()\n' + | ||
// babel 6 compat | ||
@@ -137,3 +153,5 @@ 'if (module.exports.__esModule) module.exports = module.exports.default\n' | ||
// remove style tag on dispose | ||
(style ? ' module.hot.dispose(__vueify_style_dispose__)\n' : '') + | ||
(style && !options.extractCSS | ||
? ' module.hot.dispose(__vueify_style_dispose__)\n' | ||
: '') + | ||
' if (!module.hot.data) {\n' + | ||
@@ -153,4 +171,38 @@ // initial insert | ||
} | ||
if (map) { | ||
output += '\n' + convert.fromJSON(map.toString()).toComment() | ||
} | ||
cb(null, output) | ||
} | ||
function generateSourceMap (script, output) { | ||
// hot-reload source map busting | ||
var hashedFilename = path.basename(filePath) + '?' + hash(filePath + content) | ||
var map = new sourceMap.SourceMapGenerator() | ||
map.setSourceContent(hashedFilename, content) | ||
// check input source map from babel/coffee etc | ||
var inMap = resolvedParts.map | ||
var inMapConsumer = inMap && new sourceMap.SourceMapConsumer(inMap) | ||
var generatedOffset = (output ? output.split(splitRE).length : 0) + 1 | ||
script.split(splitRE).forEach(function (line, index) { | ||
var ln = index + 1 | ||
var originalLine = inMapConsumer | ||
? inMapConsumer.originalPositionFor({ line: ln, column: 0 }).line | ||
: ln | ||
if (originalLine) { | ||
map.addMapping({ | ||
source: hashedFilename, | ||
generated: { | ||
line: ln + generatedOffset, | ||
column: 0 | ||
}, | ||
original: { | ||
line: originalLine, | ||
column: 0 | ||
} | ||
}) | ||
} | ||
}) | ||
return map | ||
} | ||
} | ||
@@ -163,14 +215,3 @@ | ||
.then(function (res) { | ||
var compiled = vueCompiler.compile(res) | ||
if (compiled.errors.length) { | ||
compiled.errors.forEach(function (msg) { | ||
console.error('\n' + chalk.red(msg) + '\n') | ||
}) | ||
throw new Error('Vue template compilation failed') | ||
} else { | ||
parts.template = { | ||
render: toFunction(compiled.render), | ||
staticRenderFns: '[' + compiled.staticRenderFns.map(toFunction).join(',') + ']' | ||
} | ||
} | ||
parts.template = compileTemplate(res, compiler) | ||
}) | ||
@@ -185,3 +226,8 @@ } | ||
.then(function (res) { | ||
parts.script = res | ||
if (typeof res === 'string') { | ||
parts.script = res | ||
} else { | ||
parts.script = res.code | ||
parts.map = res.map | ||
} | ||
}) | ||
@@ -194,3 +240,4 @@ } | ||
.then(function (res) { | ||
return rewriteStyle(id, res, part.scoped).then(function (res) { | ||
res = res.trim() | ||
return rewriteStyle(id, res, part.scoped, options).then(function (res) { | ||
parts.styles.push(res) | ||
@@ -209,6 +256,6 @@ }) | ||
var dir = path.dirname(filePath) | ||
var filePath = path.resolve(dir, src) | ||
compiler.emit('dependency', filePath) | ||
var srcPath = path.resolve(dir, src) | ||
compiler.emit('dependency', srcPath) | ||
try { | ||
return fs.readFileSync(filePath, 'utf-8') | ||
return fs.readFileSync(srcPath, 'utf-8') | ||
} catch (e) { | ||
@@ -243,5 +290,1 @@ console.error(chalk.red( | ||
} | ||
function toFunction (code) { | ||
return 'function(){' + code + '}' | ||
} |
var fs = require('fs') | ||
var path = require('path') | ||
var options = require('./options') | ||
var assign = require('object-assign') | ||
var ensureRequire = require('../ensure-require') | ||
@@ -39,10 +39,15 @@ | ||
module.exports = function (raw, cb) { | ||
module.exports = function (raw, cb, compiler, filePath) { | ||
try { | ||
var babel = require('babel-core') | ||
var res = babel.transform(raw, options.babel || babelOptions) | ||
var options = assign({ | ||
comments: false, | ||
filename: filePath, | ||
sourceMaps: compiler.options.sourceMap | ||
}, compiler.options.babel || babelOptions) | ||
var res = babel.transform(raw, options) | ||
} catch (err) { | ||
return cb(err) | ||
} | ||
cb(null, res.code) | ||
cb(null, res) | ||
} |
@@ -1,10 +0,11 @@ | ||
var options = require('./options') | ||
var ensureRequire = require('../ensure-require.js') | ||
module.exports = function (raw, cb) { | ||
module.exports = function (raw, cb, compiler) { | ||
ensureRequire('coffee', ['coffee-script']) | ||
var coffee = require('coffee-script') | ||
var compiled | ||
try { | ||
var js = coffee.compile(raw, options.coffee || { | ||
bare: true | ||
compiled = coffee.compile(raw, compiler.options.coffee || { | ||
bare: true, | ||
sourceMap: compiler.options.sourceMap | ||
}) | ||
@@ -14,3 +15,9 @@ } catch (err) { | ||
} | ||
cb(null, js) | ||
if (compiler.options.sourceMap) { | ||
compiled = { | ||
code: compiled.js, | ||
map: compiled.v3SourceMap | ||
} | ||
} | ||
cb(null, compiled) | ||
} |
@@ -1,9 +0,8 @@ | ||
var options = require('./options') | ||
var ensureRequire = require('../ensure-require.js') | ||
module.exports = function (raw, cb) { | ||
module.exports = function (raw, cb, compiler) { | ||
ensureRequire('jade', 'jade') | ||
var jade = require('jade') | ||
try { | ||
var html = jade.compile(raw, options.jade || {})() | ||
var html = jade.compile(raw, compiler.options.jade || {})() | ||
} catch (err) { | ||
@@ -10,0 +9,0 @@ return cb(err) |
@@ -1,2 +0,1 @@ | ||
var options = require('./options') | ||
var assign = require('object-assign') | ||
@@ -12,3 +11,3 @@ var path = require('path') | ||
filename: path.basename(filePath) | ||
}, options.less) | ||
}, compiler.options.less) | ||
@@ -15,0 +14,0 @@ // provide import path |
@@ -1,9 +0,8 @@ | ||
var options = require('./options') | ||
var ensureRequire = require('../ensure-require.js') | ||
module.exports = function (raw, cb) { | ||
module.exports = function (raw, cb, compiler) { | ||
ensureRequire('pug', 'pug') | ||
var pug = require('pug') | ||
try { | ||
var html = pug.compile(raw, options.pug || {})() | ||
var html = pug.compile(raw, compiler.options.pug || {})() | ||
} catch (err) { | ||
@@ -10,0 +9,0 @@ return cb(err) |
@@ -1,2 +0,1 @@ | ||
var options = require('./options') | ||
var assign = require('object-assign') | ||
@@ -22,3 +21,3 @@ var path = require('path') | ||
} | ||
}, options.sass || { | ||
}, compiler.options.sass || { | ||
sourceComments: true | ||
@@ -40,3 +39,3 @@ }) | ||
} else { | ||
res.stats.includedFiles.forEach(function(file){ | ||
res.stats.includedFiles.forEach(function (file) { | ||
compiler.emit('dependency', file) | ||
@@ -43,0 +42,0 @@ }) |
@@ -1,2 +0,1 @@ | ||
var options = require('./options') | ||
var assign = require('object-assign') | ||
@@ -12,3 +11,3 @@ var path = require('path') | ||
filename: path.basename(filePath) | ||
}, options.stylus || {}) | ||
}, compiler.options.stylus || {}) | ||
@@ -15,0 +14,0 @@ var dir = path.dirname(filePath) |
module.exports = function (name, deps) { | ||
var i, len | ||
var missing = [] | ||
if (typeof deps === "string") { | ||
if (typeof deps === 'string') { | ||
deps = [deps] | ||
} | ||
for (i = 0, len = deps.length; i < len; i++) { | ||
var mis, req = deps[i] | ||
if (typeof req === "string") { | ||
var mis | ||
var req = deps[i] | ||
if (typeof req === 'string') { | ||
mis = req | ||
@@ -27,3 +28,3 @@ } else { | ||
var message = 'You are trying to use "' + name + '". ' | ||
var npmInstall = 'npm install --save-dev ' + missing.join(" ") | ||
var npmInstall = 'npm install --save-dev ' + missing.join(' ') | ||
if (missing.length > 1) { | ||
@@ -30,0 +31,0 @@ var last = missing.pop() |
@@ -5,3 +5,2 @@ var postcss = require('postcss') | ||
var assign = require('object-assign') | ||
var options = require('./compilers/options') | ||
@@ -40,6 +39,7 @@ var currentId | ||
* @param {Boolean} scoped | ||
* @param {Object} options | ||
* @return {Promise} | ||
*/ | ||
module.exports = function (id, css, scoped) { | ||
module.exports = function (id, css, scoped, options) { | ||
var key = id + '!!' + css | ||
@@ -46,0 +46,0 @@ var val = cache.get(key) |
{ | ||
"name": "vueify", | ||
"version": "9.0.1", | ||
"version": "9.1.0", | ||
"description": "Vue component transform for Browserify", | ||
@@ -20,3 +20,3 @@ "main": "index.js", | ||
"scripts": { | ||
"test": "mocha test/test.js --slow=5000 --timeout=10000" | ||
"test": "eslint index.js lib && mocha test/test.js --slow=5000 --timeout=10000" | ||
}, | ||
@@ -26,2 +26,3 @@ "homepage": "https://github.com/vuejs/vueify", | ||
"chalk": "^1.1.1", | ||
"convert-source-map": "^1.2.0", | ||
"cssnano": "^3.3.2", | ||
@@ -33,2 +34,3 @@ "hash-sum": "^1.0.2", | ||
"postcss-selector-parser": "^2.0.0", | ||
"source-map": "^0.5.6", | ||
"through": "^2.3.6", | ||
@@ -46,2 +48,4 @@ "vue-hot-reload-api": "^2.0.1", | ||
"coffee-script": "^1.10.0", | ||
"eslint": "^2.13.0", | ||
"eslint-config-vue": "^1.0.3", | ||
"jade": "^1.11.0", | ||
@@ -48,0 +52,0 @@ "jsdom": "^9.2.1", |
116
README.md
@@ -70,13 +70,2 @@ # vueify [![Build Status](https://circleci.com/gh/vuejs/vueify.svg?style=shield)](https://circleci.com/gh/vuejs/vueify) [![npm version](https://badge.fury.io/js/vueify.svg)](http://badge.fury.io/js/vueify) | ||
If you are using npm 3+, it no longer auto install the peer dependencies. So you will also have to also install the babel-related dependencies: | ||
``` bash | ||
npm install\ | ||
babel-core\ | ||
babel-preset-es2015\ | ||
babel-runtime\ | ||
babel-plugin-transform-runtime\ | ||
--save-dev | ||
``` | ||
And this is all you need to do in your main entry file: | ||
@@ -90,5 +79,5 @@ | ||
new Vue({ | ||
el: 'body', | ||
components: { | ||
app: App | ||
el: '#app', | ||
render: function (createElement) { | ||
return createElement(App) | ||
} | ||
@@ -102,3 +91,3 @@ }) | ||
<body> | ||
<app></app> | ||
<div id="app"></div> | ||
<script src="build.js"></script> | ||
@@ -127,31 +116,30 @@ </body> | ||
## ES2015 by Default | ||
## ES2015 with Babel | ||
Vueify automatically transforms the JavaScript in your `*.vue` components using Babel. Write ES2015 today! | ||
Vueify is pre-configured to work with Babel. Simply install Babel-related dependencies: | ||
The default Babel (6) options used for Vue.js components are: | ||
``` js | ||
{ | ||
"presets": ["es2015"], | ||
"plugins": ["transform-runtime"] | ||
} | ||
``` bash | ||
npm install\ | ||
babel-core\ | ||
babel-preset-es2015\ | ||
--save-dev | ||
``` | ||
If you wish to override this, you can add a `.babelrc` file at the root of your project: | ||
Then create a `.babelrc`: | ||
``` json | ||
{ | ||
"presets": ["es2015", "stage-2"], | ||
"plugins": ["transform-runtime"] | ||
"presets": ["es2015"] | ||
} | ||
``` | ||
And voila! You can now write ES2015 in your `*.vue` files. Note if you want to use ES2015 on normal `*.js` files, you will also need [babelify](https://github.com/babel/babelify). | ||
You can also configure babel with the `babel` field in `vue.config.js`, which will take the highest priority. | ||
## Enabling Pre-Processors | ||
## Enabling Other Pre-Processors | ||
You need to install the corresponding node modules to enable the compilation. e.g. to get stylus compiled in your Vue components, do `npm install stylus --save-dev`. | ||
For other pre-processors, you also need to install the corresponding node modules to enable the compilation. e.g. to get stylus compiled in your Vue components, do `npm install stylus --save-dev`. | ||
These are the built-in preprocessors: | ||
These are the preprocessors supported by vueify out of the box: | ||
@@ -165,9 +153,5 @@ - stylus | ||
## Autoprefix by Default | ||
Starting in 5.0.0, all CSS output via vueify will be autoprefixed by default. See [config section](#configuring-options) below on customizing the options. | ||
## PostCSS | ||
Vueify uses PostCSS for scoped CSS rewrite and autoprefixing. You can also provide your own PostCSS plugins! See [config section](#configuring-options) below for an example. | ||
Vueify uses PostCSS for scoped CSS rewrite. You can also provide your own PostCSS plugins! See [config section](#configuring-options) below for an example. | ||
@@ -186,11 +170,2 @@ ## Configuring Options | ||
postcss: [...], | ||
// configure autoprefixer | ||
autoprefixer: { | ||
browsers: ['last 2 versions'] | ||
}, | ||
// configure html minification in production mode | ||
// see https://github.com/kangax/html-minifier#options-quick-reference | ||
htmlMinifier: { | ||
// ... | ||
}, | ||
// register custom compilers | ||
@@ -218,5 +193,3 @@ customCompilers: { | ||
module.exports = { | ||
postcss: [cssnext()], | ||
// disable autoprefixer since cssnext comes with it | ||
autoprefixer: false | ||
postcss: [cssnext()] | ||
} | ||
@@ -261,6 +234,4 @@ ``` | ||
### Scoped CSS | ||
## Scoped CSS | ||
> Experimental | ||
When a `<style>` tag has the `scoped` attribute, its CSS will apply to elements of the current component only. This is similar to the style encapsulation found in Shadow DOM, but doesn't require any polyfills. It is achieved by transforming the following: | ||
@@ -292,14 +263,12 @@ | ||
#### Notes | ||
### Scoped CSS Notes | ||
1. You can include both scoped and non-scoped styles in the same component. | ||
2. A child component's root node will be affected by both the parent's scoped CSS and the child's scoped CSS. | ||
2. The following will be affected by both the parent's scoped CSS and the child's scoped CSS: | ||
- A child component's root node | ||
- Content inserted to a child component via `<slot>` | ||
3. Partials are not affected by scoped styles. | ||
## Hot Reload | ||
### Hot Reload | ||
> Experimental | ||
To enable hot component reloading, you need to install the [browserify-hmr](https://github.com/AgentME/browserify-hmr) plugin: | ||
@@ -312,4 +281,27 @@ | ||
A full setup example with hot reloading is available at [vuejs/vueify-example](https://github.com/vuejs/vueify-example). | ||
You can scaffold a hot-reload enabled project easily using `vue-cli` and the [this template](https://github.com/vuejs-templates/browserify-simple-2.0). | ||
## CSS Extraction | ||
By default, the CSS in each component is injected into the page using a `<style>` tag. This works well in most scenarios and enables CSS hot-reloading during development. However, in some cases you may prefer extracting all component CSS into a single file for better performance. To do that, you will need to add the CSS extraction browserify plugin. | ||
Via CLI: | ||
``` bash | ||
browserify -t vueify -p [ vueify/plugins/extract-css -o dist/bundle.css ] main.js | ||
``` | ||
Via API: | ||
``` js | ||
browserify('./main.js') | ||
.transform('vueify') | ||
.plugin('vueify/plugins/extract-css', { | ||
out: 'dist/bundle.css' // can also be a WritableStream | ||
}) | ||
.bundle() | ||
``` | ||
This only works for vueify 9+. For Vue 1.x / vueify 8.x you can use [vueify-extract-css](https://github.com/rawcreative/vueify-extract-css). | ||
## Compiler API | ||
@@ -332,11 +324,5 @@ | ||
## Example | ||
For an example setup using most of the features mentioned above, see [vuejs/vueify-example](https://github.com/vuejs/vueify-example). | ||
If you use Webpack, there's also [vue-loader](https://github.com/vuejs/vue-loader) that does the same thing. | ||
## Changelog | ||
For version 9.0.0 and above, please see the [Releases](https://github.com/vuejs/vueify/releases) page for changes in each version. | ||
Please see the [Releases](https://github.com/vuejs/vueify/releases) page for changes in versions ^9.0.0. | ||
@@ -343,0 +329,0 @@ ## License |
37069
37
819
12
18
321
13
+ Addedconvert-source-map@^1.2.0
+ Addedsource-map@^0.5.6
+ Addedconvert-source-map@1.9.0(transitive)