├── .eslintrc ├── .gitignore ├── LICENSE ├── README.md ├── circle.yml ├── index.js ├── lib ├── compiler.js ├── compilers │ ├── babel.js │ ├── coffee.js │ ├── index.js │ ├── jade.js │ ├── less.js │ ├── pug.js │ ├── sass.js │ └── stylus.js ├── ensure-require.js ├── gen-id.js ├── insert-css.js ├── normalize.js ├── style-rewriter.js └── template-compiler.js ├── package.json ├── plugins └── extract-css.js └── test ├── fixtures ├── basic.vue ├── media-query.vue ├── postcss.vue ├── pre-processors.vue ├── pug.vue ├── scoped-css.vue ├── script-import.js ├── script-import.vue ├── style-export.vue ├── style-import-scoped.css ├── style-import.css ├── style-import.vue ├── template-import.jade └── template-import.vue └── test.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": "vue", 4 | "env": { 5 | "mocha": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | test/temp 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2016 Evan You 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # THIS REPOSITORY IS DEPRECATED 2 | 3 | > Note: We are concentrating our efforts on supporting webpack and rollup. 4 | 5 | ## 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) 6 | 7 | > [Browserify](http://browserify.org/) transform for [Vue.js](http://vuejs.org/) components, with scoped CSS and component hot-reloading. 8 | 9 | **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).** 10 | 11 | This transform allows you to write your components in this format: 12 | 13 | ``` html 14 | // app.vue 15 | 20 | 21 | 24 | 25 | 34 | ``` 35 | 36 | You can also mix preprocessor languages in the component file: 37 | 38 | ``` vue 39 | // app.vue 40 | 44 | 45 | 48 | 49 | 54 | ``` 55 | 56 | And you can import using the `src` attribute: 57 | 58 | ``` html 59 | 60 | ``` 61 | 62 | Under the hood, the transform will: 63 | 64 | - extract the styles, compile them and insert them with the `insert-css` module. 65 | - extract the template, compile it and add it to your exported options. 66 | 67 | You can `require()` other stuff in the ` 97 | 98 | ``` 99 | 100 | If you are using `vueify` in Node: 101 | 102 | ``` js 103 | var fs = require("fs") 104 | var browserify = require('browserify') 105 | var vueify = require('vueify') 106 | 107 | browserify('./main.js') 108 | .transform(vueify) 109 | .bundle() 110 | .pipe(fs.createWriteStream("bundle.js")) 111 | ``` 112 | 113 | ## Building for Production 114 | 115 | 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. 116 | 117 | If you are using Gulp, note that `gulp --production` **does not** affect vueify; you still need to explicitly set `NODE_ENV=production`. 118 | 119 | ## ES2015 with Babel 120 | 121 | Vueify is pre-configured to work with Babel. Simply install Babel-related dependencies: 122 | 123 | ``` bash 124 | npm install\ 125 | babel-core\ 126 | babel-preset-es2015\ 127 | --save-dev 128 | ``` 129 | 130 | Then create a `.babelrc`: 131 | 132 | ``` json 133 | { 134 | "presets": ["es2015"] 135 | } 136 | ``` 137 | 138 | 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). 139 | 140 | You can also configure babel with the `babel` field in `vue.config.js`, which will take the highest priority. 141 | 142 | ## Enabling Other Pre-Processors 143 | 144 | 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`. 145 | 146 | These are the preprocessors supported by vueify out of the box: 147 | 148 | - stylus 149 | - less 150 | - scss (via `node-sass`, use `sass` in [config section](#configuring-options)) 151 | - jade 152 | - pug 153 | - coffee-script (use `coffee` in [config section](#configuring-options)) 154 | 155 | ## PostCSS 156 | 157 | Vueify uses PostCSS for scoped CSS rewrite. You can also provide your own PostCSS plugins! See [config section](#configuring-options) below for an example. 158 | 159 | ## Configuring Options 160 | 161 | Create a `vue.config.js` file at where your build command is run (usually the root level of your project): 162 | 163 | ``` js 164 | module.exports = { 165 | // configure a built-in compiler 166 | sass: { 167 | includePaths: [...] 168 | }, 169 | // provide your own postcss plugins 170 | postcss: [...], 171 | // register custom compilers 172 | customCompilers: { 173 | // for tags with lang="ts" 174 | ts: function (content, cb, compiler, filePath) { 175 | // content: content extracted from lang="ts" blocks 176 | // cb: the callback to call when you're done compiling 177 | // compiler: the vueify compiler instance 178 | // filePath: the path for the file being compiled 179 | // 180 | // compile some TypeScript... and when you're done: 181 | cb(null, result) 182 | } 183 | } 184 | } 185 | ``` 186 | 187 | Example using custom PostCSS plugin: 188 | 189 | ``` js 190 | var cssnext = require('cssnext') 191 | 192 | module.exports = { 193 | postcss: [cssnext()] 194 | } 195 | ``` 196 | 197 | Alternatively, if you are using `vueify` in Node and don't want to create a `vue.config.js` file: 198 | 199 | ``` js 200 | var fs = require("fs") 201 | var browserify = require('browserify') 202 | var vueify = require('vueify') 203 | 204 | // apply custom config 205 | vueify.compiler.applyConfig({ 206 | // ...same as in vue.config.js 207 | }) 208 | 209 | browserify('./main.js') 210 | .transform(vueify) 211 | .bundle() 212 | .pipe(fs.createWriteStream("bundle.js")) 213 | ``` 214 | 215 | Or simply pass configuration object to `vueify` (in Node) (for instance to set sass search paths as in the following example): 216 | 217 | ``` js 218 | var fs = require("fs") 219 | var browserify = require('browserify') 220 | var vueify = require('vueify') 221 | 222 | browserify('./main.js') 223 | .transform(vueify, { 224 | sass: { 225 | includePaths: [...] 226 | }, 227 | // ...same as in vue.config.js 228 | }) 229 | .bundle() 230 | .pipe(fs.createWriteStream("bundle.js")) 231 | ``` 232 | 233 | ## Scoped CSS 234 | 235 | When a ` 243 | 246 | ``` 247 | 248 | Into the following: 249 | 250 | ``` html 251 | 256 | 259 | ``` 260 | 261 | ### Scoped CSS Notes 262 | 263 | 1. You can include both scoped and non-scoped styles in the same component. 264 | 265 | 2. The following will be affected by both the parent's scoped CSS and the child's scoped CSS: 266 | - A child component's root node 267 | - Content inserted to a child component via `` 268 | 269 | ## Hot Reload 270 | 271 | To enable hot component reloading, you need to install the [browserify-hmr](https://github.com/AgentME/browserify-hmr) plugin: 272 | 273 | ``` bash 274 | npm install browserify-hmr --save-dev 275 | watchify -p browserify-hmr index.js -o bundle.js 276 | ``` 277 | 278 | You can scaffold a hot-reload enabled project easily using `vue-cli` and the [this template](https://github.com/vuejs-templates/browserify-simple). 279 | 280 | ## CSS Extraction 281 | 282 | By default, the CSS in each component is injected into the page using a ` 20 | -------------------------------------------------------------------------------- /test/fixtures/media-query.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /test/fixtures/postcss.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /test/fixtures/pre-processors.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | 16 | 22 | 23 | 29 | 30 | 35 | -------------------------------------------------------------------------------- /test/fixtures/pug.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /test/fixtures/scoped-css.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/fixtures/script-import.js: -------------------------------------------------------------------------------- 1 | export default { 2 | data () { 3 | return { 4 | msg: 'Hello from Component A!' 5 | } 6 | } 7 | }; -------------------------------------------------------------------------------- /test/fixtures/script-import.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/style-export.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /test/fixtures/style-import-scoped.css: -------------------------------------------------------------------------------- 1 | h1 { color: green; } 2 | -------------------------------------------------------------------------------- /test/fixtures/style-import.css: -------------------------------------------------------------------------------- 1 | h1 { color: red; } 2 | -------------------------------------------------------------------------------- /test/fixtures/style-import.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /test/fixtures/template-import.jade: -------------------------------------------------------------------------------- 1 | div 2 | h1 hello 3 | -------------------------------------------------------------------------------- /test/fixtures/template-import.vue: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | process.env.VUEIFY_TEST = true 2 | 3 | const fs = require('fs') 4 | const path = require('path') 5 | const expect = require('chai').expect 6 | const rimraf = require('rimraf') 7 | const mkdirp = require('mkdirp') 8 | const browserify = require('browserify') 9 | const vueify = require('../index') 10 | const jsdom = require('jsdom') 11 | const vueCompiler = require('vue-template-compiler') 12 | const transpile = require('vue-template-es2015-compiler') 13 | const genId = require('../lib/gen-id') 14 | 15 | const tempDir = path.resolve(__dirname, './temp') 16 | const mockEntry = path.resolve(tempDir, 'entry.js') 17 | rimraf.sync(tempDir) 18 | mkdirp.sync(tempDir) 19 | 20 | function test (file, assert) { 21 | it(file, done => { 22 | fs.writeFileSync(mockEntry, 'window.vueModule = require("../fixtures/' + file + '.vue")') 23 | browserify(mockEntry) 24 | .transform(vueify) 25 | .bundle((err, buf) => { 26 | if (err) return done(err) 27 | jsdom.env({ 28 | html: '', 29 | src: [buf.toString()], 30 | done: (err, window) => { 31 | if (err) return done(err) 32 | assert(window) 33 | done() 34 | } 35 | }) 36 | }) 37 | }) 38 | } 39 | 40 | function testCssExtract (file, assert) { 41 | it(file, done => { 42 | fs.writeFileSync(mockEntry, 'window.vueModule = require("../fixtures/' + file + '.vue")') 43 | browserify(mockEntry) 44 | .transform(vueify) 45 | .plugin('./plugins/extract-css', { out: { write: assert, end: done }}) 46 | .bundle((err, buf) => { 47 | if (err) return done(err) 48 | }) 49 | }) 50 | } 51 | 52 | function assertRenderFn (options, template) { 53 | const compiled = vueCompiler.compile(template) 54 | expect(options.render.toString()).to.equal(transpile('function render() {' + compiled.render + '}')) 55 | } 56 | 57 | describe('vueify', () => { 58 | test('basic', window => { 59 | const module = window.vueModule 60 | assertRenderFn(module, '

