diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 000000000..31346ac39 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,25 @@ +module.exports = function (config) { + config.set({ + preprocessors: { + '**/*.vue': ['webpack', 'sourcemap'] + }, + webpack: { + devtool: 'inline-source-map', + module: { + loaders: [ + { test: /\.vue$/, loader: './index.js' } + ] + } + }, + frameworks: ['mocha', 'chai'], + files: ['test/*.vue'], + plugins: [ + require('karma-webpack'), + require('karma-mocha'), + require('karma-chai'), + require('karma-chrome-launcher'), + require('karma-phantomjs-launcher'), + require('karma-sourcemap-loader') + ] + }) +} diff --git a/lib/loader.js b/lib/loader.js index 695c3265b..4427702e9 100644 --- a/lib/loader.js +++ b/lib/loader.js @@ -144,6 +144,7 @@ module.exports = function (content) { var parts = parse(content, fileName, this.sourceMap) var hasLocalStyles = false var output = 'var __vue_script__, __vue_template__\n' + var testOutput = '' // check if there are any template syntax errors var templateWarnings = parts.template.length && parts.template[0].warnings @@ -163,29 +164,60 @@ module.exports = function (content) { output += getRequire('style', style, i, style.scoped) }) - // add require for script - var script - if (parts.script.length) { - script = parts.script[0] - output += - '__vue_script__ = ' + ( - script.src - ? getRequireForImport('script', script, 0) - : getRequire('script', script, 0) - ) - // check and warn named exports - if (!this.minimize) { + // add requires for scripts + var hasScript = false + parts.script.forEach(function (script, i) { + if (script.test === undefined) { + if (hasScript) { + throw new Error( + '[vue-loader] Only one diff --git a/test/basic.vue b/test/basic.vue new file mode 100644 index 000000000..d2bc71898 --- /dev/null +++ b/test/basic.vue @@ -0,0 +1,31 @@ + + + + + + diff --git a/test/fixtures/autoprefix.vue b/test/fixtures/autoprefix.vue deleted file mode 100644 index a5308b2e0..000000000 --- a/test/fixtures/autoprefix.vue +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/test/fixtures/basic.vue b/test/fixtures/basic.vue deleted file mode 100644 index 5035c8304..000000000 --- a/test/fixtures/basic.vue +++ /dev/null @@ -1,19 +0,0 @@ - - - - - diff --git a/test/fixtures/pre.vue b/test/fixtures/pre.vue deleted file mode 100644 index 2eafdb4fd..000000000 --- a/test/fixtures/pre.vue +++ /dev/null @@ -1,19 +0,0 @@ - - - - - diff --git a/test/fixtures/script-import.vue b/test/fixtures/script-import.vue deleted file mode 100644 index b45d1ec73..000000000 --- a/test/fixtures/script-import.vue +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/test/fixtures/template-import.vue b/test/fixtures/template-import.vue deleted file mode 100644 index ce534539b..000000000 --- a/test/fixtures/template-import.vue +++ /dev/null @@ -1 +0,0 @@ - diff --git a/test/karma.vue b/test/karma.vue new file mode 100644 index 000000000..fbb891237 --- /dev/null +++ b/test/karma.vue @@ -0,0 +1,27 @@ + + + + + + diff --git a/test/preprocessors.vue b/test/preprocessors.vue new file mode 100644 index 000000000..a7e7cd3ed --- /dev/null +++ b/test/preprocessors.vue @@ -0,0 +1,36 @@ + + + + + + + diff --git a/test/script-import.vue b/test/script-import.vue new file mode 100644 index 000000000..a39d112b8 --- /dev/null +++ b/test/script-import.vue @@ -0,0 +1,10 @@ + + + diff --git a/test/template-import.vue b/test/template-import.vue new file mode 100644 index 000000000..8b5ca968c --- /dev/null +++ b/test/template-import.vue @@ -0,0 +1,10 @@ + + + diff --git a/test/test.js b/test/test.js index 959ab05d5..2f4936d4f 100644 --- a/test/test.js +++ b/test/test.js @@ -8,6 +8,40 @@ var hash = require('hash-sum') var SourceMapConsumer = require('source-map').SourceMapConsumer var ExtractTextPlugin = require("extract-text-webpack-plugin") +describe('vue-loader lowlevel', function () { + var loader + before(function () { + loader = require('../lib/loader.js').bind({ + cacheable: function () {}, + options: {}, + emitError: function (e) { throw e }, + resourcePath: "./test.vue" + }) + }) + + it('template', function () { + var result = loader('') + expect(result).to.match(/__vue_template__ = require\("!!vue-html-loader.+selector\.js\?type=template&index=0!\.\/test\.vue"\)/g) + }) + it('script', function () { + var result = loader('') + expect(result).to.match(/__vue_script__ = require\("!!babel-loader.+selector\.js\?type=script&index=0!\.\/test\.vue"\)/g) + }) + it('script test', function () { + var result = loader('') + expect(result).to.match(/\nrequire\("!!.+selector\.js\?type=script&index=0!\.\/test\.vue"\)/g) + }) + it('script test karma', function () { + var result = loader('') + expect(result).to.match(/\nif \(window\._karma__ !== "null"\) {/g) + }) + it('style', function () { + var result = loader('') + expect(result).to.match(/\nrequire\("!!vue-style-loader.+selector\.js\?type=style&index=0!\.\/test\.vue"\)/g) + }) +}) + + describe('vue-loader', function () { var testHTML = '' @@ -34,7 +68,7 @@ describe('vue-loader', function () { function getFile (file, cb) { fs.readFile(path.resolve(outputDir, file), 'utf-8', function (err, data) { - expect(err).to.be.not.exist + expect(err).to.not.exist cb(data) }) } @@ -64,36 +98,6 @@ describe('vue-loader', function () { }) } - it('basic', function (done) { - test({ - entry: './test/fixtures/basic.vue' - }, function (window) { - var module = window.vueModule - expect(module.template).to.contain('

{{msg}}

') - expect(module.data().msg).to.contain('Hello from Component A!') - var style = window.document.querySelector('style').textContent - expect(style).to.contain('comp-a h2 {\n color: #f00;\n}') - done() - }) - }) - - it('pre-processors', function (done) { - test({ - entry: './test/fixtures/pre.vue' - }, function (window) { - var module = window.vueModule - expect(module.template).to.contain( - '

This is the app

' + - '' + - '' - ) - expect(module.data().msg).to.contain('Hello from coffee!') - var style = window.document.querySelector('style').textContent - expect(style).to.contain('body {\n font: 100% Helvetica, sans-serif;\n color: #999;\n}') - done() - }) - }) - it('scoped style', function (done) { test({ entry: './test/fixtures/scoped-css.vue' @@ -127,29 +131,9 @@ describe('vue-loader', function () { }) }) - it('template import', function (done) { - test({ - entry: './test/fixtures/template-import.vue' - }, function (window) { - var module = window.vueModule - expect(module.template).to.contain('

hello

') - done() - }) - }) - - it('script import', function (done) { - test({ - entry: './test/fixtures/script-import.vue' - }, function (window) { - var module = window.vueModule - expect(module.data().msg).to.contain('Hello from Component A!') - done() - }) - }) - it('source map', function (done) { var config = Object.assign({}, globalConfig, { - entry: './test/fixtures/basic.vue', + entry: './test/preprocessors.vue', devtool: 'source-map' }) webpack(config, function (err) { @@ -157,9 +141,8 @@ describe('vue-loader', function () { getFile('test.build.js.map', function (map) { var smc = new SourceMapConsumer(JSON.parse(map)) getFile('test.build.js', function (code) { - var line - var col - var targetRE = /^\s+msg: 'Hello from Component A!'/ + var line, col + var targetRE = /^\s+msg: 'Hello from coffee!'/ code.split(/\r?\n/g).some(function (l, i) { if (targetRE.test(l)) { line = i + 1 @@ -171,24 +154,14 @@ describe('vue-loader', function () { line: line, column: col }) - expect(pos.source.indexOf('basic.vue') > -1) - expect(pos.line).to.equal(9) + expect(pos.source.indexOf('preprocessors.vue') > -1) + expect(pos.line).to.equal(18) done() }) }) }) }) - it('autoprefix', function (done) { - test({ - entry: './test/fixtures/autoprefix.vue' - }, function (window) { - var style = window.document.querySelector('style').textContent - expect(style).to.contain('body {\n -webkit-transform: scale(1);\n transform: scale(1);\n}') - done() - }) - }) - it('media-query', function (done) { test({ entry: './test/fixtures/media-query.vue' @@ -202,6 +175,7 @@ describe('vue-loader', function () { it('extract CSS', function (done) { webpack(Object.assign({}, globalConfig, { + devtool: 'source-map', entry: './test/fixtures/extract-css.vue', vue: { loaders: { @@ -215,8 +189,26 @@ describe('vue-loader', function () { }), function (err) { expect(err).to.be.null getFile('test.output.css', function (data) { - expect(data).to.contain('h1 {\n color: #f00;\n}\n\nh2 {\n color: green;\n}') - done() + expect(data).to.contain('h1 {\n color: #f00;\n}\n\n\n\n\n\n\nh2 {\n color: green;\n}') + getFile('test.output.css.map', function (map) { + var smc = new SourceMapConsumer(JSON.parse(map)) + var line, col + var targetRE = /^\s+color: #f00;/ + data.split(/\r?\n/g).some(function (l, i) { + if (targetRE.test(l)) { + line = i + 1 + col = l.length + return true + } + }) + var pos = smc.originalPositionFor({ + line: line, + column: col + }) + expect(pos.source.indexOf('extract-css.vue') > -1) + expect(pos.line).to.equal(3) + done() + }) }) }) })