diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..0a918b9 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,7 @@ +{ + "root": true, + "extends": "vue", + "env": { + "mocha": true + } +} diff --git a/.gitignore b/.gitignore index 91dfed8..6218a0b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store -node_modules \ No newline at end of file +node_modules +test/temp diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..231a94b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2016 Evan You + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md index c842f69..9a42c15 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,13 @@ -# 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) +# THIS REPOSITORY IS DEPRECATED + +> Note: We are concentrating our efforts on supporting webpack and rollup. + +## 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) > [Browserify](http://browserify.org/) transform for [Vue.js](http://vuejs.org/) components, with scoped CSS and component hot-reloading. +**NOTE: master branch now hosts version ^9.0, which only works with Vue ^2.0. Vueify 8.x which works with Vue 1.x is in the [8.x branch](https://github.com/vuejs/vueify/tree/8.x).** + This transform allows you to write your components in this format: ``` html @@ -17,13 +23,13 @@ This transform allows you to write your components in this format: ``` @@ -58,7 +64,7 @@ Under the hood, the transform will: - extract the styles, compile them and insert them with the `insert-css` module. - extract the template, compile it and add it to your exported options. -You can `require()` other stuff in the ` ``` @@ -108,55 +104,57 @@ var fs = require("fs") var browserify = require('browserify') var vueify = require('vueify') -browserify('./entry.js') +browserify('./main.js') .transform(vueify) .bundle() .pipe(fs.createWriteStream("bundle.js")) ``` -## ES2015 by Default +## Building for Production -Vueify automatically transforms the JavaScript in your `*.vue` components using Babel. Write ES2015 today! +Make sure to have the `NODE_ENV` environment variable set to `"production"` when building for production! This strips away unnecessary code (e.g. hot-reload) for smaller bundle size. -The default Babel (6) options used for Vue.js components are: +If you are using Gulp, note that `gulp --production` **does not** affect vueify; you still need to explicitly set `NODE_ENV=production`. -``` js -{ - presets: ['es2015'], - plugins: ['transform-runtime'] -} +## ES2015 with Babel + +Vueify is pre-configured to work with Babel. Simply install Babel-related dependencies: + +``` 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: - stylus - less -- scss (via `node-sass`) +- scss (via `node-sass`, use `sass` in [config section](#configuring-options)) - jade -- coffee-script - -## 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. +- pug +- coffee-script (use `coffee` in [config section](#configuring-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. ## Configuring Options @@ -170,20 +168,16 @@ module.exports = { }, // provide your own postcss plugins 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 customCompilers: { // for tags with lang="ts" - ts: function (content, cb) { - // compile some TypeScript... + ts: function (content, cb, compiler, filePath) { + // content: content extracted from lang="ts" blocks + // cb: the callback to call when you're done compiling + // compiler: the vueify compiler instance + // filePath: the path for the file being compiled + // + // compile some TypeScript... and when you're done: cb(null, result) } } @@ -196,9 +190,7 @@ Example using custom PostCSS plugin: var cssnext = require('cssnext') module.exports = { - postcss: [cssnext()], - // disable autoprefixer since cssnext comes with it - autoprefixer: false + postcss: [cssnext()] } ``` @@ -214,15 +206,31 @@ vueify.compiler.applyConfig({ // ...same as in vue.config.js }) -browserify('./entry.js') +browserify('./main.js') .transform(vueify) .bundle() .pipe(fs.createWriteStream("bundle.js")) ``` -### Scoped CSS +Or simply pass configuration object to `vueify` (in Node) (for instance to set sass search paths as in the following example): -> Experimental +``` js +var fs = require("fs") +var browserify = require('browserify') +var vueify = require('vueify') + +browserify('./main.js') + .transform(vueify, { + sass: { + includePaths: [...] + }, + // ...same as in vue.config.js + }) + .bundle() + .pipe(fs.createWriteStream("bundle.js")) +``` + +## Scoped CSS When a ` diff --git a/test/fixtures/basic.vue b/test/fixtures/basic.vue index 0bce21e..5dce8c7 100644 --- a/test/fixtures/basic.vue +++ b/test/fixtures/basic.vue @@ -1,24 +1,19 @@ - - + + diff --git a/test/fixtures/custom.vue b/test/fixtures/custom.vue deleted file mode 100644 index e5a016e..0000000 --- a/test/fixtures/custom.vue +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/test/fixtures/empty.vue b/test/fixtures/empty.vue deleted file mode 100644 index e69de29..0000000 diff --git a/test/fixtures/imports/import.less b/test/fixtures/imports/import.less deleted file mode 100644 index 6679fe0..0000000 --- a/test/fixtures/imports/import.less +++ /dev/null @@ -1 +0,0 @@ -@base: #f938ab; diff --git a/test/fixtures/imports/import.sass b/test/fixtures/imports/import.sass deleted file mode 100644 index 6fb403e..0000000 --- a/test/fixtures/imports/import.sass +++ /dev/null @@ -1,2 +0,0 @@ -$font-stack: Helvetica, sans-serif; -$primary-color: #333; diff --git a/test/fixtures/imports/import.styl b/test/fixtures/imports/import.styl deleted file mode 100644 index b08b59b..0000000 --- a/test/fixtures/imports/import.styl +++ /dev/null @@ -1,2 +0,0 @@ -$font-stack = Helvetica, sans-serif; -$primary-color = #333 diff --git a/test/fixtures/jade.vue b/test/fixtures/jade.vue deleted file mode 100644 index 5b44d98..0000000 --- a/test/fixtures/jade.vue +++ /dev/null @@ -1,11 +0,0 @@ - \ No newline at end of file diff --git a/test/fixtures/less.vue b/test/fixtures/less.vue deleted file mode 100644 index 060a45a..0000000 --- a/test/fixtures/less.vue +++ /dev/null @@ -1,17 +0,0 @@ - diff --git a/test/fixtures/media-query.vue b/test/fixtures/media-query.vue new file mode 100644 index 0000000..9dbe0ee --- /dev/null +++ b/test/fixtures/media-query.vue @@ -0,0 +1,7 @@ + diff --git a/test/fixtures/multiple-scripts.vue b/test/fixtures/multiple-scripts.vue deleted file mode 100644 index 1ae4119..0000000 --- a/test/fixtures/multiple-scripts.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/test/fixtures/multiple-styles.vue b/test/fixtures/multiple-styles.vue deleted file mode 100644 index 71496f9..0000000 --- a/test/fixtures/multiple-styles.vue +++ /dev/null @@ -1,18 +0,0 @@ - - - - - \ No newline at end of file diff --git a/test/fixtures/multiple.vue b/test/fixtures/multiple.vue deleted file mode 100644 index 1bfbc94..0000000 --- a/test/fixtures/multiple.vue +++ /dev/null @@ -1,33 +0,0 @@ - - - - - \ No newline at end of file diff --git a/test/fixtures/non-minified.vue b/test/fixtures/non-minified.vue deleted file mode 100644 index 0e9ecd0..0000000 --- a/test/fixtures/non-minified.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/test/fixtures/postcss.vue b/test/fixtures/postcss.vue new file mode 100644 index 0000000..a02d550 --- /dev/null +++ b/test/fixtures/postcss.vue @@ -0,0 +1,5 @@ + diff --git a/test/fixtures/pre-processors.vue b/test/fixtures/pre-processors.vue new file mode 100644 index 0000000..f59787e --- /dev/null +++ b/test/fixtures/pre-processors.vue @@ -0,0 +1,34 @@ + + + + + + + + + diff --git a/test/fixtures/pug.vue b/test/fixtures/pug.vue new file mode 100644 index 0000000..5a43989 --- /dev/null +++ b/test/fixtures/pug.vue @@ -0,0 +1,6 @@ + diff --git a/test/fixtures/sass.vue b/test/fixtures/sass.vue deleted file mode 100644 index 3930c28..0000000 --- a/test/fixtures/sass.vue +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/test/fixtures/scoped-css.vue b/test/fixtures/scoped-css.vue new file mode 100644 index 0000000..ce28b06 --- /dev/null +++ b/test/fixtures/scoped-css.vue @@ -0,0 +1,20 @@ + + + + + diff --git a/test/fixtures/scoped.vue b/test/fixtures/scoped.vue deleted file mode 100644 index d30a9c0..0000000 --- a/test/fixtures/scoped.vue +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/test/fixtures/script-import.js b/test/fixtures/script-import.js new file mode 100644 index 0000000..8ab2015 --- /dev/null +++ b/test/fixtures/script-import.js @@ -0,0 +1,7 @@ +export default { + data () { + return { + msg: 'Hello from Component A!' + } + } +}; \ No newline at end of file diff --git a/test/fixtures/script-import.vue b/test/fixtures/script-import.vue new file mode 100644 index 0000000..b45d1ec --- /dev/null +++ b/test/fixtures/script-import.vue @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/fixtures/src.vue b/test/fixtures/src.vue deleted file mode 100644 index 37d642b..0000000 --- a/test/fixtures/src.vue +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/test/fixtures/src/test.js b/test/fixtures/src/test.js deleted file mode 100644 index dce344e..0000000 --- a/test/fixtures/src/test.js +++ /dev/null @@ -1,3 +0,0 @@ -export default { - el: '#hi' -} diff --git a/test/fixtures/styl.vue b/test/fixtures/styl.vue deleted file mode 100644 index b24d35a..0000000 --- a/test/fixtures/styl.vue +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/test/fixtures/style-export.vue b/test/fixtures/style-export.vue new file mode 100644 index 0000000..c3311de --- /dev/null +++ b/test/fixtures/style-export.vue @@ -0,0 +1,3 @@ + diff --git a/test/fixtures/style-import-scoped.css b/test/fixtures/style-import-scoped.css new file mode 100644 index 0000000..954b5d8 --- /dev/null +++ b/test/fixtures/style-import-scoped.css @@ -0,0 +1 @@ +h1 { color: green; } diff --git a/test/fixtures/style-import.css b/test/fixtures/style-import.css new file mode 100644 index 0000000..5ce768c --- /dev/null +++ b/test/fixtures/style-import.css @@ -0,0 +1 @@ +h1 { color: red; } diff --git a/test/fixtures/style-import.vue b/test/fixtures/style-import.vue new file mode 100644 index 0000000..54b83bf --- /dev/null +++ b/test/fixtures/style-import.vue @@ -0,0 +1,2 @@ + + diff --git a/test/fixtures/template-import.jade b/test/fixtures/template-import.jade new file mode 100644 index 0000000..bc60abf --- /dev/null +++ b/test/fixtures/template-import.jade @@ -0,0 +1,2 @@ +div + h1 hello diff --git a/test/fixtures/template-import.vue b/test/fixtures/template-import.vue new file mode 100644 index 0000000..ce53453 --- /dev/null +++ b/test/fixtures/template-import.vue @@ -0,0 +1 @@ + diff --git a/test/fixtures/test.html b/test/fixtures/test.html deleted file mode 100644 index 67326d3..0000000 --- a/test/fixtures/test.html +++ /dev/null @@ -1 +0,0 @@ -

