Webpack: Unit tests fail on separation of html from vue file

Created on 18 Feb 2017  Â·  13Comments  Â·  Source: vuejs-templates/webpack

Setup

|Module|Version|
|----------|----------|
|Node.js|6.9.2|
|npm|4.3|
|vue-cli|2.8.1|
|vue|2.1.10|
|webpack|2.2.1|
|babel|6.22|

Issue details

Took a fresh copy of the webpack template and moved the html in vue file to different file:

<!-- src/components/Hello.vue -->
<template src="./hello.html">

</template>

<script>
export default {
  name: 'hello',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}

ul {
  list-style-type: none;
  padding: 0;
}

li {
  display: inline-block;
  margin: 0 10px;
}

a {
  color: #42b983;
}
</style>

<!-- src/components/hello.html -->
<div class="hello">
    <h1>{{ msg }}</h1>
    <h2>Essential Links</h2>
    <ul>
        <li><a href="https://vuejs.org" target="_blank">Core Docs</a></li>
        <li><a href="https://forum.vuejs.org" target="_blank">Forum</a></li>
        <li><a href="https://gitter.im/vuejs/vue" target="_blank">Gitter Chat</a></li>
        <li><a href="https://twitter.com/vuejs" target="_blank">Twitter</a></li>
        <br>
        <li><a href="http://vuejs-templates.github.io/webpack/" target="_blank">Docs for This Template</a></li>
    </ul>
    <h2>Ecosystem</h2>
    <ul>
        <li><a href="http://router.vuejs.org/" target="_blank">vue-router</a></li>
        <li><a href="http://vuex.vuejs.org/" target="_blank">vuex</a></li>
        <li><a href="http://vue-loader.vuejs.org/" target="_blank">vue-loader</a></li>
        <li><a href="https://github.com/vuejs/awesome-vue" target="_blank">awesome-vue</a></li>
    </ul>
</div>

While running webpack, we get the warning:

WARNING in ./src/components/hello.html
Module parse failed: /home/suhas/Projects/mycode/vue-test/src/components/hello.html Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
| <div class="hello">
|     <h1>{{ msg }}</h1>
|     <h2>Essential Links</h2>
 @ ./src ^\.\/(?!main(\.js)?$)
 @ ./test/unit/index.js

We also get a warning WARN [reporter]: SourceMap position not found for trace: undefined


Complete npm run unit output

> [email protected] unit /home/suhas/Projects/mycode/vue-test
> cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run

Hash: b9f5465a9c850274ab28
Version: webpack 2.2.1
Time: 1844ms
   Asset    Size  Chunks                    Chunk Names
index.js  680 kB       0  [emitted]  [big]  index.js
chunk    {0} index.js (index.js) 253 kB [entry] [rendered]
    [0] ./src/components/Hello.vue 1.45 kB {0} [built]
    [1] ./src/router/index.js 1.12 kB {0} [optional] [built]
    [3] ./src/assets/logo.png 9.17 kB {0} [built]
    [4] ./src/App.vue 1.46 kB {0} [optional] [built]
    [7] ./~/vue/dist/vue.runtime.common.js 162 kB {0} [built]
    [8] ./~/function-bind/index.js 111 bytes {0} [built]
    [9] ./src ^\.\/(?!main(\.js)?$) 325 bytes {0} [built]
   [10] ./test/unit/specs \.spec$ 177 bytes {0} [built]
   [11] ./test/unit/specs/Hello.spec.js 344 bytes {0} [optional] [built]
   [16] ./~/function-bind/implementation.js 1.42 kB {0} [built]
   [18] ./~/vue-loader/lib/template-compiler.js?id=data-v-4c74d97c!./src/components/hello.html 2.13 kB {0} [built]
   [20] ./~/vue-style-loader!./~/css-loader!./~/vue-loader/lib/style-rewriter.js?id=data-v-0da8b164!./~/vue-loader/lib/selector.js?type=styles&index=0!./src/App.vue 1.34 kB {0} [built]
   [21] ./~/vue-style-loader!./~/css-loader!./~/vue-loader/lib/style-rewriter.js?id=data-v-4c74d97c&scoped=true!./~/vue-loader/lib/selector.js?type=styles&index=0!./src/components/Hello.vue 1.42 kB {0} [built]
   [24] ./src/components/hello.html 271 bytes {0} [optional] [built] [failed] [1 error]
   [25] ./test/unit/index.js 272 bytes {0} [built]
     + 11 hidden modules

