240 lines
6.5 KiB
JavaScript
240 lines
6.5 KiB
JavaScript
import html from '@rollup/plugin-html'
|
|
import { nodeResolve } from '@rollup/plugin-node-resolve'
|
|
import replace from '@rollup/plugin-replace'
|
|
import fs from 'fs'
|
|
import { createFilter } from '@rollup/pluginutils'
|
|
import { compileScript, compileStyleAsync, compileTemplate, parse } from '@vue/compiler-sfc'
|
|
import postcss from 'postcss'
|
|
import url from 'postcss-url'
|
|
import path from 'path'
|
|
import cssnano from 'cssnano'
|
|
import terser from '@rollup/plugin-terser'
|
|
|
|
const DEFAULT_VARIABLE = '__script__'
|
|
|
|
function isProduction () {
|
|
return process.env.NODE_ENV === 'production'
|
|
}
|
|
|
|
function transformScript (descriptor, id) {
|
|
if (descriptor.script === null && descriptor.scriptSetup === null) {
|
|
return {
|
|
bindings: {},
|
|
code: 'export default {}',
|
|
map: null,
|
|
descriptor
|
|
}
|
|
}
|
|
const script = compileScript(descriptor, {
|
|
id,
|
|
isProd: isProduction(),
|
|
sourceMap: true,
|
|
inlineTemplate: isProduction()
|
|
})
|
|
|
|
return {
|
|
bindings: script.bindings,
|
|
code: script.content,
|
|
map: script.map,
|
|
descriptor
|
|
}
|
|
}
|
|
|
|
function transformOptions (code) {
|
|
const newCode = code
|
|
.replaceAll('__VUE_OPTIONS_API__', 'true')
|
|
.replaceAll('__VUE_PROD_DEVTOOLS__', 'false')
|
|
|
|
return {
|
|
code: newCode,
|
|
map: null
|
|
}
|
|
}
|
|
|
|
function vuePostcss (options = {}) {
|
|
const filter = createFilter(options.include, options.exclude)
|
|
const styles = []
|
|
const components = new Map()
|
|
const processor = postcss(options.postcssPlugins || [])
|
|
let cssFileName = options.cssFileName
|
|
|
|
return {
|
|
name: 'vue-postcss',
|
|
renderStart (outputOptions, inputOptions) {
|
|
if (cssFileName) {
|
|
return
|
|
}
|
|
if (inputOptions.input.length === 0) {
|
|
this.error('cssFileName should be specified or there should be at least one input file.')
|
|
}
|
|
cssFileName = path.basename(inputOptions.input[0], '.js') + '.css'
|
|
},
|
|
async load (id) {
|
|
const [path, rawQueryString] = id.split('?')
|
|
|
|
if (!path.endsWith('.vue') || rawQueryString === undefined) {
|
|
return null
|
|
}
|
|
const queryString = new URLSearchParams(rawQueryString)
|
|
const component = components.get(path)
|
|
let snippet = {}
|
|
|
|
switch (queryString.get('type')) {
|
|
case 'template':
|
|
snippet = compileTemplate({
|
|
source: component.descriptor.template.content,
|
|
id,
|
|
filename: id,
|
|
isProd: isProduction(),
|
|
inMap: component.descriptor.template.map,
|
|
compilerOptions: {
|
|
inline: false,
|
|
bindingMetadata: component.bindings
|
|
}
|
|
})
|
|
return snippet.preamble + snippet.code
|
|
case 'script':
|
|
return component.code
|
|
default:
|
|
this.error(`Unknown vue type "${queryString.get('type')}"`)
|
|
}
|
|
},
|
|
async transform (code, id) {
|
|
if (!filter(id)) {
|
|
return
|
|
}
|
|
if (id.endsWith('/node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js')) {
|
|
return transformOptions(code)
|
|
}
|
|
if (!id.endsWith('.vue')) {
|
|
return
|
|
}
|
|
const parseResult = parse(code, {
|
|
sourceMap: true,
|
|
filename: id
|
|
})
|
|
// Throws an exception without location information, which is handled by
|
|
// rollup.
|
|
components.set(id, transformScript(parseResult.descriptor, id))
|
|
|
|
// Each component can have multiple style tags processed with PostCSS.
|
|
for (const style of parseResult.descriptor.styles) {
|
|
const compiledStyle = await compileStyleAsync({
|
|
source: style.content,
|
|
filename: id,
|
|
id,
|
|
inMap: style.map,
|
|
isProd: isProduction()
|
|
})
|
|
styles.push(compiledStyle.rawResult)
|
|
}
|
|
|
|
const source = `import { render } from '${id}?vue&type=template'\n` +
|
|
`import ${DEFAULT_VARIABLE} from '${id}?vue&type=script'\n` +
|
|
`${DEFAULT_VARIABLE}.render = render\n` +
|
|
`${DEFAULT_VARIABLE}.__file = '${id}'\n` +
|
|
`export default ${DEFAULT_VARIABLE}\n`
|
|
|
|
return {
|
|
code: source,
|
|
map: components.get(id).map
|
|
}
|
|
},
|
|
async generateBundle (options, bundle) {
|
|
const root = postcss.document()
|
|
|
|
for (const compiledStyle of styles) {
|
|
const processedStyle = await processor.process(compiledStyle, {
|
|
...compiledStyle.opts,
|
|
to: path.resolve(`${options.dir}/${cssFileName}`)
|
|
})
|
|
processedStyle.messages.forEach(message => {
|
|
switch (message.type) {
|
|
case 'warning':
|
|
this.warn({
|
|
message: message.text,
|
|
loc: { column: message.column, line: message.line },
|
|
id: processedStyle.opts.from
|
|
})
|
|
break
|
|
}
|
|
})
|
|
|
|
root.append(processedStyle.root)
|
|
}
|
|
const mapName = cssFileName + '.map'
|
|
const result = root.toResult({
|
|
to: cssFileName,
|
|
map: {
|
|
annotation: mapName
|
|
}
|
|
})
|
|
|
|
this.emitFile({
|
|
type: 'asset',
|
|
id: cssFileName,
|
|
fileName: cssFileName,
|
|
source: result.css
|
|
})
|
|
if (options.sourcemap) {
|
|
this.emitFile({
|
|
type: 'asset',
|
|
id: mapName,
|
|
fileName: mapName,
|
|
source: result.map.toString()
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export default {
|
|
input: 'assets/index.js',
|
|
output: {
|
|
dir: 'dist',
|
|
format: 'iife',
|
|
sourcemap: true
|
|
},
|
|
plugins: [
|
|
replace({
|
|
values: {
|
|
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
|
|
},
|
|
preventAssignment: true
|
|
}),
|
|
nodeResolve(),
|
|
vuePostcss({
|
|
postcssPlugins: [
|
|
url({
|
|
url: 'copy',
|
|
basePath: path.resolve('assets'),
|
|
assetsPath: '.',
|
|
useHash: false
|
|
}),
|
|
cssnano()
|
|
]
|
|
}),
|
|
html({
|
|
title: 'Hora Bona',
|
|
template ({ files, publicPath, title }) {
|
|
const contents = fs.readFileSync('assets/index.html')
|
|
.toString()
|
|
.replace(/<title><\/title>/, `<title>${title}</title>`)
|
|
const scripts = files.js.map(function (file) {
|
|
return `<script defer src="${publicPath}${file.fileName}"></script>`
|
|
})
|
|
const styles = files.css.map(function (file) {
|
|
return `<link rel="stylesheet" href="${publicPath}${file.fileName}">`
|
|
})
|
|
const headEnd = contents.search('</head>')
|
|
|
|
return contents.slice(0, headEnd) +
|
|
scripts.join('\n') +
|
|
styles.join('\n') +
|
|
contents.slice(headEnd)
|
|
}
|
|
}),
|
|
isProduction() && terser() // See: https://github.com/rollup/plugins/issues/1371
|
|
]
|
|
}
|