|
1 |
| -# TSDX Bootstrap |
| 1 | +# vue-loader [](https://circleci.com/gh/vuejs/vue-loader/tree/next) [](https://ci.appveyor.com/project/yyx990803/vue-loader/branch/next) |
2 | 2 |
|
3 |
| -This project was bootstrapped with [TSDX](https://github.com/jaredpalmer/tsdx). |
| 3 | +> webpack loader for Vue Single-File Components |
4 | 4 |
|
5 |
| -## Local Development |
| 5 | +- [Documentation](https://vue-loader.vuejs.org) |
6 | 6 |
|
7 |
| -Below is a list of commands you will probably find useful. |
| 7 | +## What is Vue Loader? |
8 | 8 |
|
9 |
| -### `npm start` or `yarn start` |
| 9 | +`vue-loader` is a loader for [webpack](https://webpack.js.org/) that allows you to author Vue components in a format called [Single-File Components (SFCs)](./docs/spec.md): |
10 | 10 |
|
11 |
| -Runs the project in development/watch mode. Your project will be rebuilt upon changes. TSDX has a special logger for you convenience. Error messages are pretty printed and formatted for compatibility VS Code's Problems tab. |
| 11 | +``` vue |
| 12 | +<template> |
| 13 | + <div class="example">{{ msg }}</div> |
| 14 | +</template> |
12 | 15 |
|
13 |
| -<img src="https://user-images.githubusercontent.com/4060187/52168303-574d3a00-26f6-11e9-9f3b-71dbec9ebfcb.gif" width="600" /> |
| 16 | +<script> |
| 17 | +export default { |
| 18 | + data () { |
| 19 | + return { |
| 20 | + msg: 'Hello world!' |
| 21 | + } |
| 22 | + } |
| 23 | +} |
| 24 | +</script> |
14 | 25 |
|
15 |
| -Your library will be rebuilt if you make edits. |
| 26 | +<style> |
| 27 | +.example { |
| 28 | + color: red; |
| 29 | +} |
| 30 | +</style> |
| 31 | +``` |
16 | 32 |
|
17 |
| -### `npm run build` or `yarn build` |
| 33 | +There are many cool features provided by `vue-loader`: |
18 | 34 |
|
19 |
| -Bundles the package to the `dist` folder. |
20 |
| -The package is optimized and bundled with Rollup into multiple formats (CommonJS, UMD, and ES Module). |
| 35 | +- Allows using other webpack loaders for each part of a Vue component, for example Sass for `<style>` and Pug for `<template>`; |
| 36 | +- Allows custom blocks in a `.vue` file that can have custom loader chains applied to them; |
| 37 | +- Treat static assets referenced in `<style>` and `<template>` as module dependencies and handle them with webpack loaders; |
| 38 | +- Simulate scoped CSS for each component; |
| 39 | +- State-preserving hot-reloading during development. |
21 | 40 |
|
22 |
| -<img src="https://user-images.githubusercontent.com/4060187/52168322-a98e5b00-26f6-11e9-8cf6-222d716b75ef.gif" width="600" /> |
| 41 | +In a nutshell, the combination of webpack and `vue-loader` gives you a modern, flexible and extremely powerful front-end workflow for authoring Vue.js applications. |
23 | 42 |
|
24 |
| -### `npm test` or `yarn test` |
| 43 | +## How It Works |
25 | 44 |
|
26 |
| -Runs the test watcher (Jest) in an interactive mode. |
27 |
| -By default, runs tests related to files changed since the last commit. |
| 45 | +> The following section is for maintainers and contributors who are interested in the internal implementation details of `vue-loader`, and is **not** required knowledge for end users. |
| 46 | +
|
| 47 | +`vue-loader` is not a simple source transform loader. It handles each language blocks inside an SFC with its own dedicated loader chain (you can think of each block as a "virtual module"), and finally assembles the blocks together into the final module. Here's a brief overview of how the whole thing works: |
| 48 | + |
| 49 | +1. `vue-loader` parses the SFC source code into an *SFC Descriptor* using `@vue/compiler-sfc`. It then generates an import for each language block so the actual returned module code looks like this: |
| 50 | + |
| 51 | + ``` js |
| 52 | + // code returned from the main loader for 'source.vue' |
| 53 | + |
| 54 | + // import the <template> block |
| 55 | + import render from 'source.vue?vue&type=template' |
| 56 | + // import the <script> block |
| 57 | + import script from 'source.vue?vue&type=script' |
| 58 | + export * from 'source.vue?vue&type=script' |
| 59 | + // import <style> blocks |
| 60 | + import 'source.vue?vue&type=style&index=1' |
| 61 | + |
| 62 | + script.render = render |
| 63 | + export default script |
| 64 | + ``` |
| 65 | + |
| 66 | + Notice how the code is importing `source.vue` itself, but with different request queries for each block. |
| 67 | + |
| 68 | +2. We want the content in `script` block to be treated like `.js` files (and if it's `<script lang="ts">`, we want to to be treated like `.ts` files). Same for other language blocks. So we want webpack to apply any configured module rules that matches `.js` also to requests that look like `source.vue?vue&type=script`. This is what `VueLoaderPlugin` (`src/plugins.ts`) does: for each module rule in the webpack config, it creates a modified clone that targets corresponding Vue language block requests. |
| 69 | +
|
| 70 | + Suppose we have configured `babel-loader` for all `*.js` files. That rule will be cloned and applied to Vue SFC `<script>` blocks as well. Internally to webpack, a request like |
| 71 | +
|
| 72 | + ``` js |
| 73 | + import script from 'source.vue?vue&type=script' |
| 74 | + ``` |
| 75 | +
|
| 76 | + Will expand to: |
| 77 | +
|
| 78 | + ``` js |
| 79 | + import script from 'babel-loader!vue-loader!source.vue?vue&type=script' |
| 80 | + ``` |
| 81 | +
|
| 82 | + Notice the `vue-loader` is also matched because `vue-loader` are applied to `.vue` files. |
| 83 | +
|
| 84 | + Similarly, if you have configured `style-loader` + `css-loader` + `sass-loader` for `*.scss` files: |
| 85 | +
|
| 86 | + ``` html |
| 87 | + <style scoped lang="scss"> |
| 88 | + ``` |
| 89 | +
|
| 90 | + Will be returned by `vue-loader` as: |
| 91 | +
|
| 92 | + ``` js |
| 93 | + import 'source.vue?vue&type=style&index=1&scoped&lang=scss' |
| 94 | + ``` |
| 95 | +
|
| 96 | + And webpack will expand it to: |
| 97 | +
|
| 98 | + ``` js |
| 99 | + import 'style-loader!css-loader!sass-loader!vue-loader!source.vue?vue&type=style&index=1&scoped&lang=scss' |
| 100 | + ``` |
| 101 | +
|
| 102 | +3. When processing the expanded requests, the main `vue-loader` will get invoked again. This time though, the loader notices that the request has queries and is targeting a specific block only. So it selects (`src/select.ts`) the inner content of the target block and passes it on to the loaders matched after it. |
| 103 | +
|
| 104 | +4. For the `<script>` block, this is pretty much it. For `<template>` and `<style>` blocks though, a few extra tasks need to be performed: |
| 105 | +
|
| 106 | + - We need to compile the template using the Vue template compiler; |
| 107 | + - We need to post-process the CSS in `<style scoped>` blocks, **after** `css-loader` but **before** `style-loader`. |
| 108 | +
|
| 109 | + Technically, these are additional loaders (`src/templateLoader.ts` and `src/stylePostLoader.ts`) that need to be injected into the expanded loader chain. It would be very complicated if the end users have to configure this themselves, so `VueLoaderPlugin` also injects a global [Pitching Loader](https://webpack.js.org/api/loaders/#pitching-loader) (`src/pitcher.ts`) that intercepts Vue `<template>` and `<style>` requests and injects the necessary loaders. The final requests look like the following: |
| 110 | +
|
| 111 | + ``` js |
| 112 | + // <template lang="pug"> |
| 113 | + import 'vue-loader/template-loader!pug-loader!source.vue?vue&type=template' |
| 114 | +
|
| 115 | + // <style scoped lang="scss"> |
| 116 | + import 'style-loader!vue-loader/style-post-loader!css-loader!sass-loader!vue-loader!source.vue?vue&type=style&index=1&scoped&lang=scss' |
| 117 | + ``` |
0 commit comments