Skip to content

Commit 38efc03

Browse files
authored
feat: add --no-unsafe-inline flag for modern mode (#2741)
closes #2570
1 parent 7096bac commit 38efc03

File tree

4 files changed

+56
-11
lines changed

4 files changed

+56
-11
lines changed

packages/@vue/cli-service/__tests__/modernMode.spec.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,21 @@ test('modern mode', async () => {
7676
expect(await getH1Text()).toMatch('Welcome to Your Vue.js App')
7777
})
7878

79+
test('no-unsafe-inline', async () => {
80+
const project = await create('no-unsafe-inline', defaultPreset)
81+
82+
const { stdout } = await project.run('vue-cli-service build --modern --no-unsafe-inline')
83+
expect(stdout).toMatch('Build complete.')
84+
85+
// should output a seperate safari-nomodule-fix bundle
86+
const files = await fs.readdir(path.join(project.dir, 'dist/js'))
87+
expect(files.some(f => /^safari-nomodule-fix\.js$/.test(f))).toBe(true)
88+
89+
// should contain no inline scripts in the output html
90+
const index = await project.read('dist/index.html')
91+
expect(index).not.toMatch(/[^>]\s*<\/script>/)
92+
})
93+
7994
afterAll(async () => {
8095
if (browser) {
8196
await browser.close()

packages/@vue/cli-service/lib/commands/build/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const defaults = {
22
clean: true,
3-
target: 'app'
3+
target: 'app',
4+
'unsafe-inline': true
45
}
56

67
const buildModes = {
@@ -25,6 +26,7 @@ module.exports = (api, options) => {
2526
'--mode': `specify env mode (default: production)`,
2627
'--dest': `specify output directory (default: ${options.outputDir})`,
2728
'--modern': `build app targeting modern browsers with auto fallback`,
29+
'--no-unsafe-inline': `build app without introducing inline scripts`,
2830
'--target': `app | lib | wc | wc-async (default: ${defaults.target})`,
2931
'--name': `name for lib or web-component mode (default: "name" in package.json or entry filename)`,
3032
'--no-clean': `do not remove the dist directory before building the project`,

packages/@vue/cli-service/lib/commands/build/resolveAppConfig.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,17 @@ module.exports = (api, args, options) => {
1818
.plugin('modern-mode-legacy')
1919
.use(ModernModePlugin, [{
2020
targetDir,
21-
isModernBuild: false
21+
isModernBuild: false,
22+
unsafeInline: args['unsafe-inline']
2223
}])
2324
} else {
2425
// Inject plugin to read non-modern build stats and inject HTML
2526
config
2627
.plugin('modern-mode-modern')
2728
.use(ModernModePlugin, [{
2829
targetDir,
29-
isModernBuild: true
30+
isModernBuild: true,
31+
unsafeInline: args['unsafe-inline']
3032
}])
3133
}
3234
}

packages/@vue/cli-service/lib/webpack/ModernModePlugin.js

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ const path = require('path')
55
const safariFix = `!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()},!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();`
66

77
class ModernModePlugin {
8-
constructor ({ targetDir, isModernBuild }) {
8+
constructor ({ targetDir, isModernBuild, unsafeInline }) {
99
this.targetDir = targetDir
1010
this.isModernBuild = isModernBuild
11+
this.unsafeInline = unsafeInline
1112
}
1213

1314
apply (compiler) {
@@ -56,13 +57,6 @@ class ModernModePlugin {
5657
}
5758
})
5859

59-
// inject Safari 10 nomodule fix
60-
data.body.push({
61-
tagName: 'script',
62-
closeTag: true,
63-
innerHTML: safariFix
64-
})
65-
6660
// inject links for legacy assets as <script nomodule>
6761
const htmlName = path.basename(data.plugin.options.filename)
6862
// Watch out for output files in sub directories
@@ -71,6 +65,38 @@ class ModernModePlugin {
7165
const legacyAssets = JSON.parse(await fs.readFile(tempFilename, 'utf-8'))
7266
.filter(a => a.tagName === 'script' && a.attributes)
7367
legacyAssets.forEach(a => { a.attributes.nomodule = '' })
68+
69+
if (this.unsafeInline) {
70+
// inject inline Safari 10 nomodule fix
71+
data.body.push({
72+
tagName: 'script',
73+
closeTag: true,
74+
innerHTML: safariFix
75+
})
76+
} else {
77+
// inject the fix as an external script
78+
const safariFixPath = legacyAssets[0].attributes.src
79+
.split('/')
80+
.slice(0, -1)
81+
.concat(['safari-nomodule-fix.js'])
82+
.join('/')
83+
compilation.assets[safariFixPath] = {
84+
source: function () {
85+
return new Buffer(safariFix)
86+
},
87+
size: function () {
88+
return Buffer.byteLength(safariFix)
89+
}
90+
}
91+
data.body.push({
92+
tagName: 'script',
93+
closeTag: true,
94+
attributes: {
95+
src: safariFixPath
96+
}
97+
})
98+
}
99+
74100
data.body.push(...legacyAssets)
75101
await fs.remove(tempFilename)
76102
cb()

0 commit comments

Comments
 (0)