├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── .node-version
├── .prettierrc
├── .vscode
└── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── example
├── App.vue
├── Button.vue
├── ScriptSetup.vue
├── TypeScript.vue
├── devServer.js
├── docs-loader.js
├── index.html
├── logo.png
├── main.js
├── ssr.js
├── types.ts
└── webpack.config.js
├── jest.config.js
├── package.json
├── pnpm-lock.yaml
├── src
├── compiler.ts
├── cssModules.ts
├── descriptorCache.ts
├── exportHelper.ts
├── formatError.ts
├── hotReload.ts
├── index.ts
├── pitcher.ts
├── plugin.ts
├── pluginWebpack4.ts
├── pluginWebpack5.ts
├── resolveScript.ts
├── select.ts
├── shim.d.ts
├── styleInlineLoader.ts
├── stylePostLoader.ts
├── templateLoader.ts
└── util.ts
├── test
├── advanced.spec.ts
├── core.spec.ts
├── custom.spec.ts
├── edgeCases.spec.ts
├── fixtures
│ ├── App.ts
│ ├── ScriptSetup.vue
│ ├── basic.vue
│ ├── css-modules-extend.vue
│ ├── css-modules-simple.vue
│ ├── css-modules.vue
│ ├── custom-import.vue
│ ├── custom-language.vue
│ ├── custom-query.vue
│ ├── duplicate-cssm.css
│ ├── duplicate-cssm.js
│ ├── duplicate-cssm.vue
│ ├── empty-style.vue
│ ├── entry.js
│ ├── extract-css-chunks.vue
│ ├── extract-css.vue
│ ├── i18n-entry.js
│ ├── i18n.vue
│ ├── imported-types-aliased.ts
│ ├── imported-types.ts
│ ├── imported-types.vue
│ ├── index.html
│ ├── logo.png
│ ├── markdown.vue
│ ├── named-exports.vue
│ ├── no-script.vue
│ ├── optional-chaining.vue
│ ├── postcss.vue
│ ├── pre.vue
│ ├── process-custom-file
│ │ ├── custom-file.svg
│ │ └── process-custom-file.vue
│ ├── resolve.vue
│ ├── scoped-css.vue
│ ├── script-import.js
│ ├── script-import.vue
│ ├── style-import-scoped.css
│ ├── style-import-twice-sub.vue
│ ├── style-import-twice.vue
│ ├── style-import.css
│ ├── style-import.vue
│ ├── style-v-bind.vue
│ ├── template-import-pre.vue
│ ├── template-import.html
│ ├── template-import.pug
│ ├── template-import.vue
│ ├── ts.vue
│ ├── tsconfig.json
│ └── unit-test.js
├── mock-loaders
│ ├── docs.js
│ ├── html.js
│ ├── js.js
│ └── query.js
├── script.spec.ts
├── style.spec.ts
├── template.spec.ts
└── utils.ts
└── tsconfig.json
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: 'ci'
2 | on:
3 | push:
4 | branches:
5 | - '**'
6 | pull_request:
7 | branches:
8 | - main
9 | jobs:
10 | test-webpack4:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v3
14 | - uses: pnpm/action-setup@v2
15 | - uses: actions/setup-node@v3
16 | with:
17 | node-version: '16'
18 | cache: 'pnpm'
19 | - run: pnpm install
20 | - run: pnpm pretest:webpack4
21 | - run: pnpm test:webpack4
22 |
23 | test-webpack5:
24 | runs-on: ubuntu-latest
25 | steps:
26 | - uses: actions/checkout@v3
27 | - uses: pnpm/action-setup@v2
28 | - uses: actions/setup-node@v3
29 | with:
30 | node-version: '16'
31 | cache: 'pnpm'
32 | - run: pnpm install
33 | - run: pnpm pretest
34 | - run: pnpm test
35 |
36 | test-webpack5-inline-match-resource:
37 | runs-on: ubuntu-latest
38 | steps:
39 | - uses: actions/checkout@v3
40 | - uses: pnpm/action-setup@v2
41 | - uses: actions/setup-node@v3
42 | with:
43 | node-version: '16'
44 | cache: 'pnpm'
45 | - run: pnpm install
46 | - run: pnpm pretest:match-resource
47 | - run: pnpm test:match-resource
48 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | .DS_Store
3 | node_modules
4 | dist
5 | dist-ssr
6 | link.sh
7 | .cache
8 | TODOs.md
9 | coverage
10 | .vscode
11 |
--------------------------------------------------------------------------------
/.node-version:
--------------------------------------------------------------------------------
1 | v16.20.0
2 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | semi: false
2 | singleQuote: true
3 | printWidth: 80
4 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "node_modules/typescript/lib"
3 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [17.4.2](https://github.com/vuejs/vue-loader/compare/v17.4.1...v17.4.2) (2023-12-30)
2 |
3 |
4 | ### Bug Fixes
5 |
6 | * pass compilerOptions to sfc parse & re-enable AST reuse ([d2a2e05](https://github.com/vuejs/vue-loader/commit/d2a2e051c3d985d1ae6bb468749b24543631b482))
7 |
8 |
9 |
10 | ## [17.4.1](https://github.com/vuejs/vue-loader/compare/v17.4.0...v17.4.1) (2023-12-30)
11 |
12 |
13 | ### Bug Fixes
14 |
15 | * (temporarily) disable template ast reuse ([31b03af](https://github.com/vuejs/vue-loader/commit/31b03af121edbe70337f538b1def95acbef4d0f1))
16 |
17 |
18 |
19 | # [17.4.0](https://github.com/vuejs/vue-loader/compare/v17.3.1...v17.4.0) (2023-12-25)
20 |
21 |
22 | ### Features
23 |
24 | * leverage ast reuse in 3.4 ([479835f](https://github.com/vuejs/vue-loader/commit/479835fe751691a39c62cda12bffeef9e6830443))
25 |
26 |
27 |
28 | ## [17.3.1](https://github.com/vuejs/vue-loader/compare/v17.3.0...v17.3.1) (2023-10-31)
29 |
30 |
31 | ### Bug Fixes
32 |
33 | * do not skip style post loader for v-bind() in CSS ([d7071bb](https://github.com/vuejs/vue-loader/commit/d7071bbdeb45518c053bdae8eb7de52fc598adc6)), closes [#2061](https://github.com/vuejs/vue-loader/issues/2061)
34 |
35 |
36 | # [17.3.0](https://github.com/vuejs/vue-loader/compare/v17.2.2...v17.3.0) (2023-10-07)
37 |
38 |
39 | ### Bug Fixes
40 |
41 | * re-use ident of vue rule for template compiler, fixes [#2029](https://github.com/vuejs/vue-loader/issues/2029) ([#2030](https://github.com/vuejs/vue-loader/issues/2030)) ([b50fa56](https://github.com/vuejs/vue-loader/commit/b50fa5665f2cbc1c0b8e18f65dd3adf1dfe848dc))
42 |
43 |
44 | ### Features
45 |
46 | * skip normal css files without scoped flag in stylePostLoader ([#2053](https://github.com/vuejs/vue-loader/issues/2053)) ([98782e7](https://github.com/vuejs/vue-loader/commit/98782e794fadca83b600b047b55aa6f0c230cc25))
47 |
48 |
49 |
50 | ## [17.2.2](https://github.com/vuejs/vue-loader/compare/v17.2.1...v17.2.2) (2023-06-02)
51 |
52 |
53 | ### Bug Fixes
54 |
55 | * windows path for `experiments.css` ([#2049](https://github.com/vuejs/vue-loader/issues/2049)) ([f3f45df](https://github.com/vuejs/vue-loader/commit/f3f45df925bcd80307232e7410ead355f87953d3))
56 |
57 |
58 |
59 | ## [17.2.1](https://github.com/vuejs/vue-loader/compare/v17.1.2...v17.2.1) (2023-06-01)
60 |
61 |
62 | ### Features
63 |
64 | * A new `experimentalInlineMatchResource` option (webpack 5 only), which leverages webpack 5's inline match resource feature and works well with the [`experiments.css`](https://webpack.js.org/configuration/experiments/#experimentscss) feature ([#2046](https://github.com/vuejs/vue-loader/issues/2046)) ([3149f6d](https://github.com/vuejs/vue-loader/commit/3149f6d69c2f456bdcfa23acc0da93473a93a764))
65 |
66 |
67 | Note: v17.2.0 was released by accident, it has the same content as v17.1.2, therefore not included in the changelog.
68 |
69 |
70 | ## [17.1.2](https://github.com/vuejs/vue-loader/compare/v17.1.1...v17.1.2) (2023-05-29)
71 |
72 |
73 | ### Bug Fixes
74 |
75 | * keep build stable when run in a different path ([#2040](https://github.com/vuejs/vue-loader/issues/2040)) ([a81dc0f](https://github.com/vuejs/vue-loader/commit/a81dc0f573d216eefa13b0275f3fc147bf3e2ef3))
76 | * properly close the watcher after tests ([40b93b9](https://github.com/vuejs/vue-loader/commit/40b93b9c2722e85a000de62e3eb8bc02facafd10))
77 |
78 |
79 |
80 | ## [17.1.1](https://github.com/vuejs/vue-loader/compare/v17.1.0...v17.1.1) (2023-05-11)
81 |
82 |
83 | ### Bug Fixes
84 |
85 | * support propsDestructure and defineModel options ([6269698](https://github.com/vuejs/vue-loader/commit/6269698f9fda37f0e3849db3e8b8e67ad1862f57))
86 |
87 |
88 |
89 | # [17.1.0](https://github.com/vuejs/vue-loader/compare/v17.1.0-beta.0...v17.1.0) (2023-04-26)
90 |
91 |
92 | ### Bug Fixes
93 |
94 | * do not throw when `Rule.layer` ([#2000](https://github.com/vuejs/vue-loader/issues/2000)) ([ef589df](https://github.com/vuejs/vue-loader/commit/ef589df2956506a5a7bbc050c476501d32dd8469))
95 |
96 |
97 |
98 | # [17.1.0-beta.0](https://github.com/vuejs/vue-loader/compare/v17.0.1...v17.1.0-beta.0) (2023-04-19)
99 |
100 |
101 | ### Bug Fixes
102 |
103 | * reference project compiler, fixes [#2031](https://github.com/vuejs/vue-loader/issues/2031) ([#2038](https://github.com/vuejs/vue-loader/issues/2038)) ([cc6fa9e](https://github.com/vuejs/vue-loader/commit/cc6fa9ebf85972a08fc8bbc359b0093b15790745))
104 |
105 |
106 | ### Features
107 |
108 | * support 3.3 imported types hmr ([bbd98fc](https://github.com/vuejs/vue-loader/commit/bbd98fc8bdc17fcbffb456a5ffe772bc184f22e4))
109 |
110 |
111 |
112 | ## [17.0.1](https://github.com/vuejs/vue-loader/compare/v17.0.0...v17.0.1) (2022-10-28)
113 |
114 |
115 | ### Bug Fixes
116 |
117 | * add `vue` and `@vue/compiler-sfc` to optional peerDependencies ([df0ded5](https://github.com/vuejs/vue-loader/commit/df0ded5356864b9923da8f89ff33db1ae6c2402f)), closes [#1944](https://github.com/vuejs/vue-loader/issues/1944)
118 | * merge custom queries rather than appending ([#1911](https://github.com/vuejs/vue-loader/issues/1911)) ([9e4249a](https://github.com/vuejs/vue-loader/commit/9e4249a548ceb04ead46fff9b68e9b2676b4c692))
119 |
120 |
121 |
122 | ## [17.0.1](https://github.com/vuejs/vue-loader/compare/v16.8.3...v17.0.1) (2022-10-28)
123 |
124 |
125 | ### Bug Fixes
126 |
127 | * add `vue` and `@vue/compiler-sfc` to optional peerDependencies ([df0ded5](https://github.com/vuejs/vue-loader/commit/df0ded5356864b9923da8f89ff33db1ae6c2402f)), closes [#1944](https://github.com/vuejs/vue-loader/issues/1944)
128 | * merge custom queries rather than appending ([#1911](https://github.com/vuejs/vue-loader/issues/1911)) ([9e4249a](https://github.com/vuejs/vue-loader/commit/9e4249a548ceb04ead46fff9b68e9b2676b4c692))
129 |
130 |
131 |
132 | # [17.0.0](https://github.com/vuejs/vue-loader/compare/v16.8.3...v17.0.0) (2021-12-12)
133 |
134 |
135 | ### Features
136 |
137 | * support `reactivityTransform` option ([e07490e](https://github.com/vuejs/vue-loader/commit/e07490ec8b8ac9e00050251d6f0e697fb1f3bf3c))
138 |
139 |
140 | ### BREAKING CHANGES
141 |
142 | * remove `refSugar` option, require `vue@^3.2.13`
143 |
144 |
145 |
146 | ## [16.8.3](https://github.com/vuejs/vue-loader/compare/v16.8.2...v16.8.3) (2021-11-04)
147 |
148 |
149 | ### Bug Fixes
150 |
151 | * HMR not working correctly with vue-class-component components ([#1897](https://github.com/vuejs/vue-loader/issues/1897)) ([76b1448](https://github.com/vuejs/vue-loader/commit/76b1448eb227c42e1791a691a86782b7a8cacfc0))
152 |
153 |
154 |
155 | ## [16.8.3](https://github.com/vuejs/vue-loader/compare/v16.8.2...v16.8.3) (2021-11-04)
156 |
157 |
158 | ### Bug Fixes
159 |
160 | * HMR not working correctly with vue-class-component components ([#1897](https://github.com/vuejs/vue-loader/issues/1897)) ([76b1448](https://github.com/vuejs/vue-loader/commit/76b1448eb227c42e1791a691a86782b7a8cacfc0))
161 |
162 |
163 |
164 | ## [16.8.2](https://github.com/vuejs/vue-loader/compare/v16.8.1...v16.8.2) (2021-10-26)
165 |
166 |
167 | ### Bug Fixes
168 |
169 | * should allow chaining with loaders for non-vue files ([#1889](https://github.com/vuejs/vue-loader/issues/1889)) ([f32f953](https://github.com/vuejs/vue-loader/commit/f32f9538ea34fc08e1a28622227896241847690f)), closes [#1879](https://github.com/vuejs/vue-loader/issues/1879) [#1883](https://github.com/vuejs/vue-loader/issues/1883) [#1890](https://github.com/vuejs/vue-loader/issues/1890)
170 | * **plugin:** use compiler.webpack when possible ([#1884](https://github.com/vuejs/vue-loader/issues/1884)) ([820d23c](https://github.com/vuejs/vue-loader/commit/820d23cbf16013dae894e0d84ed9da6e58a37584))
171 |
172 |
173 |
174 | ## [16.8.1](https://github.com/vuejs/vue-loader/compare/v16.8.0...v16.8.1) (2021-09-22)
175 |
176 |
177 | ### Bug Fixes
178 |
179 | * fix template options resolving for ts ([91f581b](https://github.com/vuejs/vue-loader/commit/91f581b99644119b68e586a0b642fff3811c8741))
180 |
181 | # [16.8.0](https://github.com/vuejs/vue-loader/compare/v16.7.1...v16.8.0) (2021-09-22)
182 |
183 |
184 | ### Bug Fixes
185 |
186 | * **hmr:** fix hmr regression ([bacc6a9](https://github.com/vuejs/vue-loader/commit/bacc6a9eeca40d6028a2d9a5f6ee02e6c8574abd))
187 |
188 |
189 | ### Features
190 |
191 | * enableTsInTemplate option ([7613534](https://github.com/vuejs/vue-loader/commit/7613534954b83489a060860b9525a0d121023c5b))
192 |
193 | - When used with `ts-loader`, due to `ts-loader`'s cache invalidation behavior, it sometimes prevents the template from being hot-reloaded in isolation, causing the component to reload despite only the template being edited. If this is annoying, you can set this option to `false` (and avoid using TS expressions in templates).
194 |
195 | - Alternatively, leave this option on (by default) and use [`esbuild-loader`](https://github.com/privatenumber/esbuild-loader) to transpile TS instead, which doesn't suffer from this problem (it's also a lot faster). However, do note you will need to rely on TS type checking from other sources (e.g. IDE or `vue-tsc`).
196 |
197 | ## [16.7.1](https://github.com/vuejs/vue-loader/compare/v16.7.0...v16.7.1) (2021-09-22)
198 |
199 |
200 | ### Bug Fixes
201 |
202 | * remove pure annotation for custom blocks ([cd891e5](https://github.com/vuejs/vue-loader/commit/cd891e593bf7f8aff852f1d47fda2337de661bea))
203 |
204 |
205 | # [16.7.0](https://github.com/vuejs/vue-loader/compare/v16.6.0...v16.7.0) (2021-09-21)
206 |
207 |
208 | ### Features
209 |
210 | * support optional @vue/compiler-sfc peer dep ([21725a4](https://github.com/vuejs/vue-loader/commit/21725a4ebc9c8d7f8a590d700017759327e21c2e))
211 |
212 |
213 | # [16.6.0](https://github.com/vuejs/vue-loader/compare/v16.5.0...v16.6.0) (2021-09-20)
214 |
215 |
216 | ### Bug Fixes
217 |
218 | * generate treeshaking friendly code ([11e3cb8](https://github.com/vuejs/vue-loader/commit/11e3cb8a8a4a4e0aedc2978ce6d7e549a61de3d7))
219 |
220 |
221 | ### Features
222 |
223 | * support ts in template expressions ([573fbd2](https://github.com/vuejs/vue-loader/commit/573fbd2e72c3246c2daadb8d8c053464c964cfe3))
224 |
225 |
226 | # [16.5.0](https://github.com/vuejs/vue-loader/compare/v16.4.1...v16.5.0) (2021-08-07)
227 |
228 | * Custom Elements mode behavior changed: now only inlines the CSS and no longer exports the custom element constructor (exports the component as in normal mode). Users now need to explicitly call `defineCustomElement` on the component. This allows the custom element to be defined using an async version of the source component.
229 |
230 |
231 | ## [16.4.1](https://github.com/vuejs/vue-loader/compare/v16.4.0...v16.4.1) (2021-08-02)
232 |
233 |
234 | ### Bug Fixes
235 |
236 | * fix webpack 5.48 compatibility ([b94289c](https://github.com/vuejs/vue-loader/commit/b94289c9fb395556100ec121529dfe676280d3cd)), closes [#1859](https://github.com/vuejs/vue-loader/issues/1859)
237 |
238 |
239 | # [16.4.0](https://github.com/vuejs/vue-loader/compare/v16.3.3...v16.4.0) (2021-07-30)
240 |
241 |
242 | ### Features
243 |
244 | * customElement option support for Vue 3.2 ([e19fcda](https://github.com/vuejs/vue-loader/commit/e19fcdaa62c4aa5d826c33a0e7fb8786904ee225))
245 |
246 |
247 | ## [16.3.3](https://github.com/vuejs/vue-loader/compare/v16.3.2...v16.3.3) (2021-07-21)
248 |
249 |
250 | ### Bug Fixes
251 |
252 | * mark @vue/compiler-sfc as an optional peer dependency ([089473a](https://github.com/vuejs/vue-loader/commit/089473af97077b8e14b3feff48d32d2733ad792c))
253 |
254 |
255 |
256 | ## [16.3.2](https://github.com/vuejs/vue-loader/compare/v16.3.1...v16.3.2) (2021-07-20)
257 |
258 |
259 | ### Bug Fixes
260 |
261 | * add undeclared peer dependency `webpack` and `@vue/compiler-sfc` ([#1853](https://github.com/vuejs/vue-loader/issues/1853)) ([330d672](https://github.com/vuejs/vue-loader/commit/330d672fb344fddefec98e170587d93876a9e354))
262 |
263 |
264 |
265 | ## [16.3.1](https://github.com/vuejs/vue-loader/compare/v16.3.0...v16.3.1) (2021-07-16)
266 |
267 |
268 | ### Bug Fixes
269 |
270 | * pick up production env in thread-loader context ([821a3a3](https://github.com/vuejs/vue-loader/commit/821a3a35f04cda3154a9341898225f61d72b3f05)), closes [vuejs/vue-next#3921](https://github.com/vuejs/vue-next/issues/3921)
271 |
272 |
273 |
274 | # [16.3.0](https://github.com/vuejs/vue-loader/compare/v16.2.0...v16.3.0) (2021-06-29)
275 |
276 |
277 | ### Features
278 |
279 | * pass on compilerOptions and refSugar when using `
46 |
47 |
52 | ```
53 |
54 | There are many cool features provided by `vue-loader`:
55 |
56 | - Allows using other webpack loaders for each part of a Vue component, for example Sass for `
39 |
--------------------------------------------------------------------------------
/example/Button.vue:
--------------------------------------------------------------------------------
1 |
2 | prop foo: {{ foo }}
3 |
4 |
5 |
6 |
7 |
23 |
24 |
29 |
30 |
31 | This component is fire. // <-- this should be logged
32 |
33 |
--------------------------------------------------------------------------------
/example/ScriptSetup.vue:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 | {{ hello }}
21 |
22 | ref sugar count: {{ count }}
23 |
24 |
25 |
26 |
27 |
28 |
33 |
--------------------------------------------------------------------------------
/example/TypeScript.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 | {{ Object.keys(props) }}
13 | From TSssss: {{ a?.toFixed(2) }}
14 |
15 |
--------------------------------------------------------------------------------
/example/devServer.js:
--------------------------------------------------------------------------------
1 | // register proxy sub-paths
2 | if (process.env.WEBPACK4) {
3 | console.log('using webpack 4...')
4 | const Module = require('module')
5 | const resolve = Module._resolveFilename
6 | Module._resolveFilename = (request, ...rest) => {
7 | if (request === 'webpack') {
8 | return resolve('webpack4', ...rest)
9 | }
10 | if (request.startsWith('webpack/')) {
11 | return resolve(request.replace(/^webpack\//, 'webpack4/'), ...rest)
12 | }
13 | return resolve(request, ...rest)
14 | }
15 | }
16 |
17 | require('webpack-dev-server/bin/webpack-dev-server.js')
18 |
--------------------------------------------------------------------------------
/example/docs-loader.js:
--------------------------------------------------------------------------------
1 | module.exports = function(source) {
2 | this.callback(null, `export default function (Comp) {
3 | Comp.mounted = () => console.log(${JSON.stringify(source.trim())})
4 | }`)
5 | }
6 |
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/example/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs/vue-loader/698636508e08f5379a57eaf086b5ff533af8e051/example/logo.png
--------------------------------------------------------------------------------
/example/main.js:
--------------------------------------------------------------------------------
1 | import App from './App.vue'
2 | import { createApp, createSSRApp } from 'vue'
3 |
4 | const app = __IS_SSR__ ? createSSRApp(App) : createApp(App)
5 | export default app
6 |
7 | if (typeof window !== 'undefined') {
8 | app.mount('#app')
9 | }
10 |
--------------------------------------------------------------------------------
/example/ssr.js:
--------------------------------------------------------------------------------
1 | // This script is part of `yarn build-example-ssr`.
2 |
3 | const fs = require('fs')
4 | const path = require('path')
5 | const { renderToString } = require('@vue/server-renderer')
6 | const template = fs.readFileSync(path.resolve(__dirname, 'index.html'), 'utf-8')
7 |
8 | // here out server-side build directly exports an app instance.
9 | // in an actual SSR setup, you'll want to export a `createApp()` function that
10 | // returns a fresh app instance for each request. You probably also want to
11 | // return the router instance so that you can set the app's route state before
12 | // actually rendering it.
13 | const app = require('./dist-ssr/server/main.js').default
14 |
15 | renderToString(app).then((html) => {
16 | fs.writeFileSync(
17 | path.resolve(__dirname, 'dist-ssr/index.html'),
18 | template.replace(/()/, `$1${html}`)
19 | )
20 | })
21 |
--------------------------------------------------------------------------------
/example/types.ts:
--------------------------------------------------------------------------------
1 | export interface Props {
2 | msg: string
3 | lol?: string
4 | }
5 |
--------------------------------------------------------------------------------
/example/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const webpack = require('webpack')
3 | const VueLoaderPlugin = require('../dist/plugin').default
4 | const MiniCssExtractPlugin = require('mini-css-extract-plugin')
5 |
6 | module.exports = (env = {}) => {
7 | const isProd = env.prod
8 | const isSSR = env.ssr
9 |
10 | /**
11 | * Some notes regarding config for the server build of an SSR app:
12 | * 1. target: 'node'
13 | * 2. output.libraryTarget: 'commonjs' (so the exported app can be required)
14 | * 3. externals: this is mostly for faster builds.
15 | * - externalize @vue/* deps via commonjs require()
16 | * - externalize client side deps that are never used on the server, e.g.
17 | * ones that are only used in onMounted() to empty modules
18 | * 4. If using cache-loader or any other forms of cache, make sure the cache
19 | * key takes client vs. server builds into account!
20 | */
21 | const genConfig = (isServerBuild = false) => {
22 | const minimize = isProd && !isServerBuild && !env.noMinimize
23 |
24 | return {
25 | mode: isProd ? 'production' : 'development',
26 | entry: path.resolve(__dirname, './main.js'),
27 | target: isServerBuild ? 'node' : 'web',
28 | devtool: 'source-map',
29 | resolve: {
30 | extensions: ['.js', '.ts'],
31 | alias: process.env.WEBPACK4
32 | ? {
33 | webpack: 'webpack4',
34 | }
35 | : {},
36 | },
37 | output: {
38 | path: path.resolve(
39 | __dirname,
40 | isSSR ? (isServerBuild ? 'dist-ssr/server' : 'dist-ssr/dist') : 'dist'
41 | ),
42 | filename: '[name].js',
43 | publicPath: '/dist/',
44 | libraryTarget: isServerBuild ? 'commonjs' : undefined,
45 | },
46 | externals: isServerBuild
47 | ? [
48 | (ctx, request, cb) => {
49 | if (/^@vue/.test(request)) {
50 | return cb(null, 'commonjs ' + request)
51 | }
52 | cb()
53 | },
54 | ]
55 | : undefined,
56 | module: {
57 | rules: [
58 | {
59 | test: /\.vue$/,
60 | loader: 'vue-loader',
61 | options: {
62 | // reactivityTransform: true,
63 | compilerOptions: {
64 | isCustomElement: (tag) => tag.startsWith('custom-'),
65 | },
66 | },
67 | },
68 | {
69 | test: /\.png$/,
70 | use: [
71 | {
72 | loader: 'url-loader',
73 | options: {
74 | limit: 8192,
75 | },
76 | },
77 | ],
78 | },
79 | {
80 | test: /\.css$/,
81 | use: [MiniCssExtractPlugin.loader, 'css-loader'],
82 | },
83 | {
84 | test: /\.ts$/,
85 | use: [
86 | {
87 | loader: process.env.WEBPACK4
88 | ? require.resolve('ts-loader')
89 | : require.resolve('ts-loader-v9'),
90 | options: {
91 | transpileOnly: true,
92 | appendTsSuffixTo: [/\.vue$/],
93 | },
94 | },
95 | ],
96 | },
97 | // target
custom blocks
98 | {
99 | resourceQuery: /blockType=docs/,
100 | loader: require.resolve('./docs-loader'),
101 | },
102 | ],
103 | },
104 | plugins: [
105 | new VueLoaderPlugin(),
106 | new MiniCssExtractPlugin({
107 | filename: '[name].css',
108 | }),
109 | new webpack.DefinePlugin({
110 | __IS_SSR__: !!isSSR,
111 | __VUE_OPTIONS_API__: true,
112 | __VUE_PROD_DEVTOOLS__: false,
113 | __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false,
114 | }),
115 | ],
116 | optimization: {
117 | minimize,
118 | },
119 | devServer: {
120 | hot: true,
121 | stats: 'minimal',
122 | contentBase: __dirname,
123 | overlay: true,
124 | },
125 | resolveLoader: {
126 | alias: {
127 | 'vue-loader': require.resolve('../'),
128 | },
129 | },
130 | }
131 | }
132 |
133 | if (!isSSR) {
134 | return genConfig()
135 | } else {
136 | return [genConfig(), genConfig(true)]
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | const isWebpack4 = process.env.WEBPACK4
2 |
3 | console.log(
4 | `running tests with webpack ${isWebpack4 ? '4' : '5'}${
5 | !isWebpack4 && process.env.INLINE_MATCH_RESOURCE
6 | ? ' with inline match resource enabled'
7 | : ''
8 | }...`
9 | )
10 |
11 | module.exports = {
12 | preset: 'ts-jest',
13 | testTimeout: 60000,
14 | testEnvironment: 'node',
15 | testPathIgnorePatterns: ['/dist/', '/node_modules/'],
16 | globals: {
17 | 'ts-jest': {
18 | diagnostics: false,
19 | },
20 | },
21 | moduleNameMapper: process.env.WEBPACK4
22 | ? {
23 | '^webpack$': 'webpack4',
24 | '^webpack/(.*)': 'webpack4/$1',
25 | }
26 | : undefined,
27 | }
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-loader",
3 | "version": "17.4.2",
4 | "license": "MIT",
5 | "author": "Evan You",
6 | "repository": "vuejs/vue-loader",
7 | "main": "dist/index.js",
8 | "types": "dist/index.d.ts",
9 | "files": [
10 | "dist"
11 | ],
12 | "scripts": {
13 | "dev": "tsc --watch",
14 | "build": "tsc",
15 | "pretest": "tsc",
16 | "test": "jest",
17 | "pretest:match-resource": "tsc",
18 | "test:match-resource": "INLINE_MATCH_RESOURCE=true jest",
19 | "pretest:webpack4": "tsc",
20 | "test:webpack4": "WEBPACK4=true jest",
21 | "dev-example": "node example/devServer.js --config example/webpack.config.js --inline --hot",
22 | "build-example": "rm -rf example/dist && webpack --config example/webpack.config.js --env.prod",
23 | "build-example-ssr": "rm -rf example/dist-ssr && webpack --config example/webpack.config.js --env.prod --env.ssr && node example/ssr.js",
24 | "lint": "prettier --write --parser typescript \"{src,test}/**/*.{j,t}s\"",
25 | "prepublishOnly": "tsc && conventional-changelog -p angular -i CHANGELOG.md -s -r 2"
26 | },
27 | "gitHooks": {
28 | "pre-commit": "lint-staged"
29 | },
30 | "lint-staged": {
31 | "*.js": [
32 | "prettier --write"
33 | ],
34 | "*.ts": [
35 | "prettier --parser=typescript --write"
36 | ]
37 | },
38 | "packageManager": "pnpm@8.12.0",
39 | "dependencies": {
40 | "chalk": "^4.1.0",
41 | "watchpack": "^2.4.0"
42 | },
43 | "peerDependencies": {
44 | "webpack": "^4.1.0 || ^5.0.0-0"
45 | },
46 | "peerDependenciesMeta": {
47 | "@vue/compiler-sfc": {
48 | "optional": true
49 | },
50 | "vue": {
51 | "optional": true
52 | }
53 | },
54 | "devDependencies": {
55 | "@babel/core": "^7.7.7",
56 | "@babel/preset-env": "^7.11.5",
57 | "@intlify/vue-i18n-loader": "^3.0.0",
58 | "@types/cssesc": "^3.0.2",
59 | "@types/estree": "^0.0.45",
60 | "@types/jest": "^26.0.13",
61 | "@types/jsdom": "^16.2.13",
62 | "@types/mini-css-extract-plugin": "^0.9.1",
63 | "@types/webpack-merge": "^4.1.5",
64 | "babel-loader": "^8.1.0",
65 | "cache-loader": "^4.1.0",
66 | "conventional-changelog-cli": "^2.1.1",
67 | "css-loader": "^4.3.0",
68 | "cssesc": "^3.0.0",
69 | "file-loader": "^6.1.0",
70 | "html-webpack-plugin": "^4.5.0",
71 | "html-webpack-plugin-v5": "npm:html-webpack-plugin@^5.3.2",
72 | "jest": "^26.4.1",
73 | "jsdom": "^16.4.0",
74 | "lint-staged": "^10.3.0",
75 | "markdown-loader": "^6.0.0",
76 | "memfs": "^3.1.2",
77 | "mini-css-extract-plugin": "^1.6.2",
78 | "normalize-newline": "^3.0.0",
79 | "null-loader": "^4.0.1",
80 | "postcss-loader": "^4.0.4",
81 | "prettier": "^2.1.1",
82 | "pug": "^2.0.0",
83 | "pug-plain-loader": "^1.0.0",
84 | "source-map": "^0.6.1",
85 | "style-loader": "^2.0.0",
86 | "stylus": "^0.54.7",
87 | "stylus-loader": "^4.1.1",
88 | "sugarss": "^3.0.1",
89 | "ts-jest": "^26.2.0",
90 | "ts-loader": "^8.0.6",
91 | "ts-loader-v9": "npm:ts-loader@^9.2.4",
92 | "typescript": "^4.4.3",
93 | "url-loader": "^4.1.0",
94 | "vue": "^3.4.3",
95 | "vue-i18n": "^9.1.7",
96 | "webpack": "^5.79.0",
97 | "webpack-cli": "^3.3.12",
98 | "webpack-dev-server": "^3.11.3",
99 | "webpack-merge": "^5.1.4",
100 | "webpack4": "npm:webpack@^4.46.0",
101 | "yorkie": "^2.0.0"
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/compiler.ts:
--------------------------------------------------------------------------------
1 | // extend the descriptor so we can store the scopeId on it
2 | declare module 'vue/compiler-sfc' {
3 | interface SFCDescriptor {
4 | id: string
5 | }
6 | }
7 |
8 | import * as _compiler from 'vue/compiler-sfc'
9 |
10 | export let compiler: typeof _compiler
11 |
12 | try {
13 | // Vue 3.2.13+ ships the SFC compiler directly under the `vue` package
14 | // making it no longer necessary to have @vue/compiler-sfc separately installed.
15 | compiler = require('vue/compiler-sfc')
16 | } catch (e) {
17 | try {
18 | compiler = require('@vue/compiler-sfc')
19 | } catch (e) {
20 | throw new Error(
21 | `@vitejs/plugin-vue requires vue (>=3.2.13) or @vue/compiler-sfc ` +
22 | `to be present in the dependency tree.`
23 | )
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/cssModules.ts:
--------------------------------------------------------------------------------
1 | export function genCSSModulesCode(
2 | id: string,
3 | index: number,
4 | request: string,
5 | moduleName: string | boolean,
6 | needsHotReload: boolean
7 | ): string {
8 | const styleVar = `style${index}`
9 | let code = `\nimport ${styleVar} from ${request}`
10 |
11 | // inject variable
12 | const name = typeof moduleName === 'string' ? moduleName : '$style'
13 | code += `\ncssModules["${name}"] = ${styleVar}`
14 |
15 | if (needsHotReload) {
16 | code += `
17 | if (module.hot) {
18 | module.hot.accept(${request}, () => {
19 | cssModules["${name}"] = ${styleVar}
20 | __VUE_HMR_RUNTIME__.rerender("${id}")
21 | })
22 | }`
23 | }
24 |
25 | return code
26 | }
27 |
--------------------------------------------------------------------------------
/src/descriptorCache.ts:
--------------------------------------------------------------------------------
1 | import * as fs from 'fs'
2 | import type { CompilerOptions, SFCDescriptor } from 'vue/compiler-sfc'
3 | import { compiler } from './compiler'
4 |
5 | const { parse } = compiler
6 | export const descriptorCache = new Map()
7 |
8 | export function setDescriptor(filename: string, entry: SFCDescriptor) {
9 | descriptorCache.set(cleanQuery(filename), entry)
10 | }
11 |
12 | export function getDescriptor(
13 | filename: string,
14 | compilerOptions?: CompilerOptions
15 | ): SFCDescriptor {
16 | filename = cleanQuery(filename)
17 | if (descriptorCache.has(filename)) {
18 | return descriptorCache.get(filename)!
19 | }
20 |
21 | // This function should only be called after the descriptor has been
22 | // cached by the main loader.
23 | // If this is somehow called without a cache hit, it's probably due to sub
24 | // loaders being run in separate threads. The only way to deal with this is to
25 | // read from disk directly...
26 | const source = fs.readFileSync(filename, 'utf-8')
27 | const { descriptor } = parse(source, {
28 | filename,
29 | sourceMap: true,
30 | templateParseOptions: compilerOptions,
31 | })
32 | descriptorCache.set(filename, descriptor)
33 | return descriptor
34 | }
35 |
36 | function cleanQuery(str: string) {
37 | const i = str.indexOf('?')
38 | return i > 0 ? str.slice(0, i) : str
39 | }
40 |
--------------------------------------------------------------------------------
/src/exportHelper.ts:
--------------------------------------------------------------------------------
1 | // runtime helper for setting properties on components
2 | // in a tree-shakable way
3 | export default (sfc: any, props: [string, string][]) => {
4 | const target = sfc.__vccOpts || sfc
5 | for (const [key, val] of props) {
6 | target[key] = val
7 | }
8 | return target
9 | }
10 |
--------------------------------------------------------------------------------
/src/formatError.ts:
--------------------------------------------------------------------------------
1 | import type { CompilerError } from 'vue/compiler-sfc'
2 | import { compiler } from './compiler'
3 | import chalk = require('chalk')
4 |
5 | const { generateCodeFrame } = compiler
6 |
7 | export function formatError(
8 | err: SyntaxError | CompilerError,
9 | source: string,
10 | file: string
11 | ) {
12 | const loc = (err as CompilerError).loc
13 | if (!loc) {
14 | return
15 | }
16 | const locString = `:${loc.start.line}:${loc.start.column}`
17 | const filePath = chalk.gray(`at ${file}${locString}`)
18 | const codeframe = generateCodeFrame(source, loc.start.offset, loc.end.offset)
19 | err.message = `\n${chalk.red(
20 | `VueCompilerError: ${err.message}`
21 | )}\n${filePath}\n${chalk.yellow(codeframe)}\n`
22 | }
23 |
--------------------------------------------------------------------------------
/src/hotReload.ts:
--------------------------------------------------------------------------------
1 | // __VUE_HMR_RUNTIME__ is injected to global scope by @vue/runtime-core
2 |
3 | export function genHotReloadCode(
4 | id: string,
5 | templateRequest: string | undefined
6 | ): string {
7 | return `
8 | /* hot reload */
9 | if (module.hot) {
10 | __exports__.__hmrId = "${id}"
11 | const api = __VUE_HMR_RUNTIME__
12 | module.hot.accept()
13 | if (!api.createRecord('${id}', __exports__)) {
14 | api.reload('${id}', __exports__)
15 | }
16 | ${templateRequest ? genTemplateHotReloadCode(id, templateRequest) : ''}
17 | }
18 | `
19 | }
20 |
21 | function genTemplateHotReloadCode(id: string, request: string) {
22 | return `
23 | module.hot.accept(${request}, () => {
24 | api.rerender('${id}', render)
25 | })
26 | `
27 | }
28 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import type { LoaderContext } from 'webpack'
2 | import * as path from 'path'
3 | import * as crypto from 'crypto'
4 | import * as qs from 'querystring'
5 |
6 | import { compiler } from './compiler'
7 | import type {
8 | TemplateCompiler,
9 | CompilerOptions,
10 | SFCBlock,
11 | SFCTemplateCompileOptions,
12 | SFCScriptCompileOptions,
13 | } from 'vue/compiler-sfc'
14 | import { selectBlock } from './select'
15 | import { genHotReloadCode } from './hotReload'
16 | import { genCSSModulesCode } from './cssModules'
17 | import { formatError } from './formatError'
18 |
19 | import VueLoaderPlugin from './plugin'
20 | import { canInlineTemplate } from './resolveScript'
21 | import { setDescriptor } from './descriptorCache'
22 | import {
23 | getOptions,
24 | stringifyRequest as _stringifyRequest,
25 | genMatchResource,
26 | testWebpack5,
27 | } from './util'
28 |
29 | export { VueLoaderPlugin }
30 |
31 | export interface VueLoaderOptions {
32 | // https://babeljs.io/docs/en/next/babel-parser#plugins
33 | babelParserPlugins?: SFCScriptCompileOptions['babelParserPlugins']
34 | transformAssetUrls?: SFCTemplateCompileOptions['transformAssetUrls']
35 | compiler?: TemplateCompiler | string
36 | compilerOptions?: CompilerOptions
37 | /**
38 | * TODO remove in 3.4
39 | * @deprecated
40 | */
41 | reactivityTransform?: boolean
42 |
43 | /**
44 | * @experimental
45 | */
46 | propsDestructure?: boolean
47 | /**
48 | * @experimental
49 | */
50 | defineModel?: boolean
51 |
52 | customElement?: boolean | RegExp
53 |
54 | hotReload?: boolean
55 | exposeFilename?: boolean
56 | appendExtension?: boolean
57 | enableTsInTemplate?: boolean
58 | experimentalInlineMatchResource?: boolean
59 |
60 | isServerBuild?: boolean
61 | }
62 |
63 | let errorEmitted = false
64 |
65 | const { parse } = compiler
66 | const exportHelperPath = require.resolve('./exportHelper')
67 |
68 | function hash(text: string): string {
69 | return crypto.createHash('sha256').update(text).digest('hex').substring(0, 8)
70 | }
71 |
72 | export default function loader(
73 | this: LoaderContext,
74 | source: string
75 | ) {
76 | const loaderContext = this
77 |
78 | // check if plugin is installed
79 | if (
80 | !errorEmitted &&
81 | !(loaderContext as any)['thread-loader'] &&
82 | !(loaderContext as any)[VueLoaderPlugin.NS]
83 | ) {
84 | loaderContext.emitError(
85 | new Error(
86 | `vue-loader was used without the corresponding plugin. ` +
87 | `Make sure to include VueLoaderPlugin in your webpack config.`
88 | )
89 | )
90 | errorEmitted = true
91 | }
92 |
93 | const stringifyRequest = (r: string) => _stringifyRequest(loaderContext, r)
94 |
95 | const {
96 | mode,
97 | target,
98 | sourceMap,
99 | rootContext,
100 | resourcePath,
101 | resourceQuery: _resourceQuery = '',
102 | _compiler,
103 | } = loaderContext
104 |
105 | const isWebpack5 = testWebpack5(_compiler)
106 | const rawQuery = _resourceQuery.slice(1)
107 | const incomingQuery = qs.parse(rawQuery)
108 | const resourceQuery = rawQuery ? `&${rawQuery}` : ''
109 | const options = (getOptions(loaderContext) || {}) as VueLoaderOptions
110 | const enableInlineMatchResource =
111 | isWebpack5 && Boolean(options.experimentalInlineMatchResource)
112 |
113 | const isServer = options.isServerBuild ?? target === 'node'
114 | const isProduction =
115 | mode === 'production' || process.env.NODE_ENV === 'production'
116 |
117 | const filename = resourcePath.replace(/\?.*$/, '')
118 |
119 | const { descriptor, errors } = parse(source, {
120 | filename,
121 | sourceMap,
122 | templateParseOptions: options.compilerOptions,
123 | })
124 |
125 | const asCustomElement =
126 | typeof options.customElement === 'boolean'
127 | ? options.customElement
128 | : (options.customElement || /\.ce\.vue$/).test(filename)
129 |
130 | // cache descriptor
131 | setDescriptor(filename, descriptor)
132 |
133 | if (errors.length) {
134 | errors.forEach((err) => {
135 | formatError(err, source, resourcePath)
136 | loaderContext.emitError(err)
137 | })
138 | return ``
139 | }
140 |
141 | // module id for scoped CSS & hot-reload
142 | const rawShortFilePath = path
143 | .relative(rootContext || process.cwd(), filename)
144 | .replace(/^(\.\.[\/\\])+/, '')
145 | const shortFilePath = rawShortFilePath.replace(/\\/g, '/')
146 | const id = hash(
147 | isProduction
148 | ? shortFilePath + '\n' + source.replace(/\r\n/g, '\n')
149 | : shortFilePath
150 | )
151 |
152 | // if the query has a type field, this is a language block request
153 | // e.g. foo.vue?type=template&id=xxxxx
154 | // and we will return early
155 | if (incomingQuery.type) {
156 | return selectBlock(
157 | descriptor,
158 | id,
159 | options,
160 | loaderContext,
161 | incomingQuery,
162 | !!options.appendExtension
163 | )
164 | }
165 |
166 | // feature information
167 | const hasScoped = descriptor.styles.some((s) => s.scoped)
168 | const needsHotReload =
169 | !isServer &&
170 | !isProduction &&
171 | !!(descriptor.script || descriptor.scriptSetup || descriptor.template) &&
172 | options.hotReload !== false
173 |
174 | // extra properties to attach to the script object
175 | // we need to do this in a tree-shaking friendly manner
176 | const propsToAttach: [string, string][] = []
177 |
178 | // script
179 | let scriptImport = `const script = {}`
180 | let isTS = false
181 | const { script, scriptSetup } = descriptor
182 | if (script || scriptSetup) {
183 | const lang = script?.lang || scriptSetup?.lang
184 | isTS = !!(lang && /tsx?/.test(lang))
185 | const externalQuery = Boolean(script && !scriptSetup && script.src)
186 | ? `&external`
187 | : ``
188 | const src = (script && !scriptSetup && script.src) || resourcePath
189 | const attrsQuery = attrsToQuery((scriptSetup || script)!.attrs, 'js')
190 | const query = `?vue&type=script${attrsQuery}${resourceQuery}${externalQuery}`
191 |
192 | let scriptRequest: string
193 |
194 | if (enableInlineMatchResource) {
195 | scriptRequest = stringifyRequest(
196 | genMatchResource(this, src, query, lang || 'js')
197 | )
198 | } else {
199 | scriptRequest = stringifyRequest(src + query)
200 | }
201 |
202 | scriptImport =
203 | `import script from ${scriptRequest}\n` +
204 | // support named exports
205 | `export * from ${scriptRequest}`
206 | }
207 |
208 | // template
209 | let templateImport = ``
210 | let templateRequest
211 | const renderFnName = isServer ? `ssrRender` : `render`
212 | const useInlineTemplate = canInlineTemplate(descriptor, isProduction)
213 | if (descriptor.template && !useInlineTemplate) {
214 | const src = descriptor.template.src || resourcePath
215 | const externalQuery = Boolean(descriptor.template.src) ? `&external` : ``
216 | const idQuery = `&id=${id}`
217 | const scopedQuery = hasScoped ? `&scoped=true` : ``
218 | const attrsQuery = attrsToQuery(descriptor.template.attrs)
219 | const tsQuery =
220 | options.enableTsInTemplate !== false && isTS ? `&ts=true` : ``
221 | const query = `?vue&type=template${idQuery}${scopedQuery}${tsQuery}${attrsQuery}${resourceQuery}${externalQuery}`
222 |
223 | if (enableInlineMatchResource) {
224 | templateRequest = stringifyRequest(
225 | genMatchResource(
226 | this,
227 | src,
228 | query,
229 | options.enableTsInTemplate !== false && isTS ? 'ts' : 'js'
230 | )
231 | )
232 | } else {
233 | templateRequest = stringifyRequest(src + query)
234 | }
235 |
236 | templateImport = `import { ${renderFnName} } from ${templateRequest}`
237 | propsToAttach.push([renderFnName, renderFnName])
238 | }
239 |
240 | // styles
241 | let stylesCode = ``
242 | let hasCSSModules = false
243 | const nonWhitespaceRE = /\S+/
244 | if (descriptor.styles.length) {
245 | descriptor.styles
246 | .filter((style) => style.src || nonWhitespaceRE.test(style.content))
247 | .forEach((style, i) => {
248 | const src = style.src || resourcePath
249 | const attrsQuery = attrsToQuery(style.attrs, 'css')
250 | const lang = String(style.attrs.lang || 'css')
251 | // make sure to only pass id when necessary so that we don't inject
252 | // duplicate tags when multiple components import the same css file
253 | const idQuery = !style.src || style.scoped ? `&id=${id}` : ``
254 | const inlineQuery = asCustomElement ? `&inline` : ``
255 | const externalQuery = Boolean(style.src) ? `&external` : ``
256 | const query = `?vue&type=style&index=${i}${idQuery}${inlineQuery}${attrsQuery}${resourceQuery}${externalQuery}`
257 |
258 | let styleRequest
259 | if (enableInlineMatchResource) {
260 | styleRequest = stringifyRequest(
261 | genMatchResource(this, src, query, lang)
262 | )
263 | } else {
264 | styleRequest = stringifyRequest(src + query)
265 | }
266 |
267 | if (style.module) {
268 | if (asCustomElement) {
269 | loaderContext.emitError(
270 | new Error(
271 | `
20 |
--------------------------------------------------------------------------------
/test/fixtures/css-modules-extend.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/test/fixtures/css-modules-simple.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
10 |
--------------------------------------------------------------------------------
/test/fixtures/css-modules.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
17 |
18 |
21 |
--------------------------------------------------------------------------------
/test/fixtures/custom-import.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{msg}}
6 |
7 |
8 |
17 |
18 |
23 |
--------------------------------------------------------------------------------
/test/fixtures/custom-language.vue:
--------------------------------------------------------------------------------
1 |
2 | describe('example', () => {
3 | it('basic', done => {
4 | done();
5 | })
6 | })
7 |
8 |
9 |
10 | This is example documentation for a component.
11 |
12 |
13 |
14 | {{msg}}
15 |
16 |
17 |
26 |
27 |
32 |
--------------------------------------------------------------------------------
/test/fixtures/custom-query.vue:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/test/fixtures/duplicate-cssm.css:
--------------------------------------------------------------------------------
1 | @value color: red;
2 |
--------------------------------------------------------------------------------
/test/fixtures/duplicate-cssm.js:
--------------------------------------------------------------------------------
1 | import values from './duplicate-cssm.css'
2 | import Comp from './duplicate-cssm.vue'
3 |
4 | export { values }
5 | export default Comp
6 |
7 | window.exports = values
8 |
--------------------------------------------------------------------------------
/test/fixtures/duplicate-cssm.vue:
--------------------------------------------------------------------------------
1 |
2 | hi
3 |
4 |
5 |
12 |
--------------------------------------------------------------------------------
/test/fixtures/empty-style.vue:
--------------------------------------------------------------------------------
1 |
2 | empty style
3 |
4 |
5 |
7 |
--------------------------------------------------------------------------------
/test/fixtures/entry.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 |
3 | import Component from '~target'
4 | import * as exports from '~target'
5 |
6 | if (typeof window !== 'undefined') {
7 | window.componentModule = Component
8 | window.exports = exports
9 |
10 | const app = createApp(Component)
11 | const container = window.document.createElement('div')
12 | container.id = 'app'
13 | window.instance = app.mount(container)
14 | window.document.body.appendChild(container)
15 | }
16 |
17 | export default Component
18 |
--------------------------------------------------------------------------------
/test/fixtures/extract-css-chunks.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
16 |
17 |
22 |
--------------------------------------------------------------------------------
/test/fixtures/extract-css.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
11 |
12 |
15 |
--------------------------------------------------------------------------------
/test/fixtures/i18n-entry.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import { createI18n } from 'vue-i18n'
3 |
4 | import Component from './i18n.vue'
5 | import * as exports from './i18n.vue'
6 |
7 | const i18n = createI18n({
8 | locale: 'de',
9 | silentFallbackWarn: true,
10 | silentTranslationWarn: true,
11 | })
12 |
13 | if (typeof window !== 'undefined') {
14 | window.componentModule = Component
15 | window.exports = exports
16 |
17 | const app = createApp(Component).use(i18n)
18 |
19 | const container = window.document.createElement('div')
20 | window.instance = app.mount(container)
21 | }
22 |
23 | export default Component
24 |
--------------------------------------------------------------------------------
/test/fixtures/i18n.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ $t('test') }}
3 |
4 |
5 |
6 | test: Example Text
7 |
8 |
--------------------------------------------------------------------------------
/test/fixtures/imported-types-aliased.ts:
--------------------------------------------------------------------------------
1 | export interface Props {
2 | id?: number
3 | }
4 |
--------------------------------------------------------------------------------
/test/fixtures/imported-types.ts:
--------------------------------------------------------------------------------
1 | export interface Props {
2 | msg: string
3 | }
4 |
--------------------------------------------------------------------------------
/test/fixtures/imported-types.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 | {{ Object.keys(props) }}
10 |
11 |
--------------------------------------------------------------------------------
/test/fixtures/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/test/fixtures/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vuejs/vue-loader/698636508e08f5379a57eaf086b5ff533af8e051/test/fixtures/logo.png
--------------------------------------------------------------------------------
/test/fixtures/markdown.vue:
--------------------------------------------------------------------------------
1 | ## {{msg}}
2 |
3 |
12 |
--------------------------------------------------------------------------------
/test/fixtures/named-exports.vue:
--------------------------------------------------------------------------------
1 |
9 | Terms
10 |
--------------------------------------------------------------------------------
/test/fixtures/no-script.vue:
--------------------------------------------------------------------------------
1 |
2 | hello
3 |
4 |
5 |
10 |
--------------------------------------------------------------------------------
/test/fixtures/optional-chaining.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
17 |
--------------------------------------------------------------------------------
/test/fixtures/postcss.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
10 |
--------------------------------------------------------------------------------
/test/fixtures/pre.vue:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 | div
11 | h1 This is the app
12 | comp-a
13 | comp-b
14 |
15 |
16 |
23 |
--------------------------------------------------------------------------------
/test/fixtures/process-custom-file/custom-file.svg:
--------------------------------------------------------------------------------
1 |
2 | ProcessedCustomFile
3 |
--------------------------------------------------------------------------------
/test/fixtures/process-custom-file/process-custom-file.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/fixtures/resolve.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
15 |
--------------------------------------------------------------------------------
/test/fixtures/scoped-css.vue:
--------------------------------------------------------------------------------
1 |
64 |
65 |
66 |
67 |
hi
68 |
hi
69 |
yo
70 |
73 |
74 |
75 |
76 |
83 |
--------------------------------------------------------------------------------
/test/fixtures/script-import.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | msg: 'Hello from Component A!',
5 | }
6 | },
7 | }
8 |
--------------------------------------------------------------------------------
/test/fixtures/script-import.vue:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/test/fixtures/style-import-scoped.css:
--------------------------------------------------------------------------------
1 | h1 { color: green; }
2 |
--------------------------------------------------------------------------------
/test/fixtures/style-import-twice-sub.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/test/fixtures/style-import-twice.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
--------------------------------------------------------------------------------
/test/fixtures/style-import.css:
--------------------------------------------------------------------------------
1 | h1 { color: red; }
2 |
--------------------------------------------------------------------------------
/test/fixtures/style-import.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/test/fixtures/style-v-bind.vue:
--------------------------------------------------------------------------------
1 |
2 | hello
3 |
4 |
5 |
17 |
18 |
26 |
--------------------------------------------------------------------------------
/test/fixtures/template-import-pre.vue:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/test/fixtures/template-import.html:
--------------------------------------------------------------------------------
1 |
2 |
hello
3 |
4 |
--------------------------------------------------------------------------------
/test/fixtures/template-import.pug:
--------------------------------------------------------------------------------
1 | div
2 | h1 hello
3 |
--------------------------------------------------------------------------------
/test/fixtures/template-import.vue:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/test/fixtures/ts.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ msg }}
3 |
4 |
5 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/test/fixtures/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "paths": {
4 | "foo": ["./imported-types-aliased.ts"]
5 | }
6 | },
7 | "include": ["."]
8 | }
9 |
--------------------------------------------------------------------------------
/test/fixtures/unit-test.js:
--------------------------------------------------------------------------------
1 | describe('example', () => {
2 | it('basic', (done) => {
3 | done()
4 | })
5 | })
6 |
--------------------------------------------------------------------------------
/test/mock-loaders/docs.js:
--------------------------------------------------------------------------------
1 | module.exports = function (source, map) {
2 | this.callback(
3 | null,
4 | `export default Component => {
5 | Component.__docs = ${JSON.stringify(source)}
6 | }`,
7 | map
8 | )
9 | }
10 |
--------------------------------------------------------------------------------
/test/mock-loaders/html.js:
--------------------------------------------------------------------------------
1 | module.exports = function (content) {
2 | return content.replace(/red/, 'green')
3 | }
4 |
--------------------------------------------------------------------------------
/test/mock-loaders/js.js:
--------------------------------------------------------------------------------
1 | module.exports = function (content) {
2 | return content.replace(/Hello from Component A!/, 'Changed!')
3 | }
4 |
--------------------------------------------------------------------------------
/test/mock-loaders/query.js:
--------------------------------------------------------------------------------
1 | module.exports = function (content) {
2 | const query = this.resourceQuery.slice(1)
3 |
4 | if (/change/.test(query)) {
5 | return `
6 |
7 | Changed!
8 |
9 |
18 | `
19 | }
20 |
21 | return content
22 | }
23 |
--------------------------------------------------------------------------------
/test/script.spec.ts:
--------------------------------------------------------------------------------
1 | import { mockBundleAndRun } from './utils'
2 |
3 | test('named exports', async () => {
4 | const { exports } = await mockBundleAndRun({
5 | entry: 'named-exports.vue',
6 | })
7 | expect(exports.default.name).toBe('named-exports')
8 | expect(exports.foo()).toBe(1)
9 | })
10 |
11 | test('experimental