WARNING in ./src/components/hello.html
Module parse failed: /home/suhas/Projects/mycode/vue-test/src/components/hello.html Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
| <div class="hello">
|     <h1>{{ msg }}</h1>
|     <h2>Essential Links</h2>
 @ ./src ^\.\/(?!main(\.js)?$)
 @ ./test/unit/index.js
18 02 2017 12:52:26.501:INFO [karma]: Karma v1.4.1 server started at http://0.0.0.0:9876/
18 02 2017 12:52:26.503:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
18 02 2017 12:52:26.510:INFO [launcher]: Starting browser PhantomJS
18 02 2017 12:52:26.803:INFO [PhantomJS 2.1.1 (Linux 0.0.0)]: Connected on socket xeNY1WDvg0BIH7BZAAAA with id 58691659
PhantomJS 2.1.1 (Linux 0.0.0) INFO LOG: 'You are running Vue in development mode.
Make sure to turn on production mode when deploying for production.
See more tips at https://vuejs.org/guide/deployment.html'
18 02 2017 12:52:26.947:WARN [reporter]: SourceMap position not found for trace: undefined
PhantomJS 2.1.1 (Linux 0.0.0) ERROR
  Error: Module parse failed: /home/suhas/Projects/mycode/vue-test/src/components/hello.html Unexpected token (1:0)
  You may need an appropriate loader to handle this file type.
  | <div class="hello">
  |     <h1>{{ msg }}</h1>
  |     <h2>Essential Links</h2>
  at index.js:9538

PhantomJS 2.1.1 (Linux 0.0.0): Executed 0 of 0 ERROR (0.148 secs / 0 secs)


Expected output

> [email protected] unit /home/suhas/Projects/mycode/vue-test
> cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run

18 02 2017 13:08:00.221:INFO [karma]: Karma v1.4.1 server started at http://0.0.0.0:9876/
18 02 2017 13:08:00.224:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
18 02 2017 13:08:00.230:INFO [launcher]: Starting browser PhantomJS
18 02 2017 13:08:00.487:INFO [PhantomJS 2.1.1 (Linux 0.0.0)]: Connected on socket bu5qnN7DoGOrxJ62AAAA with id 59329966
PhantomJS 2.1.1 (Linux 0.0.0) INFO LOG: 'You are running Vue in development mode.
Make sure to turn on production mode when deploying for production.
See more tips at https://vuejs.org/guide/deployment.html'

  Hello.vue
    ✓ should render correct contents

PhantomJS 2.1.1 (Linux 0.0.0): Executed 1 of 1 SUCCESS (0.001 secs / 0.006 secs)
TOTAL: 1 SUCCESS


=============================== Coverage summary ===============================
Statements   : 100% ( 2/2 )
Branches     : 100% ( 0/0 )
Functions    : 100% ( 0/0 )
Lines        : 100% ( 2/2 )
================================================================================

bug good first contribution

Most helpful comment

Thanks for the hint, @Hanruis - the following adjustment in /test/unit/index.js (line 12) resolved the HTML import problems for me:

const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)(?!.+\.html$)/);

Simply added the negative lookahead (?!.+\.html$) at the end of the regex pattern.

All 13 comments

Hm, that seems odd.

The guide only mentions separating js and css. It probably makes less sense to keep the html in another separate file if js and css already are. So am I trying to do something that I shouldn't?

No, that should work fine.

@sudo-suhas If you separate the javascript in a js file and keep the html in the .vue file, the tests ALSO Fail.
This is a showstopper for me :(

@paulvanbladel I tried reproducing the error for js section as a separate file and I think I know what the issue(and the workaround) is.

When I placed a js file in the same folder as my Vue component with the same name(hello.js), I saw the following warning:

WARNING in ./src/components/Hello.js
There are multiple modules with names that only differ in casing.
This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
Use equal casing. Compare these module identifiers:
* E:\Projects\repos\vue-test\node_modules\babel-loader\lib\index.js!E:\Projects\repos\vue-test\src\components\Hello.js
    Used by 3 module(s), i. e.
    E:\Projects\repos\vue-test\node_modules\babel-loader\lib\index.js!E:\Projects\repos\vue-test\test\unit\specs\Hello.spec.js
* E:\Projects\repos\vue-test\node_modules\babel-loader\lib\index.js!E:\Projects\repos\vue-test\src\components\hello.js
    Used by 3 module(s), i. e.
    E:\Projects\repos\vue-test\src /^\.\/(?!main(\.js)?$)/

And the tests failed with the following output:

13 03 2017 09:55:37.445:INFO [PhantomJS 2.1.1 (Windows 8 0.0.0)]: Connected on socket Eo_tCb-w3-ZkzEQyAAAA with id 29354609
ERROR LOG: '[Vue warn]: Failed to mount component: template or render function not defined.
(found in <Root>)'

  Hello.vue
    ×should render correct contents
        undefined is not a constructor (evaluating 'vm.$el.querySelector('.hello h1')')
        webpack:///test/unit/specs/Hello.spec.js:8:32 <- index.js:7518:32

However, when I placed the js file in a subfolder(sections), the tests passed. File structure:

├───components
│   │   Hello.vue
│   │
│   └───sections
│           hello.js

However, this still does not fix the errors with HTML seperation.

@sudo-suhas
Thanks for checking that. I tried also several things but due tomy lack of in-depth knowledge about webpack....
@LinusBorg : when saying "that should work", do you mean it works at your side, or do you mean that you would like if it would work :) ? If it works on your side, thanks for providing some pointers.

