From 001382dad684b409082b7196b40a5c52a3a3169e Mon Sep 17 00:00:00 2001 From: Haoqun Jiang Date: Thu, 24 Jan 2019 01:00:02 +0800 Subject: [PATCH] feat: make `__file` injection opt-in in production (#1475) --- docs/options.md | 9 +++++++++ lib/index.js | 17 +++++++++-------- test/advanced.spec.js | 20 +++++++++++++++++++- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/docs/options.md b/docs/options.md index 282ea8099..f57932b96 100644 --- a/docs/options.md +++ b/docs/options.md @@ -92,3 +92,12 @@ When both options are specified, enables file-system-based template compilation - default: `true` In development mode, we use [prettier](https://prettier.io/) to format the compiled render function for ease of debugging by default. However, if you encounter any obscure bug of prettier, such as [exponential compilation time for deeply nested functions](https://github.com/prettier/prettier/issues/4672), you can disable this option to circumvent it. + +## exposeFilename + +- type: `boolean` +- default: `false` + +In non-production environments, vue-loader injects a `__file` property to components for better debugging experience. If the `name` property is missing in a component, Vue will infer it from the `__file` field to display in console warnings. + +This property is stripped in production builds by default. But you may want to retain it if you are developing a component library and don't want to bother specifying `name` in each component. Then you can turn this option on. diff --git a/lib/index.js b/lib/index.js index 752f9854e..f33663aa4 100644 --- a/lib/index.js +++ b/lib/index.js @@ -176,14 +176,15 @@ var component = normalizer( } // Expose filename. This is used by the devtools and Vue runtime warnings. - code += `\ncomponent.options.__file = ${ - isProduction - // For security reasons, only expose the file's basename in production. - ? JSON.stringify(filename) - // Expose the file's full path in development, so that it can be opened - // from the devtools. - : JSON.stringify(rawShortFilePath.replace(/\\/g, '/')) - }` + if (!isProduction) { + // Expose the file's full path in development, so that it can be opened + // from the devtools. + code += `\ncomponent.options.__file = ${JSON.stringify(rawShortFilePath.replace(/\\/g, '/'))}` + } else if (options.exposeFilename) { + // Libraies can opt-in to expose their components' filenames in production builds. + // For security reasons, only expose the file's basename in production. + code += `\ncomponent.options.__file = ${JSON.stringify(filename)}` + } code += `\nexport default component.exports` // console.log(code) diff --git a/test/advanced.spec.js b/test/advanced.spec.js index 9379ff84f..212ef4ef2 100644 --- a/test/advanced.spec.js +++ b/test/advanced.spec.js @@ -54,13 +54,31 @@ test('expose file path as __file outside production', done => { }) }) -test('expose file basename as __file in production', done => { +test('no __file in production when exposeFilename disabled', done => { const origNodeEnv = process.env.NODE_ENV process.env.NODE_ENV = 'production' mockBundleAndRun( { entry: 'basic.vue' }, + ({ module }) => { + expect(module.__file).toBe(undefined) + process.env.NODE_ENV = origNodeEnv + done() + } + ) +}) + +test('expose file basename as __file in production when exposeFilename enabled', done => { + const origNodeEnv = process.env.NODE_ENV + process.env.NODE_ENV = 'production' + mockBundleAndRun( + { + entry: 'basic.vue', + vue: { + exposeFilename: true + } + }, ({ module }) => { expect(module.__file).toBe('basic.vue') process.env.NODE_ENV = origNodeEnv