-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
feat(warn): warn when an existing property starting with $ is not pro… #8214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
8604075
8dd1b54
abe72a7
690d9b9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,16 @@ if (process.env.NODE_ENV !== 'production') { | |
) | ||
} | ||
|
||
const warnStartingWithDollar = (target, key) => { | ||
warn( | ||
`Property "${key}" must be accessed with "$data.${key}" because ` + | ||
'properties starting with "$" or "_" are not proxied in the Vue instance to ' + | ||
'prevent conflicts with Vue internals' + | ||
'See: https://vuejs.org/v2/api/#data', | ||
target | ||
) | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we do the same thing when we come across properties prefixed with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that's true, I thought there is an eslint warning for it. Let me check again There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added that as well but I wonder if it is correct. I'm not sure what babel helpers are we talking about in 8e1478e There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not proxying both? I changed all mixins in a big project to respect this rule on Style Guide (https://vuejs.org/v2/style-guide/#Private-property-names-essential) and now when I am trying to pass it to a component prop it gets there undefined because it is not being proxied There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. to prevent conflicts. We cannot check all existing properties (which would be ideal), for conflicts, so we test that instead. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yet the style guide recommends it, I think this issue should be given some thought, either change the rule for private property names or proxy everything, (maybe giving a warning in development process). Not proxying this is removing functionality and forcing developers that follow the recommended style guide find workarounds because of limited functionality to prevent others who may not read the documentation and override vue properties. |
||
const hasProxy = | ||
typeof Proxy !== 'undefined' && isNative(Proxy) | ||
|
||
|
@@ -45,9 +55,11 @@ if (process.env.NODE_ENV !== 'production') { | |
const hasHandler = { | ||
has (target, key) { | ||
const has = key in target | ||
const isAllowed = allowedGlobals(key) || (typeof key === 'string' && key.charAt(0) === '_') | ||
const isAllowed = allowedGlobals(key) || | ||
(typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data)) | ||
if (!has && !isAllowed) { | ||
warnNonPresent(target, key) | ||
if (key in target.$data) warnStartingWithDollar(target, key) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it have to be some property starting with preserved prefixes here? It feels a little weird to me that after these checks we concluded that the property starts with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if the key is in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Proxying properties starting with $_ would be an option |
||
else warnNonPresent(target, key) | ||
} | ||
return has || !isAllowed | ||
} | ||
|
@@ -56,7 +68,8 @@ if (process.env.NODE_ENV !== 'production') { | |
const getHandler = { | ||
get (target, key) { | ||
if (typeof key === 'string' && !(key in target)) { | ||
warnNonPresent(target, key) | ||
if (key in target.$data) warnStartingWithDollar(target, key) | ||
else warnNonPresent(target, key) | ||
} | ||
return target[key] | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,5 +45,50 @@ if (typeof Proxy !== 'undefined') { | |
|
||
expect(vm.$el.textContent).toBe('foo') | ||
}) | ||
|
||
it('should warn properties starting with $ when found', () => { | ||
new Vue({ | ||
data: { $a: 'foo' }, | ||
template: `<div>{{ $a }}</div>` | ||
}).$mount() | ||
expect(`Property "$a" must be accessed with "$data.$a"`).toHaveBeenWarned() | ||
}) | ||
|
||
it('should warn properties starting with _ when found', () => { | ||
new Vue({ | ||
data: { _foo: 'foo' }, | ||
template: `<div>{{ _foo }}</div>` | ||
}).$mount() | ||
expect(`Property "_foo" must be accessed with "$data._foo"`).toHaveBeenWarned() | ||
}) | ||
|
||
it('should warn properties starting with $ when not found', () => { | ||
new Vue({ | ||
template: `<div>{{ $a }}</div>` | ||
}).$mount() | ||
expect(`Property or method "$a" is not defined`).toHaveBeenWarned() | ||
expect(`Property "$a" must be accessed with "$data.$a"`).not.toHaveBeenWarned() | ||
}) | ||
|
||
it('should warn properties starting with $ when not found (with stripped)', () => { | ||
const render = function (h) { | ||
return h('p', this.$a) | ||
} | ||
render._withStripped = true | ||
new Vue({ | ||
data: { $a: 'foo' }, | ||
render | ||
}).$mount() | ||
expect(`Property "$a" must be accessed with "$data.$a"`).toHaveBeenWarned() | ||
}) | ||
|
||
it('should not warn properties starting with $ when using $data to access', () => { | ||
new Vue({ | ||
data: { $a: 'foo' }, | ||
template: `<div>{{ $data.$a }}</div>` | ||
}).$mount() | ||
expect(`Property or method "$a" is not defined`).not.toHaveBeenWarned() | ||
expect(`Property or method "$a" is not defined`).not.toHaveBeenWarned() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These two expects are identical, is that accidental? |
||
}) | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something like
warnPreservedPrefix
?