feat: add --no-unsafe-inline flag for modern mode (#2741)

closes #2570
This commit is contained in:
Haoqun Jiang
2018-10-29 19:14:11 +08:00
committed by GitHub
parent 7096bacab3
commit 38efc032e5
4 changed files with 56 additions and 11 deletions
@@ -76,6 +76,21 @@ test('modern mode', async () => {
expect(await getH1Text()).toMatch('Welcome to Your Vue.js App')
})
test('no-unsafe-inline', async () => {
const project = await create('no-unsafe-inline', defaultPreset)
const { stdout } = await project.run('vue-cli-service build --modern --no-unsafe-inline')
expect(stdout).toMatch('Build complete.')
// should output a seperate safari-nomodule-fix bundle
const files = await fs.readdir(path.join(project.dir, 'dist/js'))
expect(files.some(f => /^safari-nomodule-fix\.js$/.test(f))).toBe(true)
// should contain no inline scripts in the output html
const index = await project.read('dist/index.html')
expect(index).not.toMatch(/[^>]\s*<\/script>/)
})
afterAll(async () => {
if (browser) {
await browser.close()
@@ -1,6 +1,7 @@
const defaults = {
clean: true,
target: 'app'
target: 'app',
'unsafe-inline': true
}
const buildModes = {
@@ -25,6 +26,7 @@ module.exports = (api, options) => {
'--mode': `specify env mode (default: production)`,
'--dest': `specify output directory (default: ${options.outputDir})`,
'--modern': `build app targeting modern browsers with auto fallback`,
'--no-unsafe-inline': `build app without introducing inline scripts`,
'--target': `app | lib | wc | wc-async (default: ${defaults.target})`,
'--name': `name for lib or web-component mode (default: "name" in package.json or entry filename)`,
'--no-clean': `do not remove the dist directory before building the project`,
@@ -18,7 +18,8 @@ module.exports = (api, args, options) => {
.plugin('modern-mode-legacy')
.use(ModernModePlugin, [{
targetDir,
isModernBuild: false
isModernBuild: false,
unsafeInline: args['unsafe-inline']
}])
} else {
// Inject plugin to read non-modern build stats and inject HTML
@@ -26,7 +27,8 @@ module.exports = (api, args, options) => {
.plugin('modern-mode-modern')
.use(ModernModePlugin, [{
targetDir,
isModernBuild: true
isModernBuild: true,
unsafeInline: args['unsafe-inline']
}])
}
}
@@ -5,9 +5,10 @@ const path = require('path')
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()}}();`
class ModernModePlugin {
constructor ({ targetDir, isModernBuild }) {
constructor ({ targetDir, isModernBuild, unsafeInline }) {
this.targetDir = targetDir
this.isModernBuild = isModernBuild
this.unsafeInline = unsafeInline
}
apply (compiler) {
@@ -56,13 +57,6 @@ class ModernModePlugin {
}
})
// inject Safari 10 nomodule fix
data.body.push({
tagName: 'script',
closeTag: true,
innerHTML: safariFix
})
// inject links for legacy assets as <script nomodule>
const htmlName = path.basename(data.plugin.options.filename)
// Watch out for output files in sub directories
@@ -71,6 +65,38 @@ class ModernModePlugin {
const legacyAssets = JSON.parse(await fs.readFile(tempFilename, 'utf-8'))
.filter(a => a.tagName === 'script' && a.attributes)
legacyAssets.forEach(a => { a.attributes.nomodule = '' })
if (this.unsafeInline) {
// inject inline Safari 10 nomodule fix
data.body.push({
tagName: 'script',
closeTag: true,
innerHTML: safariFix
})
} else {
// inject the fix as an external script
const safariFixPath = legacyAssets[0].attributes.src
.split('/')
.slice(0, -1)
.concat(['safari-nomodule-fix.js'])
.join('/')
compilation.assets[safariFixPath] = {
source: function () {
return new Buffer(safariFix)
},
size: function () {
return Buffer.byteLength(safariFix)
}
}
data.body.push({
tagName: 'script',
closeTag: true,
attributes: {
src: safariFixPath
}
})
}
data.body.push(...legacyAssets)
await fs.remove(tempFilename)
cb()