Skip to content

Commit f4e215c

Browse files
committed
feat(plugin): add plugin work compatibility with vue-loader v15
docs(readme): include plugin usage description
1 parent 8c056de commit f4e215c

File tree

2 files changed

+228
-37
lines changed

2 files changed

+228
-37
lines changed

README.md

Lines changed: 162 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,19 @@
88
[![Maintainability](https://api.codeclimate.com/v1/badges/eeb26dd14d1b50a6ea2f/maintainability)](https://codeclimate.com/github/NetCZ/vue-separate-files-webpack-loader/maintainability)
99
[![Greenkeeper badge](https://badges.greenkeeper.io/NetCZ/vue-separate-files-webpack-loader.svg)](https://greenkeeper.io/)
1010

11-
> ## CAUTION!
12-
> Loader works with [vue-loader](https://github.com/vuejs/vue-loader) up to version 14. It **DO NOT WORK** with version 15.
13-
> Compatibility issues has been identified and solving is in progress.
11+
Creates `.vue` single file components on fly, allowing you to have clean separated components files and still enjoy
12+
advantages of [vue-loader](https://github.com/vuejs/vue-loader).
1413

15-
Creates `.vue` single file components on fly, allowing you to have clean separated components files and still enjoy advantages of [vue-loader](https://github.com/vuejs/vue-loader).
16-
17-
- Handles files by their names (instead of loading all files in folder) and creates `.vue` file on fly (instead of creating physical one)
14+
- Handles files by their names (instead of loading all files in folder) and creates `.vue` file on fly (instead of
15+
creating physical one)
1816
- Allows to add custom attributes through `options.global`, `options[FILE_TYPE]` and `options[TAG_NAME]`
1917
- Allows to handle [vue custom blocks](https://vue-loader.vuejs.org/en/configurations/custom-blocks.html)
2018
- Allows to have `scoped` style by component
2119
- Allows to define support for other file extensions / types
2220
- Allows to define test condition for loader (eg. `.vue.`, etc.)
2321

24-
> Based on these ideas [vue-builder-webpack-plugin](https://github.com/pksunkara/vue-builder-webpack-plugin) and [vue-separate-files-loader](https://github.com/iFwu/vue-separate-files-loader).
22+
> Based on these ideas [vue-builder-webpack-plugin](https://github.com/pksunkara/vue-builder-webpack-plugin) and
23+
[vue-separate-files-loader](https://github.com/iFwu/vue-separate-files-loader).
2524

2625
## Example application
2726

@@ -38,45 +37,171 @@ yarn add -D vue-separate-files-webpack-loader
3837

3938
## Usage
4039

40+
**VueLoader v15 onward**\
41+
As [vue-loader](https://github.com/vuejs/vue-loader) introduced mandatory plugin usage in version 15,
42+
which updates webpack rules, there's need to use plugin provided by `vue-separate-files-webpack-loader/plugin` in order to work
43+
with this version onward.
44+
45+
**VueLoader v14 and below**\
46+
Just don't include `vue-separate-files-webpack-loader/plugin` to your webpack configuration.
47+
4148
### Configuration
4249

43-
Loader must have precedence before `vue-loader`.
50+
#### Simple
51+
```javascript
52+
// webpack.config.js
53+
54+
const VueSeparateLoaderPlugin = require('vue-separate-files-webpack-loader/plugin')
4455

56+
module.exports = {
57+
module: {
58+
rules: [
59+
{
60+
// notice modified file test
61+
test: /\.vue\./,
62+
use: [
63+
{
64+
loader: 'vue-loader'
65+
},
66+
{
67+
loader: 'vue-separate-files-webpack-loader'
68+
}
69+
]
70+
}
71+
]
72+
},
73+
plugins: [
74+
// mandatory from VueLoader v15 onward
75+
// has to be added AFTER "new VueLoaderPlugin()"
76+
// available options below
77+
new VueSeparateLoaderPlugin(options),
78+
]
79+
}
80+
```
81+
82+
#### Complex (with options definition)
4583
```javascript
46-
rules: [
47-
{
48-
// notice modified file test
49-
test: /\.vue\./,
50-
use: [
84+
// webpack.config.js
85+
86+
const VueSeparateLoaderPlugin = require('vue-separate-files-webpack-loader/plugin')
87+
88+
module.exports = {
89+
module: {
90+
rules: [
91+
// regular VueLoader definition
92+
// use it when you want to use both component styles, otherwise you may omit it
93+
// ie SFC: Component.vue and Separated: Component.vue.html Component.vue.js
5194
{
52-
loader: 'vue-loader',
53-
options: {/* usual vue-loader options */}
95+
test: /\.vue$/,
96+
loader: 'vue-loader'
5497
},
98+
// VueSeparateFilesWebpackLoader definition
5599
{
56-
loader: 'vue-separate-files-webpack-loader',
57-
options: {
58-
// add support for other file types
59-
types: {
60-
script: '\\.re$',
61-
template: '\\.hb$'
100+
// notice modified file test
101+
test: /\.vue\./,
102+
use: [
103+
{
104+
loader: 'vue-loader',
105+
options: {/* usual vue-loader options */}
62106
},
63-
global: {
64-
// all files will have these
65-
attr: 'value'
66-
},
67-
sass: {
68-
// only SASS files will have these
69-
attr: 'value'
70-
},
71-
style: {
72-
// only style files will have these
73-
attr: 'value'
107+
{
108+
loader: 'vue-separate-files-webpack-loader',
109+
options: {
110+
// add support for other file types
111+
types: {
112+
script: '\\.re$',
113+
template: '\\.hb$'
114+
},
115+
global: {
116+
// all files will have these
117+
attr: 'value'
118+
},
119+
sass: {
120+
// only SASS files will have these
121+
attr: 'value'
122+
},
123+
style: {
124+
// only style files will have these
125+
attr: 'value'
126+
}
127+
}
74128
}
75-
}
129+
]
76130
}
77131
]
132+
},
133+
plugins: [
134+
// mandatory from VueLoader v15 onward
135+
// has to be added AFTER "new VueLoaderPlugin()"
136+
// available options below
137+
new VueSeparateLoaderPlugin(options),
138+
]
139+
}
140+
```
141+
142+
#### With VueCLI 3 generated project
143+
144+
```javascript
145+
// vue.config.js
146+
147+
const VueSeparateFilesWebpackLoaderPlugin = require('vue-separate-files-webpack-loader/plugin')
148+
149+
module.exports = {
150+
chainWebpack: config => {
151+
config
152+
.plugin('vue-separate-files-webpack-loader')
153+
.use(VueSeparateFilesWebpackLoaderPlugin, [options])
154+
.after('vue-loader')
155+
156+
config.module
157+
.rule('vue-separate-files-webpack-loader')
158+
.test(/\.vue\./)
159+
.use('vue-loader')
160+
.loader('vue-loader')
161+
.end()
162+
.use('vue-separate-files-webpack-loader')
163+
.loader('vue-separate-files-webpack-loader')
78164
}
79-
]
165+
}
166+
```
167+
168+
#### Plugin options
169+
170+
Passed as regular `Object`.
171+
172+
| Option| Default value | Description |
173+
| :--- | :--- | :--- |
174+
| test | `/\.vue\./` | When you use different file test condition in loader definition than default `/\.vue\./`, you have to define it also in plugin options. |
175+
176+
##### Example
177+
178+
```javascript
179+
// webpack.config.js
180+
181+
const VueSeparateLoaderPlugin = require('vue-separate-files-webpack-loader/plugin')
182+
183+
module.exports = {
184+
module: {
185+
rules: [
186+
{
187+
test: /\.condition\./,
188+
use: [
189+
{
190+
loader: 'vue-loader'
191+
},
192+
{
193+
loader: 'vue-separate-files-webpack-loader'
194+
}
195+
]
196+
}
197+
]
198+
},
199+
plugins: [
200+
new VueSeparateLoaderPlugin({
201+
test: /\.condition\./
202+
})
203+
]
204+
}
80205
```
81206

82207
### Supported file extensions / types
@@ -94,7 +219,7 @@ types: {
94219
}
95220
```
96221

97-
> IMPORTANT! configurations are MERGED together, so there is no way do remove default configuration
222+
> **IMPORTANT!** configurations are MERGED together, so there is no way do remove default configuration
98223
99224
### How it works
100225

@@ -118,11 +243,11 @@ Generated structure
118243
<script src="Component.vue.js"></script>
119244
```
120245

121-
This generated string is then passed to "vue-loader"
246+
This generated string is then passed to `vue-loader`
122247

123248
### Custom block support
124249

125-
Loader allows to use `vue custom blocks`.
250+
Loader allows to use **vue custom blocks**.
126251
Simply define file and its extension will be used as tag name.
127252

128253
#### Example

plugin.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
var _ = require('lodash');
2+
3+
var defaultOptions = {
4+
test: /\.vue\./
5+
};
6+
7+
function VueSeparateFilesWebpackLoaderPlugin(options) {
8+
this.options = _.assign({}, _.cloneDeep(defaultOptions), options);
9+
10+
if (!_.isRegExp(this.options.test)) {
11+
throw new Error('[VueSeparateFilesWebpackLoaderPlugin] Test condition has to be RegExp.');
12+
}
13+
14+
this.testString = this.options.test.source.replace(/\\\./g, '.');
15+
}
16+
17+
VueSeparateFilesWebpackLoaderPlugin.prototype.apply = function (compiler) {
18+
var plugins = _.filter(compiler.options.plugins, function (plugin) {
19+
var name = plugin.constructor.name;
20+
return name === 'VueLoaderPlugin' || name === 'VueSeparateFilesWebpackLoaderPlugin';
21+
});
22+
var vueLoaderPluginIndex = _.findIndex(plugins, function (plugin) {
23+
return plugin.constructor.name === 'VueLoaderPlugin';
24+
});
25+
26+
// make sure VueSeparateFilesWebpackLoaderPlugin is used after VueLoaderPlugin
27+
if (vueLoaderPluginIndex !== 0) {
28+
throw new Error('[VueSeparateFilesWebpackLoaderPlugin] Please use VueSeparateFilesWebpackLoaderPlugin after VueLoaderPlugin.');
29+
}
30+
31+
var rules = compiler.options.module.rules;
32+
var ruleIndex = _.findIndex(rules, matcher);
33+
var rule = rules[ruleIndex];
34+
35+
if (!rule) {
36+
throw new Error('[VueSeparateFilesWebpackLoaderPlugin] No matching rule for ' + this.testString + ' files found.\n' +
37+
'Make sure there is at least one root-level rule that matches ' + this.testString + ' files.\n' +
38+
'Also make sure you pass options.test property when not using default one.'
39+
)
40+
}
41+
42+
var ruleUse = _.concat([], rule.use);
43+
44+
rule = _.assign({}, rule, {
45+
resource: {
46+
test: this.options.test
47+
},
48+
resourceQuery: undefined,
49+
use: function (options) {
50+
return /separated/.test(options.resourceQuery) ? [] : ruleUse;
51+
}
52+
});
53+
54+
// remove all vue separate files webpack loader rules so when duplicated is not called multiple times
55+
compiler.options.module.rules = _.reject(compiler.options.module.rules, matcher);
56+
57+
compiler.options.module.rules.push(rule);
58+
};
59+
60+
function matcher(item) {
61+
return _.findIndex(item.use, function (use) {
62+
return use.loader === 'vue-separate-files-webpack-loader';
63+
}) !== -1;
64+
}
65+
66+
module.exports = VueSeparateFilesWebpackLoaderPlugin;

0 commit comments

Comments
 (0)