@@ -25,29 +25,16 @@ class VueLoaderPlugin {
25
25
} )
26
26
}
27
27
28
- // get a hold of the raw rules
29
- const rawRules = compiler . options . module . rules . slice ( )
30
28
// use webpack's RuleSet utility to normalize user rules
31
- const rawNormalizedRules = new RuleSet ( rawRules ) . rules
32
-
33
- const createMatcher = fakeFile => ( rule , i ) => {
34
- // #1201 we need to skip the `include` check when locating the vue rule
35
- const clone = Object . assign ( { } , rule )
36
- delete clone . include
37
- const normalized = RuleSet . normalizeRule ( clone , { } , '' )
38
- return (
39
- ! rule . enforce &&
40
- normalized . resource &&
41
- normalized . resource ( fakeFile )
42
- )
43
- }
29
+ const rawRules = compiler . options . module . rules
30
+ const { rules } = new RuleSet ( rawRules )
44
31
45
32
// find the rule that applies to vue files
46
33
let vueRuleIndex = rawRules . findIndex ( createMatcher ( `foo.vue` ) )
47
34
if ( vueRuleIndex < 0 ) {
48
35
vueRuleIndex = rawRules . findIndex ( createMatcher ( `foo.vue.html` ) )
49
36
}
50
- const vueRule = rawRules [ vueRuleIndex ]
37
+ const vueRule = rules [ vueRuleIndex ]
51
38
52
39
if ( ! vueRule ) {
53
40
throw new Error (
@@ -62,12 +49,10 @@ class VueLoaderPlugin {
62
49
)
63
50
}
64
51
65
- // find the normalized version of the vue rule
66
- const normalizedVueRule = rawNormalizedRules [ vueRuleIndex ]
67
52
// get the normlized "use" for vue files
68
- const normalizedVueUse = normalizedVueRule . use
53
+ const vueUse = vueRule . use
69
54
// get vue-loader options
70
- const vueLoaderUseIndex = normalizedVueUse . findIndex ( u => {
55
+ const vueLoaderUseIndex = vueUse . findIndex ( u => {
71
56
return / ^ v u e - l o a d e r | ( \/ | \\ ) v u e - l o a d e r / . test ( u . loader )
72
57
} )
73
58
@@ -81,76 +66,69 @@ class VueLoaderPlugin {
81
66
// make sure vue-loader options has a known ident so that we can share
82
67
// options by reference in the template-loader by using a ref query like
83
68
// template-loader??vue-loader-options
84
- const ident = 'vue-loader-options'
85
- const vueLoaderUse = normalizedVueUse [ vueLoaderUseIndex ]
86
- // has options, just set ident
87
- if ( vueLoaderUse . options ) {
88
- vueLoaderUse . options . ident = ident
89
- } else {
90
- // user provided no options, but we must ensure the options is present
91
- // otherwise RuleSet throws error if no option for a given ref is found.
92
- if ( vueRule . loader || vueRule . loaders ) {
93
- vueRule . options = { ident }
94
- } else if ( Array . isArray ( vueRule . use ) ) {
95
- const use = vueRule . use [ vueLoaderUseIndex ]
96
- if ( typeof use === 'string' ) {
97
- vueRule . use [ vueLoaderUseIndex ] = { loader : use , options : { ident } }
98
- } else {
99
- use . options = { ident }
100
- }
101
- } else if ( typeof vueRule . use === 'string' ) {
102
- vueRule . use = [ { loader : vueRule . use , options : { ident } } ]
103
- } else {
104
- throw new Error (
105
- `VueLoaderPlugin Error: this should not happen. Please open an issue ` +
106
- `with your webpack config.`
107
- )
108
- }
109
- }
110
-
111
- // get new rules without the vue rule
112
- const baseRules = rawRules . filter ( r => r !== vueRule )
113
- const normalizedRules = rawNormalizedRules . filter ( r => r !== normalizedVueRule )
114
-
115
- // for each user rule, inject a cloned rule by checking if the rule
116
- // matches the lang specified in the resourceQuery.
117
- rawRules . unshift . apply ( rawRules , baseRules . map ( ( rule , i ) => {
118
- return cloneRule ( rule , normalizedRules [ i ] )
119
- } ) )
120
-
121
- // inject global pitcher (responsible for injecting template compiler
122
- // loader & CSS post loader)
123
- rawRules . unshift ( {
69
+ const vueLoaderUse = vueUse [ vueLoaderUseIndex ]
70
+ vueLoaderUse . ident = 'vue-loader-options'
71
+ vueLoaderUse . options = vueLoaderUse . options || { }
72
+
73
+ // for each user rule (expect the vue rule), create a cloned rule
74
+ // that targets the corresponding language blocks in *.vue files.
75
+ const clonedRules = rules
76
+ . filter ( r => r !== vueRule )
77
+ . map ( cloneRule )
78
+
79
+ // global pitcher (responsible for injecting template compiler loader & CSS
80
+ // post loader)
81
+ const pitcher = {
124
82
loader : require . resolve ( './loaders/pitcher' ) ,
125
83
resourceQuery : query => {
126
84
const parsed = qs . parse ( query . slice ( 1 ) )
127
85
return parsed . vue != null
128
86
}
129
- } )
87
+ }
130
88
131
89
// replace original rules
132
- compiler . options . module . rules = rawRules
90
+ compiler . options . module . rules = [
91
+ pitcher ,
92
+ ...clonedRules ,
93
+ ...rules
94
+ ]
95
+ }
96
+ }
97
+
98
+ function createMatcher ( fakeFile ) {
99
+ return ( rule , i ) => {
100
+ // #1201 we need to skip the `include` check when locating the vue rule
101
+ const clone = Object . assign ( { } , rule )
102
+ delete clone . include
103
+ const normalized = RuleSet . normalizeRule ( clone , { } , '' )
104
+ return (
105
+ ! rule . enforce &&
106
+ normalized . resource &&
107
+ normalized . resource ( fakeFile )
108
+ )
133
109
}
134
110
}
135
111
136
- function cloneRule ( rule , normalizedRule ) {
112
+ function cloneRule ( rule ) {
113
+ const { resource, resourceQuery } = rule
137
114
// Assuming `test` and `resourceQuery` tests are executed in series and
138
115
// synchronously (which is true based on RuleSet's implementation), we can
139
116
// save the current resource being matched from `test` so that we can access
140
117
// it in `resourceQuery`. This ensures when we use the normalized rule's
141
118
// resource check, include/exclude are matched correctly.
142
119
let currentResource
143
120
const res = Object . assign ( { } , rule , {
144
- test : resource => {
145
- currentResource = resource
146
- return true
121
+ resource : {
122
+ test : resource => {
123
+ currentResource = resource
124
+ return true
125
+ }
147
126
} ,
148
127
resourceQuery : query => {
149
128
const parsed = qs . parse ( query . slice ( 1 ) )
150
129
if ( parsed . vue == null ) {
151
130
return false
152
131
}
153
- const { resource, resourceQuery } = normalizedRule
154
132
if ( resource && parsed . lang == null ) {
155
133
return false
156
134
}
@@ -162,50 +140,15 @@ function cloneRule (rule, normalizedRule) {
162
140
return false
163
141
}
164
142
return true
165
- } ,
166
- use : normalizedRule . use ? normalizedRule . use . map ( cleanIdent ) : undefined
143
+ }
167
144
} )
168
145
169
- // delete shorthand since we have normalized use
170
- delete res . loader
171
- delete res . loaders
172
- delete res . options
173
-
174
- // these are included in the normalized resource() check
175
- delete res . resource
176
- delete res . include
177
- delete res . exclude
178
-
179
146
if ( rule . oneOf ) {
180
- res . oneOf = rule . oneOf . map ( ( r , i ) => {
181
- return cloneRule ( r , normalizedRule . oneOf [ i ] )
182
- } )
147
+ res . oneOf = rule . oneOf . map ( cloneRule )
183
148
}
184
149
185
150
return res
186
151
}
187
152
188
- const reuseIdentWhitelist = [
189
- 'css-loader' ,
190
- '(vue-)?style-loader' ,
191
- 'postcss-loader' ,
192
- 'extract-text-webpack-plugin' ,
193
- 'mini-css-extract-plugin'
194
- ]
195
-
196
- const reuseIdentPattern = new RegExp ( `(${ reuseIdentWhitelist . join ( '|' ) } )` )
197
-
198
- function cleanIdent ( use ) {
199
- if ( use . ident ) {
200
- if ( reuseIdentPattern . test ( use . loader ) ) {
201
- // Reuse options ident, so that imports from within css-loader would get the
202
- // exact same request prefixes, avoiding duplicated modules (#1199)
203
- use . options . ident = use . ident
204
- }
205
- delete use . ident
206
- }
207
- return use
208
- }
209
-
210
153
VueLoaderPlugin . NS = NS
211
154
module . exports = VueLoaderPlugin
0 commit comments