@sudo-suhas yeah, I confirm that for the .js files it works, when both files have a different name. I can very much live with that.
I love vue and this brilliant webpack template for the cli.

Ran into the same html loader issue today. My setup is a little bit different from yours:

Module | Version
--- | ---
Node.js | 6.9.1
npm | 3.10.8
vue-cli | 2.8.1
vue | 2.1.10
webpack | 1.13.2
babel | 6.0.0

My project was created using vue-cli, so I think the webpack and karma setups would be pretty much the same as yours.

In my project, I separate html, css, and js files then source them in a .vue file. Then I got this html loader issue when running unit tests. This is a little bit wired to me, because the dev config is almost the same as the karma config, except for the source map settings. How come?

Simply adding a html-loader didn't help. So I went for a tricky work around:

Rename all html files to vue files, that is: Hello.html -> Hello.tpl.vue

Also, remember to change the source file name of <template> in the actual .vue file.

Both dev and test are happy now.

Doing this will result in having two .vue files under one component or view folder. But writing all the codes in one large file really sucks. There seem to be no other side effects, so I am going to stick with this work around for now.

Hope this helps.

If you're using vue-cli's generated project you can change line 11 in webpack.test.conf.js to include an html-loader. The tests will run, however there's some strange output which may or may not have to do with the new rule.

//line 11 webpack.test.conf.js
rules: [...utils.styleLoaders(), {test: /\.html/, loader: 'html-loader'}]

Hello,
I had same probleme with a multiple files component.
I started Webpack & VueJs recently but here is maybe a solution.

Setup

| Module | Version |
| --------|---------|
| Node | 6.11.0 |
| npm | 3.10.10 |
| vue | 2.8.2 |
| webpack | 2.6.1 |
| babel | 6.22.1 |

Component structure

├───components
│   └───Navigation
│       └───index.vue
│       └───script.js
│       └───template.html
│       └───style.scss

Here is the index.vue

<template src="./template.html"></template>
<script src="./script.js" scoped></script>
<style lang="scss" src="./style.scss"></style>

Webpack test configuration

Both HTML and SCSS failed in test mode until I write in the webpack.test.conf.js :

// Note: test conf is merged with base conf, all base rules are present, plus:

// Line 10
module: {
    rules: [
        {
            // Maybe just use vue-loader on html template files in components directory only 
            // Like /components\/.*\.html$/
            test: /\.html$/,
            loader: 'vue-loader'
        }
    ]
}

Does it work for you?
What do you guys think?

read the code in test/index.js. it is the karma 'entry' file. it tells krama to load all files in the src directory execpt the main.js

const srcContext = require.context('../src', true, /^\.\/(?!(main(\.js)/);

so you can eclude all the html file by the regx or add html loader in webpack config. require.context can be found in webpack's doc, you can find more detail

Thanks for the hint, @Hanruis - the following adjustment in /test/unit/index.js (line 12) resolved the HTML import problems for me:

const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)(?!.+\.html$)/);

Simply added the negative lookahead (?!.+\.html$) at the end of the regex pattern.

Since I have svg and png files in my src folder I had to use this srcContext:

const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)(?!.+\.html$)(?!.+\.svg$)(?!.+\.png$)(?!.+\.css$)/);

What would be a better regexp to include only the JS files?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dann95 picture dann95  Â·  3Comments

nicolas-t picture nicolas-t  Â·  4Comments

akoboy picture akoboy  Â·  3Comments

v1ar31 picture v1ar31  Â·  3Comments

dfdgsdfg picture dfdgsdfg  Â·  4Comments