{{msg}}

') 61 | expect(module.data().msg).to.contain('Hello from Component A!') 62 | const style = window.document.querySelector('style').textContent 63 | expect(style).to.contain('comp-a h2 {\n color: #f00;\n}') 64 | }) 65 | 66 | test('pre-processors', window => { 67 | var module = window.vueModule 68 | assertRenderFn(module, 69 | '
' + 70 | '

This is the app

' + 71 | '' + 72 | '' + 73 | '
' 74 | ) 75 | expect(module.data().msg).to.contain('Hello from coffee!') 76 | var style = window.document.querySelector('style').textContent 77 | // stylus 78 | expect(style).to.contain('body {\n font: 100% Helvetica, sans-serif;\n color: #999;\n}') 79 | // sass 80 | expect(style).to.contain('h1 {\n color: red;') 81 | // less 82 | expect(style).to.contain('h1 {\n color: green;') 83 | }) 84 | 85 | test('pug', window => { 86 | var module = window.vueModule 87 | assertRenderFn(module, 88 | '
' + 89 | '

This is the app

' + 90 | '' + 91 | '' + 92 | '
' 93 | ) 94 | }) 95 | 96 | test('scoped-css', window => { 97 | var module = window.vueModule 98 | var id = 'data-v-' + genId(require.resolve('./fixtures/scoped-css.vue')) 99 | expect(module._scopeId).to.equal(id) 100 | assertRenderFn(module, 101 | '
' + 102 | '

hi

\n' + 103 | '

hi

\n' + 104 | '\n' + 105 | '

' + 106 | '
' 107 | ) 108 | var style = window.document.querySelector('style').textContent 109 | expect(style).to.contain('.test[' + id + '] {\n color: yellow;\n}') 110 | expect(style).to.contain('.test[' + id + ']:after {\n content: \'bye!\';\n}') 111 | expect(style).to.contain('h1[' + id + '] {\n color: green;\n}') 112 | }) 113 | 114 | test('style-import', window => { 115 | var styles = window.document.querySelectorAll('style') 116 | expect(styles[0].textContent).to.contain('h1 { color: red; }') 117 | // import with scoped 118 | var id = 'data-v-' + genId(require.resolve('./fixtures/style-import.vue')) 119 | expect(styles[0].textContent).to.contain('h1[' + id + '] { color: green; }') 120 | }) 121 | 122 | test('template-import', window => { 123 | var module = window.vueModule 124 | assertRenderFn(module, '

hello

') 125 | }) 126 | 127 | test('script-import', window => { 128 | var module = window.vueModule 129 | expect(module.data().msg).to.contain('Hello from Component A!') 130 | }) 131 | 132 | test('media-query', window => { 133 | var style = window.document.querySelector('style').textContent 134 | var id = 'data-v-' + genId(require.resolve('./fixtures/media-query.vue')) 135 | expect(style).to.contain('@media print {\n .foo[' + id + '] {\n color: #000;\n }\n}') 136 | }) 137 | 138 | testCssExtract('style-export', css => { 139 | expect(css).to.equal('h2 {color: red;}') 140 | }) 141 | }) 142 | --------------------------------------------------------------------------------