Skip to content

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

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

Merged
merged 1 commit into from
Oct 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions packages/@vue/cli-service/__tests__/modernMode.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
4 changes: 3 additions & 1 deletion packages/@vue/cli-service/lib/commands/build/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const defaults = {
clean: true,
target: 'app'
target: 'app',
'unsafe-inline': true
}

const buildModes = {
Expand All @@ -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`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@ 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
config
.plugin('modern-mode-modern')
.use(ModernModePlugin, [{
targetDir,
isModernBuild: true
isModernBuild: true,
unsafeInline: args['unsafe-inline']
}])
}
}
Expand Down
42 changes: 34 additions & 8 deletions packages/@vue/cli-service/lib/webpack/ModernModePlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand All @@ -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()
Expand Down