Permalink
Browse files

fix: Transform `require` in render function compiled from `<template>` (

  • Loading branch information...
znck committed Jun 5, 2018
1 parent 534c04b commit 89839f2f3311fd6be862409abbb82830fbce7421
Showing with 205 additions and 37 deletions.
  1. +1 −0 .gitignore
  2. +13 −4 package.json
  3. +43 −16 src/index.ts
  4. +16 −0 src/utils.ts
  5. 0 test/assertions.ts
  6. +11 −3 test/baseline.spec.ts
  7. +4 −1 test/setup/index.ts
  8. +4 −1 test/setup/plugins.ts
  9. +113 −12 yarn.lock
@@ -7,6 +7,7 @@ output/
logs/
*.log
npm-debug.log*
docs/changelog.md

# Runtime data
pids
@@ -19,15 +19,20 @@
},
"standard-version": {
"scripts": {
"postchangelog": "yarn test && yarn docs && git add docs/"
"postchangelog": "yarn test && yarn build:docs && git add docs/"
}
},
"scripts": {
"prepublishOnly": "yarn build",
"prebuild": "yarn lint",
"build": "tsc",
"prebuild:docs": "cp CHANGELOG.md docs/changelog.md",
"build:docs": "vuepress build docs/",
"postbuild:docs": "rm docs/changelog.md",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 1",
"docs": "typedoc typings src/index.ts && touch docs/.nojekyll",
"predocs": "cp CHANGELOG.md docs/changelog.md",
"docs": "vuepress dev docs/",
"postdocs": "rm docs/CHANGELOG.md",
"lint": "prettier --no-semi --single-quote --write **/*.js **/*.vue !test/target/** !dist/**",
"release": "standard-version -a",
"pretest": "yarn build",
@@ -43,7 +48,6 @@
"@vue/component-compiler-utils": "^1.2.1",
"debug": "^2.6.0",
"hash-sum": "^1.0.2",
"postcss": "^6.0.22",
"querystring": "^0.2.0",
"rollup-pluginutils": "^2.0.1"
},
@@ -52,6 +56,7 @@
"@babel/plugin-proposal-object-rest-spread": "^7.0.0-beta.46",
"@babel/plugin-transform-runtime": "^7.0.0-beta.46",
"@babel/preset-env": "^7.0.0-beta.46",
"@types/debug": "^0.0.30",
"@types/jest": "^22.2.3",
"@types/node": "^10.0.4",
"@types/puppeteer": "^1.3.1",
@@ -62,20 +67,24 @@
"conventional-changelog": "^1.1.24",
"jest": "^22.4.2",
"node-sass": "^4.9.0",
"postcss": "^6.0.22",
"postcss-assets": "^5.0.0",
"prettier": "^1.12.1",
"pug": "^2.0.3",
"puppeteer": "^1.4.0",
"rollup": "^0.58.2",
"rollup-plugin-babel": "^4.0.0-beta.4",
"rollup-plugin-commonjs": "^9.1.3",
"rollup-plugin-css-only": "^0.4.0",
"rollup-plugin-image": "^1.0.2",
"rollup-plugin-md": "^0.0.7",
"rollup-plugin-node-resolve": "^3.3.0",
"rollup-plugin-replace": "^2.0.0",
"rollup-plugin-typescript": "^0.8.1",
"rollup-plugin-url": "^1.4.0",
"ts-jest": "^22.4.5",
"typescript": "^2.8.3",
"vue": "^2.5.16",
"vue-class-component": "^6.2.0",
"vue-template-compiler": "^2.5.16"
},
"peerDependencies": {
@@ -3,7 +3,8 @@ import {
createVuePartRequest,
parseVuePartRequest,
resolveVuePart,
isVuePartRequest
isVuePartRequest,
transformRequireToImport
} from './utils'
import {
createDefaultCompiler,
@@ -13,26 +14,29 @@ import {
TemplateOptions,
StyleCompileResult
} from '@vue/component-compiler'
import {Plugin} from 'rollup'
import { Plugin } from 'rollup'
import * as path from 'path'
import {parse, SFCDescriptor, SFCBlock} from '@vue/component-compiler-utils'
import { parse, SFCDescriptor, SFCBlock } from '@vue/component-compiler-utils'
import debug from 'debug'

const hash = require('hash-sum')
const d = debug('rollup-plugin-vue')
const { version } = require('../package.json')

export interface VuePluginOptions {
/**
* Include files or directories.
* @default `'.vue'`
*/
include?: Array<string|RegExp> | string | RegExp
include?: Array<string | RegExp> | string | RegExp
/**
* Exclude files or directories.
* @default `undefined`
*/
exclude?: Array<string|RegExp> | string | RegExp
exclude?: Array<string | RegExp> | string | RegExp
/**
* Default language for blocks.
*
*
* @default `{}`
* @example
* ```js
@@ -41,7 +45,7 @@ export interface VuePluginOptions {
*/
defaultLang?: {
[key: string]: string
},
}
/**
* Exclude customBlocks for final build.
* @default `['*']`
@@ -99,7 +103,12 @@ export interface VuePluginOptions {
*/
export default function VuePlugin(opts: VuePluginOptions = {}): Plugin {
const isVue = createVueFilter(opts.include, opts.exclude)
const isProduction = process.env.NODE_ENV === 'production'
const isProduction =
process.env.NODE_ENV === 'production' || process.env.BUILD === 'production'

d('Version ' + version)
d(`Build environment: ${isProduction ? 'production' : 'development'}`)
d(`Build target: ${process.env.VUE_ENV || 'browser'}`)

createVuePartRequest.defaultLang = {
...createVuePartRequest.defaultLang,
@@ -121,9 +130,23 @@ export default function VuePlugin(opts: VuePluginOptions = {}): Plugin {
delete opts.include
delete opts.exclude

opts.template = {
transformAssetUrls: {
video: ['src', 'poster'],
source: 'src',
img: 'src',
image: 'xlink:href'
},
...opts.template
} as any
if (opts.template && typeof opts.template.isProduction === 'undefined') {
opts.template.isProduction = isProduction
}
const compiler = createDefaultCompiler(opts)
const descriptors = new Map<string, SFCDescriptor>()

if (opts.css === false) d('Running in CSS extract mode')

return {
name: 'VuePlugin',

@@ -154,7 +177,7 @@ export default function VuePlugin(opts: VuePluginOptions = {}): Plugin {
const element = resolveVuePart(descriptors, request)

return 'code' in element
? (element as any).code as string // .code is set when extract styles is used. { css: false }
? ((element as any).code as string) // .code is set when extract styles is used. { css: false }
: element.content
},

@@ -186,6 +209,10 @@ export default function VuePlugin(opts: VuePluginOptions = {}): Plugin {
descriptor.template
)

input.template.code = transformRequireToImport(
input.template.code
)

if (input.template.errors && input.template.errors.length) {
input.template.errors.map((error: Error) => this.error(error))
}
@@ -197,7 +224,7 @@ export default function VuePlugin(opts: VuePluginOptions = {}): Plugin {

input.script = descriptor.script
? {
code: `
code: `
export * from '${createVuePartRequest(
filename,
descriptor.script.lang || 'js',
@@ -210,13 +237,13 @@ export default function VuePlugin(opts: VuePluginOptions = {}): Plugin {
)}'
export default script
`
}
: {code: ''}
}
: { code: '' }

if (shouldExtractCss) {
input.styles = input.styles
.map((style: StyleCompileResult, index: number) => {
(descriptor.styles[index] as any).code = style.code
;(descriptor.styles[index] as any).code = style.code

input.script.code +=
'\n' +
@@ -228,7 +255,7 @@ export default function VuePlugin(opts: VuePluginOptions = {}): Plugin {
)}'`

if (style.module || descriptor.styles[index].scoped) {
return {...style, code: ''}
return { ...style, code: '' }
}
})
.filter(Boolean)
@@ -243,8 +270,8 @@ export default function VuePlugin(opts: VuePluginOptions = {}): Plugin {
`export * from '${createVuePartRequest(
filename,
block.attrs.lang ||
createVuePartRequest.defaultLang[block.type] ||
block.type,
createVuePartRequest.defaultLang[block.type] ||
block.type,
'customBlocks',
index
)}'`
@@ -123,3 +123,19 @@ export function resolveVuePart(

return block
}

export function transformRequireToImport(code: string): string {
const imports: { [key: string]: string } = {}
let strImports = ''

code = code.replace(/require\(("(?:[^"\\]|\\.)+"|'(?:[^'\\]|\\.)+')\)/g, (_, name): any => {
if (!(name in imports)) {
imports[name] = `__$_require_${name.replace(/[^a-z0-9]/g, '_').replace(/_{2,}/g, '_').replace(/^_|_$/g, '')}__`
strImports += 'import ' + imports[name] + ' from ' + name + '\n'
}

return imports[name]
})

return strImports + code
}
No changes.
@@ -1,11 +1,16 @@
const puppeteer = require('puppeteer')
import * as fs from 'fs'
import * as path from 'path'
import * as assertions from './assertions'

import {build, open} from "./setup"

let browser = null

function toCamelCase(name: string) : string {
return name.replace(/-(.)/g, (_, char) => char.toUpperCase())
}

beforeAll(async () => {
browser = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'],
@@ -18,14 +23,15 @@ describe('baseline', () => {
.filter((filename: string) => filename.endsWith('.vue'))
.map((filename: string) => filename.replace(/\.vue$/i, ''))
.forEach(fixture => {
test(fixture, () => testRunner(fixture, true))
test(fixture + ' (extract css)', () => testRunner(fixture, false))
const name = toCamelCase(fixture)
test(fixture, () => testRunner(fixture, true, assertions[name]))
test(fixture + ' (extract css)', () => testRunner(fixture, false, assertions[name]))
})
})

afterAll(async () => browser && (await browser.close()))

async function testRunner(fixture: string, extractCss: boolean): Promise<void> {
async function testRunner(fixture: string, extractCss: boolean, moreAssertions?: Function): Promise<void> {
const filename = path.join(__dirname, 'fixtures', fixture + '.vue')
const code = await build(filename, extractCss)
const page = await open(
@@ -43,5 +49,7 @@ async function testRunner(fixture: string, extractCss: boolean): Promise<void> {
)
).toEqual('rgb(255, 0, 0)')

moreAssertions && moreAssertions(page)

await page.close()
}
@@ -8,6 +8,7 @@ import {pluginCreateVueApp, plugins} from "./plugins"
import pluginVue from '../..'

const pluginCSS = require('rollup-plugin-css-only')
const assets = require('postcss-assets')

// -- rollup plugin inline file

@@ -18,7 +19,9 @@ export async function build(filename, css = false): Promise<string> {
if (cacheKey in cache) return cache[cacheKey]
let style: string | undefined
const input = filename + '__app.js'
const options = {defaultLang: {markdown: 'pluginMarkdown'}, css: css}
const options = {defaultLang: {markdown: 'pluginMarkdown'}, css: css, style: {
postcssPlugins: [assets({ basePath: '/' })]
}}
const bundle = await rollup({
input,
plugins: [
@@ -1,18 +1,21 @@
const pluginBabel = require('rollup-plugin-babel')
const pluginNodeResolve = require('rollup-plugin-node-resolve')
const pluginCommonJS = require('rollup-plugin-commonjs')
const pluginImage = require('rollup-plugin-image')
const pluginImage = require('rollup-plugin-url')
const pluginMarkdown = require('rollup-plugin-md')
const pluginTypescript = require('rollup-plugin-typescript')
const pluginReplace = require('rollup-plugin-replace')
const path = require('path')

export const plugins = [
pluginImage(),
pluginMarkdown(),
pluginNodeResolve(),
pluginCommonJS(),
pluginReplace({ 'process.env.NODE_ENV': '"production"' }),
pluginTypescript({
tsconfig: false,
experimentalDecorators: true,
module: 'es2015'
}),
pluginBabel({
Oops, something went wrong.

0 comments on commit 89839f2

Please sign in to comment.