hi

\ No newline at end of file diff --git a/test/fixtures/test.styl b/test/fixtures/test.styl deleted file mode 100644 index c6fe265..0000000 --- a/test/fixtures/test.styl +++ /dev/null @@ -1,2 +0,0 @@ -h1 - font-size 12px \ No newline at end of file diff --git a/test/test.js b/test/test.js index 202799a..dfcf92a 100644 --- a/test/test.js +++ b/test/test.js @@ -1,75 +1,141 @@ -var fs = require('fs') -var path = require('path') -var compiler = require('../lib/compiler') -var assert = require('assert') -var hash = require('hash-sum') +process.env.VUEIFY_TEST = true -// test custom transform -compiler.applyConfig({ - customCompilers: { - test: function (content, cb) { - content = content.replace('not ', '') - cb(null, content) - } - } -}) +const fs = require('fs') +const path = require('path') +const expect = require('chai').expect +const rimraf = require('rimraf') +const mkdirp = require('mkdirp') +const browserify = require('browserify') +const vueify = require('../index') +const jsdom = require('jsdom') +const vueCompiler = require('vue-template-compiler') +const transpile = require('vue-template-es2015-compiler') +const genId = require('../lib/gen-id') -function read (file) { - return fs.readFileSync(path.resolve(__dirname, file), 'utf-8') -} +const tempDir = path.resolve(__dirname, './temp') +const mockEntry = path.resolve(tempDir, 'entry.js') +rimraf.sync(tempDir) +mkdirp.sync(tempDir) -function test (name) { - it(name, function (done) { - var filePath = 'fixtures/' + name + '.vue' - var fileContent = read(filePath) - var expected = read('expects/' + name + '.js') - .replace(/\{\{id\}\}/g, '_v-' + hash(require.resolve('./' + filePath))) +function test (file, assert) { + it(file, done => { + fs.writeFileSync(mockEntry, 'window.vueModule = require("../fixtures/' + file + '.vue")') + browserify(mockEntry) + .transform(vueify) + .bundle((err, buf) => { + if (err) return done(err) + jsdom.env({ + html: '', + src: [buf.toString()], + done: (err, window) => { + if (err) return done(err) + assert(window) + done() + } + }) + }) + }) +} - // test registering dependency - var deps = [] - function addDep (file) { - deps.push(file) - } - compiler.on('dependency', addDep) +function testCssExtract (file, assert) { + it(file, done => { + fs.writeFileSync(mockEntry, 'window.vueModule = require("../fixtures/' + file + '.vue")') + browserify(mockEntry) + .transform(vueify) + .plugin('./plugins/extract-css', { out: { write: assert, end: done }}) + .bundle((err, buf) => { + if (err) return done(err) + }) + }) +} - process.env.VUEIFY_TEST = true - process.env.NODE_ENV = name === 'non-minified' - ? 'development' - : 'production' +function assertRenderFn (options, template) { + const compiled = vueCompiler.compile(template) + expect(options.render.toString()).to.equal(transpile('function render() {' + compiled.render + '}')) +} - compiler.compile( - fileContent, - path.resolve(__dirname, filePath), - function (err, result) { - // the cb is handled by a Promise, so the assertion - // errors gets swallowed and the test never fails. - // do it in a separate tick. - setTimeout(function () { - if (err) throw err - assert.equal(result, expected, 'should compile correctly') +describe('vueify', () => { + test('basic', window => { + const module = window.vueModule + assertRenderFn(module, '

{{msg}}

') + expect(module.data().msg).to.contain('Hello from Component A!') + const style = window.document.querySelector('style').textContent + expect(style).to.contain('comp-a h2 {\n color: #f00;\n}') + }) - // check src - if (name === 'src') { - assert.equal(deps[0], __dirname + '/fixtures/test.html') - assert.equal(deps[1], __dirname + '/fixtures/test.styl') - assert.equal(deps[2], __dirname + '/fixtures/src/test.js') - } + test('pre-processors', window => { + var module = window.vueModule + assertRenderFn(module, + '
' + + '

This is the app

' + + '' + + '' + + '
' + ) + expect(module.data().msg).to.contain('Hello from coffee!') + var style = window.document.querySelector('style').textContent + // stylus + expect(style).to.contain('body {\n font: 100% Helvetica, sans-serif;\n color: #999;\n}') + // sass + expect(style).to.contain('h1 {\n color: red;') + // less + expect(style).to.contain('h1 {\n color: green;') + }) - if (name === 'less' || name === 'sass' || name === 'styl') { - assert.equal(deps[0], __dirname + '/fixtures/imports/import.' + name) - } + test('pug', window => { + var module = window.vueModule + assertRenderFn(module, + '
' + + '

This is the app

' + + '' + + '' + + '
' + ) + }) - compiler.removeListener('dependency', addDep) - done() - }, 0) - } + test('scoped-css', window => { + var module = window.vueModule + var id = 'data-v-' + genId(require.resolve('./fixtures/scoped-css.vue')) + expect(module._scopeId).to.equal(id) + assertRenderFn(module, + '
' + + '

hi

\n' + + '

hi

\n' + + '\n' + + '

' + + '
' ) + var style = window.document.querySelector('style').textContent + expect(style).to.contain('.test[' + id + '] {\n color: yellow;\n}') + expect(style).to.contain('.test[' + id + ']:after {\n content: \'bye!\';\n}') + expect(style).to.contain('h1[' + id + '] {\n color: green;\n}') + }) + + test('style-import', window => { + var styles = window.document.querySelectorAll('style') + expect(styles[0].textContent).to.contain('h1 { color: red; }') + // import with scoped + var id = 'data-v-' + genId(require.resolve('./fixtures/style-import.vue')) + expect(styles[0].textContent).to.contain('h1[' + id + '] { color: green; }') + }) + + test('template-import', window => { + var module = window.vueModule + assertRenderFn(module, '

hello

') + }) + + test('script-import', window => { + var module = window.vueModule + expect(module.data().msg).to.contain('Hello from Component A!') }) -} -describe('Vueify compiler', function () { - fs.readdirSync(path.resolve(__dirname, 'expects')) - .forEach(function (file) { - test(path.basename(file, '.js')) - }) + test('media-query', window => { + var style = window.document.querySelector('style').textContent + var id = 'data-v-' + genId(require.resolve('./fixtures/media-query.vue')) + expect(style).to.contain('@media print {\n .foo[' + id + '] {\n color: #000;\n }\n}') + }) + + testCssExtract('style-export', css => { + expect(css).to.equal('h2 {color: red;}') + }) })