提交 e98abce0 编写于 作者: fxy060608's avatar fxy060608

Merge branch 'dev' of https://github.com/dcloudio/uni-app into alpha

......@@ -386,13 +386,13 @@ class Util {
// },
data: optionsData,
success: () => {
if (process.env.NODE_ENV === 'development') {
console.log('stat request success');
}
// if (process.env.NODE_ENV === 'development') {
// console.log('stat request success');
// }
},
fail: (e) => {
if (process.env.NODE_ENV === 'development') {
console.log('stat request fail', e);
// console.log('stat request fail', e);
}
if (++this._retry < 3) {
setTimeout(() => {
......@@ -495,9 +495,9 @@ class Stat extends Util {
report(options, self) {
this.self = self;
if (process.env.NODE_ENV === 'development') {
console.log('report init');
}
// if (process.env.NODE_ENV === 'development') {
// console.log('report init');
// }
setPageResidenceTime()
this.__licationShow = true;
this._sendReportRequest(options, true);
......
......@@ -584,7 +584,12 @@ describe('mp:compiler-extra', () => {
`<view data-test="{{'hello'+aaa}}"></view>`
)
})
it('generate event ', () => {
it('generate event ', () => {
assertCodegen(
`<view @/>`,
`<view></view>`
)
assertCodegen(
`<text v-for="item in items['metas']" :key="item['id']" class="title" @tap="handle(item['id'],item['title'])">{{item.title}}</text>`,
`<block wx:for="{{items['metas']}}" wx:for-item="item" wx:for-index="__i0__" wx:key="id"><text data-event-opts="{{[['tap',[['handle',['$0','$1'],[[['items.metas','id',item['id'],'id']],[['items.metas','id',item['id'],'title']]]]]]]}}" class="title" bindtap="__e">{{item.title}}</text></block>`
......
......@@ -2,7 +2,7 @@ const compiler = require('../lib')
const res = compiler.compile(
`
<view v-for="item in dataList" :key="item.id" @click="click1(item, 1);click2(item, 2);"/>
<view @/>
`, {
resourcePath: '/User/fxy/Documents/test.wxml',
mp: {
......
......@@ -55,10 +55,18 @@ module.exports = {
}
// console.log(`function render(){${res.render}}`)
const ast = parser.parse(`function render(){${res.render}}`)
res.render = generateScript(traverseScript(ast, state), state)
let template = generateTemplate(traverseTemplate(ast, state), state)
let template = ''
try {
res.render = generateScript(traverseScript(ast, state), state)
template = generateTemplate(traverseTemplate(ast, state), state)
} catch (e) {
console.error(e)
throw new Error('Compile failed at ' + options.resourcePath.replace(
path.extname(options.resourcePath),
'.vue'
))
}
res.specialMethods = state.options.specialMethods || new Set()
delete state.options.specialMethods
......
......@@ -167,7 +167,7 @@ function getMethodName (methodName) {
return methodName === '__HOLDER__' ? '' : methodName
}
function parseEventByCallExpression (callExpr, methods) {
function parseEventByCallExpression (callExpr, methods) {
let methodName = callExpr.callee.name
if (methodName === '$set') {
methodName = INTERNAL_SET_SYNC
......@@ -197,12 +197,12 @@ function parseEventByCallExpression (callExpr, methods) {
arrayExpression.push(t.arrayExpression(argsExpression))
}
}
methods.push(t.arrayExpression(arrayExpression))
methods.push(t.arrayExpression(arrayExpression))
}
function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false, tagName, ret) {
const key = keyPath.node
let type = key.value || key.name
let type = key.value || key.name || ''
const isCustom = isComponent && !isNativeOn
......@@ -211,124 +211,126 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false,
let isPassive = false
let isOnce = false
isPassive = type.charAt(0) === VUE_EVENT_MODIFIERS.passive
type = isPassive ? type.slice(1) : type
let methods = []
isOnce = type.charAt(0) === VUE_EVENT_MODIFIERS.once // Prefixed last, checked first
type = isOnce ? type.slice(1) : type
if (type) {
isPassive = type.charAt(0) === VUE_EVENT_MODIFIERS.passive
type = isPassive ? type.slice(1) : type
isCapture = type.charAt(0) === VUE_EVENT_MODIFIERS.capture
type = isCapture ? type.slice(1) : type
isOnce = type.charAt(0) === VUE_EVENT_MODIFIERS.once // Prefixed last, checked first
type = isOnce ? type.slice(1) : type
const specialEvents = state.options.platform.specialEvents
const isSpecialEvent = specialEvents[tagName] && Object.keys(specialEvents[tagName]).includes(type)
isCapture = type.charAt(0) === VUE_EVENT_MODIFIERS.capture
type = isCapture ? type.slice(1) : type
let methods = []
const specialEvents = state.options.platform.specialEvents
const isSpecialEvent = specialEvents[tagName] && Object.keys(specialEvents[tagName]).includes(type)
if (!valuePath.isArrayExpression()) {
valuePath = [valuePath]
} else {
valuePath = valuePath.get('elements')
}
if (!valuePath.isArrayExpression()) {
valuePath = [valuePath]
} else {
valuePath = valuePath.get('elements')
}
valuePath.forEach(funcPath => {
if ( // wxs event
funcPath.isMemberExpression() &&
t.isIdentifier(funcPath.node.object) &&
state.options.filterModules.includes(funcPath.node.object.name)
) {
const {
getEventType,
formatEventType
} = state.options.platform
const wxsEventType = formatEventType(getEventType(type))
if (key.value) {
key.value = wxsEventType
} else {
key.name = wxsEventType
}
} else if (funcPath.isIdentifier()) { // on:{click:handle}
if (!isSpecialEvent) {
const arrayExpression = [t.stringLiteral(getMethodName(funcPath.node.name))]
if (!isCustom) { // native events
arrayExpression.push(defaultArgs)
valuePath.forEach(funcPath => {
if ( // wxs event
funcPath.isMemberExpression() &&
t.isIdentifier(funcPath.node.object) &&
state.options.filterModules.includes(funcPath.node.object.name)
) {
const {
getEventType,
formatEventType
} = state.options.platform
const wxsEventType = formatEventType(getEventType(type))
if (key.value) {
key.value = wxsEventType
} else {
key.name = wxsEventType
}
methods.push(t.arrayExpression(arrayExpression))
} else {
if (!state.options.specialMethods) {
state.options.specialMethods = new Set()
} else if (funcPath.isIdentifier()) { // on:{click:handle}
if (!isSpecialEvent) {
const arrayExpression = [t.stringLiteral(getMethodName(funcPath.node.name))]
if (!isCustom) { // native events
arrayExpression.push(defaultArgs)
}
methods.push(t.arrayExpression(arrayExpression))
} else {
if (!state.options.specialMethods) {
state.options.specialMethods = new Set()
}
state.options.specialMethods.add(funcPath.node.name)
}
state.options.specialMethods.add(funcPath.node.name)
}
} else if (isSpecialEvent) {
state.errors.add(
`${tagName} 组件 ${type} 事件仅支持 @${type}="methodName" 方式绑定`
)
} else if (funcPath.isArrowFunctionExpression()) { // e=>count++
methods.push(addEventExpressionStatement(funcPath, state, isCustom))
} else {
let anonymous = true
} else if (isSpecialEvent) {
state.errors.add(
`${tagName} 组件 ${type} 事件仅支持 @${type}="methodName" 方式绑定`
)
} else if (funcPath.isArrowFunctionExpression()) { // e=>count++
methods.push(addEventExpressionStatement(funcPath, state, isCustom))
} else {
let anonymous = true
// "click":function($event) {click1(item);click2(item);}
const body = funcPath.node.body.body
if (body.length) {
const exprStatements = body.filter(node => {
return t.isExpressionStatement(node) && t.isCallExpression(node.expression)
})
if (exprStatements.length === body.length) {
anonymous = false
exprStatements.forEach(exprStatement => {
parseEventByCallExpression(exprStatement.expression, methods)
// "click":function($event) {click1(item);click2(item);}
const body = funcPath.node.body && funcPath.node.body.body
if (body && body.length) {
const exprStatements = body.filter(node => {
return t.isExpressionStatement(node) && t.isCallExpression(node.expression)
})
}
}
anonymous && funcPath.traverse({
noScope: true,
MemberExpression (path) {
if (path.node.object.name === '$event' && path.node.property.name ===
'stopPropagation') {
isCatch = true
path.stop()
}
},
AssignmentExpression (path) { // "update:title": function($event) {title = $event}
const left = path.node.left
const right = path.node.right
// v-bind:title.sync="title"
if (t.isIdentifier(left) &&
t.isIdentifier(right) &&
right.name === '$event' &&
type.indexOf('update:') === 0) {
methods.push(t.arrayExpression( // ['$set',['title','$event']]
[
t.stringLiteral(INTERNAL_SET_SYNC),
t.arrayExpression([
t.identifier(left.name),
t.stringLiteral(left.name),
t.stringLiteral('$event')
])
]
))
if (exprStatements.length === body.length) {
anonymous = false
path.stop()
exprStatements.forEach(exprStatement => {
parseEventByCallExpression(exprStatement.expression, methods)
})
}
},
ReturnStatement (path) {
const argument = path.node.argument
if (t.isCallExpression(argument)) {
if (t.isIdentifier(argument.callee)) {
}
anonymous && funcPath.traverse({
noScope: true,
MemberExpression (path) {
if (path.node.object.name === '$event' && path.node.property.name ===
'stopPropagation') {
isCatch = true
path.stop()
}
},
AssignmentExpression (path) { // "update:title": function($event) {title = $event}
const left = path.node.left
const right = path.node.right
// v-bind:title.sync="title"
if (t.isIdentifier(left) &&
t.isIdentifier(right) &&
right.name === '$event' &&
type.indexOf('update:') === 0) {
methods.push(t.arrayExpression( // ['$set',['title','$event']]
[
t.stringLiteral(INTERNAL_SET_SYNC),
t.arrayExpression([
t.identifier(left.name),
t.stringLiteral(left.name),
t.stringLiteral('$event')
])
]
))
anonymous = false
parseEventByCallExpression(argument, methods)
path.stop()
}
},
ReturnStatement (path) {
const argument = path.node.argument
if (t.isCallExpression(argument)) {
if (t.isIdentifier(argument.callee)) {
anonymous = false
parseEventByCallExpression(argument, methods)
}
}
}
})
if (anonymous) {
methods.push(addEventExpressionStatement(funcPath, state, isComponent, isNativeOn))
}
})
if (anonymous) {
methods.push(addEventExpressionStatement(funcPath, state, isComponent, isNativeOn))
}
}
})
})
}
return {
type,
......@@ -345,6 +347,10 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false,
function _processEvent (path, state, isComponent, isNativeOn = false, tagName, ret) {
const opts = []
// remove invalid event
path.node.value.properties = path.node.value.properties.filter(property => {
return property.key.value || property.key.name
})
const len = path.node.value.properties.length
for (let i = 0; i < len; i++) {
const propertyPath = path.get(`value.properties.${i}`)
......@@ -439,4 +445,4 @@ module.exports = function processEvent (paths, path, state, isComponent, tagName
)
return ret
}
}
......@@ -139,7 +139,10 @@ if (platformOptions.usingComponents === true) {
}
}
if (process.env.UNI_USING_COMPONENTS || process.env.UNI_PLATFORM === 'h5') { // 自定义组件模式或 h5 平台
if (
process.env.NODE_ENV === 'production' &&
(process.env.UNI_USING_COMPONENTS || process.env.UNI_PLATFORM === 'h5')
) { // 自定义组件模式或 h5 平台
const uniStatistics = Object.assign(
manifestJsonObj.uniStatistics || {},
platformOptions.uniStatistics || {}
......@@ -201,9 +204,10 @@ if (process.env.UNI_PLATFORM !== 'h5') {
const moduleAlias = require('module-alias')
// 将 template-compiler 指向修订后的版本
// 将 template-compiler 指向修订后的版本
moduleAlias.addAlias('vue-template-compiler', '@dcloudio/vue-cli-plugin-uni/packages/vue-template-compiler')
moduleAlias.addAlias('@megalo/template-compiler', '@dcloudio/vue-cli-plugin-uni/packages/@megalo/template-compiler')
moduleAlias.addAlias('mpvue-template-compiler', '@dcloudio/vue-cli-plugin-uni/packages/mpvue-template-compiler')
moduleAlias.addAlias('mpvue-template-compiler', '@dcloudio/vue-cli-plugin-uni/packages/mpvue-template-compiler')
if (runByHBuilderX) {
const oldError = console.error
......
......@@ -2,6 +2,10 @@ const {
tags
} = require('@dcloudio/uni-cli-shared')
const {
isUnaryTag
} = require('../util')
const simplePathRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/
function processEvent (expr, filterModules) {
......@@ -41,6 +45,7 @@ function addTag (tag) {
}
module.exports = {
isUnaryTag,
preserveWhitespace: false,
modules: [require('../format-text'), {
preTransformNode (el, {
......
......@@ -86,7 +86,7 @@ module.exports = {
loader: resolve('packages/h5-vue-template-loader')
}]
}, {
resourceQuery: /blockType=wxs/,
resourceQuery: [/lang=wxs/, /blockType=wxs/],
use: [{
loader: resolve('packages/webpack-uni-filter-loader')
}]
......
......@@ -13,6 +13,10 @@ const {
getPlatformCssnano
} = require('@dcloudio/uni-cli-shared')
const {
isUnaryTag
} = require('./util')
function createUniMPPlugin () {
if (process.env.UNI_USING_COMPONENTS) {
const WebpackUniMPPlugin = require('@dcloudio/webpack-uni-mp-loader/lib/plugin/index-new')
......@@ -125,7 +129,14 @@ module.exports = {
loader: '@dcloudio/webpack-uni-mp-loader/lib/template'
}]
}, {
resourceQuery: [/blockType=wxs/, /blockType=filter/, /blockType=import-sjs/],
resourceQuery: [
/lang=wxs/,
/lang=filter/,
/lang=import-sjs/,
/blockType=wxs/,
/blockType=filter/,
/blockType=import-sjs/
],
use: [{
loader: require.resolve(
'@dcloudio/vue-cli-plugin-uni/packages/webpack-uni-filter-loader')
......@@ -154,6 +165,7 @@ module.exports = {
.tap(options => Object.assign(options, {
compiler: getPlatformCompiler(),
compilerOptions: process.env.UNI_USING_COMPONENTS ? {
isUnaryTag,
preserveWhitespace: false
} : require('./mp-compiler-options'),
cacheDirectory: false,
......@@ -172,15 +184,24 @@ module.exports = {
.uses
.delete('cache-loader')
const styleExt = getPlatformExts().style
webpackConfig.plugin('extract-css')
.init((Plugin, args) => new Plugin({
filename: '[name]' + getPlatformExts().style
filename: '[name]' + styleExt
}))
if (process.env.NODE_ENV === 'production') {
if (
process.env.NODE_ENV === 'production' &&
process.env.UNI_PLATFORM !== 'app-plus'
) {
const OptimizeCssnanoPlugin = require('../packages/@intervolga/optimize-cssnano-plugin/index.js')
webpackConfig.plugin('optimize-css')
.init((Plugin, args) => new Plugin({
.init((Plugin, args) => new OptimizeCssnanoPlugin({
sourceMap: false,
filter (assetName) {
return path.extname(assetName) === styleExt
},
cssnanoOptions: {
preset: [
'default',
......
function makeMap (str, expectsLowerCase) {
const map = Object.create(null)
const list = str.split(',')
for (let i = 0; i < list.length; i++) {
map[list[i]] = true
}
return expectsLowerCase
? val => map[val.toLowerCase()]
: val => map[val]
}
module.exports = {
isUnaryTag: makeMap(
'image,area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' +
'link,meta,param,source,track,wbr'
)
}
MIT License
Copyright (c) 2017 INTERVOLGA.RU
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# optimize-cssnano-plugin [![Build Status](https://travis-ci.org/intervolga/optimize-cssnano-plugin.svg?branch=master)](https://travis-ci.org/intervolga/optimize-cssnano-plugin)
It will search for CSS assets during the Webpack build and minimize it with [cssnano](http://github.com/ben-eb/cssnano).
Solves [extract-text-webpack-plugin](http://github.com/webpack/extract-text-webpack-plugin) CSS duplication problem.
Just like [optimize-css-assets-webpack-plugin](http://github.com/NMFR/optimize-css-assets-webpack-plugin) but more accurate with source maps.
## Installation:
Using npm:
```shell
$ npm install --save-dev @intervolga/optimize-cssnano-plugin
```
## Configuration:
``` javascript
const OptimizeCssnanoPlugin = require('@intervolga/optimize-cssnano-plugin');
module.exports = {
module: {
loaders: [
{ test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }
]
},
plugins: [
new ExtractTextPlugin("styles.css"),
new OptimizeCssnanoPlugin({
sourceMap: nextSourceMap,
cssnanoOptions: {
preset: ['default', {
discardComments: {
removeAll: true,
},
}],
},
}),
]
}
```
\ No newline at end of file
const cssnano = require('cssnano');
const postcss = require('postcss');
/**
* Optimize cssnano plugin
*
* @param {Object} options
*/
function OptimizeCssnanoPlugin(options) {
this.options = Object.assign({
sourceMap: false,
filter(assetName){// fixed by xxxxxx custom filter
return /\.css$/i.test(assetName);
},
cssnanoOptions: {
preset: 'default',
},
}, options);
if (this.options.sourceMap) {
this.options.sourceMap = Object.assign(
{inline: false},
this.options.sourceMap || {});
}
}
OptimizeCssnanoPlugin.prototype.apply = function(compiler) {
const self = this;
compiler.hooks.emit.tapAsync('OptimizeCssnanoPlugin',
function(compilation, callback) {
// Search for CSS assets
const assetsNames = Object.keys(compilation.assets)
.filter(self.options.filter);// fixed by xxxxxx custom filter
let hasErrors = false;
const promises = [];
// Generate promises for each minification
assetsNames.forEach((assetName) => {
// Original CSS
const asset = compilation.assets[assetName];
const originalCss = asset.source();
// Options for particalar cssnano call
const postCssOptions = {
from: assetName,
to: assetName,
map: false,
};
const cssnanoOptions = self.options.cssnanoOptions;
// Extract or remove previous map
const mapName = assetName + '.map';
if (self.options.sourceMap) {
// Use previous map if exist...
if (compilation.assets[mapName]) {
const mapObject = JSON.parse(compilation.assets[mapName].source());
// ... and not empty
if (mapObject.sources.length > 0 || mapObject.mappings.length > 0) {
postCssOptions.map = Object.assign({
prev: compilation.assets[mapName].source(),
}, self.options.sourceMap);
} else {
postCssOptions.map = Object.assign({}, self.options.sourceMap);
}
}
} else {
delete compilation.assets[mapName];
}
// Run minification
const promise = postcss([cssnano(cssnanoOptions)])
.process(originalCss, postCssOptions)
.then((result) => {
if (hasErrors) {
return;
}
// Extract CSS back to assets
const processedCss = result.css;
compilation.assets[assetName] = {
source: function() {
return processedCss;
},
size: function() {
return processedCss.length;
},
};
// Extract map back to assets
if (result.map) {
const processedMap = result.map.toString();
compilation.assets[mapName] = {
source: function() {
return processedMap;
},
size: function() {
return processedMap.length;
},
};
}
}
).catch(function(err) {
hasErrors = true;
throw new Error('CSS minification error: ' + err.message +
'. File: ' + assetName);
}
);
promises.push(promise);
});
Promise.all(promises)
.then(function() {
callback();
})
.catch(callback);
});
};
module.exports = OptimizeCssnanoPlugin;
{
"name": "@intervolga/optimize-cssnano-plugin",
"version": "1.0.6",
"description": "WebPack 2+ plugin for CSS minification after ExtractTextPluging",
"main": "index.js",
"scripts": {
"mocha": "mocha --ui tdd test/",
"lint": "eslint index.js lib test/index.js test/helpers",
"test": "npm run lint && npm run mocha"
},
"repository": {
"type": "git",
"url": "git+https://github.com/intervolga/optimize-cssnano-plugin"
},
"keywords": [
"html",
"index",
"webpack",
"loader"
],
"author": "Shkarupa Alex",
"license": "MIT",
"bugs": {
"url": "https://github.com/intervolga/optimize-cssnano-plugin/issues"
},
"homepage": "https://github.com/intervolga/optimize-cssnano-plugin#readme",
"peerDependencies": {
"webpack": "^4.0.0"
},
"dependencies": {
"cssnano": "^4.0.0",
"cssnano-preset-default": "^4.0.0",
"postcss": "^7.0.0"
},
"devDependencies": {
"autoprefixer": "^8.6.5",
"css-loader": "^0.28.11",
"eslint": "^4.19.1",
"eslint-config-google": "^0.8.0",
"eslint-plugin-promise": "^3.8.0",
"eslint-plugin-standard": "^3.1.0",
"expect.js": "^0.3.1",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"fs-extra": "^5.0.0",
"mocha": "^5.2.0",
"node-sass": "^4.9.2",
"postcss-loader": "^2.1.6",
"sass-loader": "^6.0.7",
"style-loader": "^0.20.3",
"webpack": "^4.16.1"
},
"files": [
"lib",
"index.js",
"README",
"LICENSE"
]
}
# vue-template-compiler
> This package is auto-generated. For pull requests please see [src/platforms/web/entry-compiler.js](https://github.com/vuejs/vue/tree/dev/src/platforms/web/entry-compiler.js).
This package can be used to pre-compile Vue 2.0 templates into render functions to avoid runtime-compilation overhead and CSP restrictions. In most cases you should be using it with [`vue-loader`](https://github.com/vuejs/vue-loader), you will only need it separately if you are writing build tools with very specific needs.
## Installation
``` bash
npm install vue-template-compiler
```
``` js
const compiler = require('vue-template-compiler')
```
## API
### compiler.compile(template, [options])
Compiles a template string and returns compiled JavaScript code. The returned result is an object of the following format:
``` js
{
ast: ?ASTElement, // parsed template elements to AST
render: string, // main render function code
staticRenderFns: Array<string>, // render code for static sub trees, if any
errors: Array<string> // template syntax errors, if any
}
```
Note the returned function code uses `with` and thus cannot be used in strict mode code.
#### Options
- `outputSourceRange` *new in 2.6*
- Type: `boolean`
- Default: `false`
Set this to true will cause the `errors` returned in the compiled result become objects in the form of `{ msg, start, end }`. The `start` and `end` properties are numbers that mark the code range of the error source in the template. This can be passed on to the `compiler.generateCodeFrame` API to generate a code frame for the error.
- `whitespace`
- Type: `string`
- Valid values: `'preserve' | 'condense'`
- Default: `'preserve'`
The default value `'preserve'` handles whitespaces as follows:
- A whitespace-only text node between element tags is condensed into a single space.
- All other whitespaces are preserved as-is.
If set to `'condense'`:
- A whitespace-only text node between element tags is removed if it contains new lines. Otherwise, it is condensed into a single space.
- Consecutive whitespaces inside a non-whitespace-only text node are condensed into a single space.
Using condense mode will result in smaller compiled code size and slightly improved performance. However, it will produce minor visual layout differences compared to plain HTML in certain cases.
**This option does not affect the `<pre>` tag.**
Example:
``` html
<!-- source -->
<div>
<span>
foo
</span> <span>bar</span>
</div>
<!-- whitespace: 'preserve' -->
<div> <span>
foo
</span> <span>bar</span> </div>
<!-- whitespace: 'condense' -->
<div><span> foo </span> <span>bar</span></div>
```
- `modules`
It's possible to hook into the compilation process to support custom template features. **However, beware that by injecting custom compile-time modules, your templates will not work with other build tools built on standard built-in modules, e.g `vue-loader` and `vueify`.**
An array of compiler modules. For details on compiler modules, refer to the `ModuleOptions` type in [flow declarations](https://github.com/vuejs/vue/blob/dev/flow/compiler.js#L38-L45) and the [built-in modules](https://github.com/vuejs/vue/tree/dev/src/platforms/web/compiler/modules).
- `directives`
An object where the key is the directive name and the value is a function that transforms an template AST node. For example:
``` js
compiler.compile('<div v-test></div>', {
directives: {
test (node, directiveMeta) {
// transform node based on directiveMeta
}
}
})
```
By default, a compile-time directive will extract the directive and the directive will not be present at runtime. If you want the directive to also be handled by a runtime definition, return `true` in the transform function.
Refer to the implementation of some [built-in compile-time directives](https://github.com/vuejs/vue/tree/dev/src/platforms/web/compiler/directives).
- `preserveWhitespace` **Deprecated since 2.6**
- Type: `boolean`
- Default: `true`
By default, the compiled render function preserves all whitespace characters between HTML tags. If set to `false`, whitespace between tags will be ignored. This can result in slightly better performance but may affect layout for inline elements.
---
### compiler.compileToFunctions(template)
Similar to `compiler.compile`, but directly returns instantiated functions:
``` js
{
render: Function,
staticRenderFns: Array<Function>
}
```
This is only useful at runtime with pre-configured builds, so it doesn't accept any compile-time options. In addition, this method uses `new Function()` so it is not CSP-compliant.
---
### compiler.ssrCompile(template, [options])
> 2.4.0+
Same as `compiler.compile` but generates SSR-specific render function code by optimizing parts of the template into string concatenation in order to improve SSR performance.
This is used by default in `vue-loader@>=12` and can be disabled using the [`optimizeSSR`](https://vue-loader.vuejs.org/en/options.html#optimizessr) option.
---
### compiler.ssrCompileToFunctions(template)
> 2.4.0+
Same as `compiler.compileToFunction` but generates SSR-specific render function code by optimizing parts of the template into string concatenation in order to improve SSR performance.
---
### compiler.parseComponent(file, [options])
Parse a SFC (single-file component, or `*.vue` file) into a descriptor (refer to the `SFCDescriptor` type in [flow declarations](https://github.com/vuejs/vue/blob/dev/flow/compiler.js)). This is used in SFC build tools like `vue-loader` and `vueify`.
---
### compiler.generateCodeFrame(template, start, end)
Generate a code frame that highlights the part in `template` defined by `start` and `end`. Useful for error reporting in higher-level tooling.
#### Options
#### `pad`
`pad` is useful when you are piping the extracted content into other pre-processors, as you will get correct line numbers or character indices if there are any syntax errors.
- with `{ pad: "line" }`, the extracted content for each block will be prefixed with one newline for each line in the leading content from the original file to ensure that the line numbers align with the original file.
- with `{ pad: "space" }`, the extracted content for each block will be prefixed with one space for each character in the leading content from the original file to ensure that the character count remains the same as the original file.
try {
var vueVersion = require('vue').version
} catch (e) {}
var packageName = require('./package.json').name
var packageVersion = require('./package.json').version
if (vueVersion && vueVersion !== packageVersion) {
var vuePath = require.resolve('vue')
var packagePath = require.resolve('./package.json')
throw new Error(
'\n\nVue packages version mismatch:\n\n' +
'- vue@' + vueVersion + ' (' + vuePath + ')\n' +
'- ' + packageName + '@' + packageVersion + ' (' + packagePath + ')\n\n' +
'This may cause things to work incorrectly. Make sure to use the same version for both.\n' +
'If you are using vue-loader@>=10.0, simply update vue-template-compiler.\n' +
'If you are using vue-loader@<10.0 or vueify, re-installing vue-loader/vueify should bump ' + packageName + ' to the latest.\n'
)
}
module.exports = require('./build')
{
"name": "vue-template-compiler",
"version": "2.6.10",
"description": "template compiler for Vue 2.0",
"main": "index.js",
"unpkg": "browser.js",
"jsdelivr": "browser.js",
"browser": "browser.js",
"types": "types/index.d.ts",
"repository": {
"type": "git",
"url": "git+https://github.com/vuejs/vue.git"
},
"keywords": [
"vue",
"compiler"
],
"author": "Evan You",
"license": "MIT",
"bugs": {
"url": "https://github.com/vuejs/vue/issues"
},
"homepage": "https://github.com/vuejs/vue/tree/dev/packages/vue-template-compiler#readme",
"dependencies": {
"he": "^1.1.0",
"de-indent": "^1.0.2"
},
"devDependencies": {
"vue": "file:../.."
}
}
import Vue, { VNode } from "vue"
/*
* Template compilation options / results
*/
interface CompilerOptions {
modules?: ModuleOptions[];
directives?: Record<string, DirectiveFunction>;
preserveWhitespace?: boolean;
whitespace?: 'preserve' | 'condense';
outputSourceRange?: any
}
interface CompilerOptionsWithSourceRange extends CompilerOptions {
outputSourceRange: true
}
interface ErrorWithRange {
msg: string;
start: number;
end: number;
}
interface CompiledResult<ErrorType> {
ast: ASTElement | undefined;
render: string;
staticRenderFns: string[];
errors: ErrorType[];
tips: ErrorType[];
}
interface CompiledResultFunctions {
render: () => VNode;
staticRenderFns: (() => VNode)[];
}
interface ModuleOptions {
preTransformNode: (el: ASTElement) => ASTElement | undefined;
transformNode: (el: ASTElement) => ASTElement | undefined;
postTransformNode: (el: ASTElement) => void;
genData: (el: ASTElement) => string;
transformCode?: (el: ASTElement, code: string) => string;
staticKeys?: string[];
}
type DirectiveFunction = (node: ASTElement, directiveMeta: ASTDirective) => void;
/*
* AST Types
*/
/**
* - 0: FALSE - whole sub tree un-optimizable
* - 1: FULL - whole sub tree optimizable
* - 2: SELF - self optimizable but has some un-optimizable children
* - 3: CHILDREN - self un-optimizable but have fully optimizable children
* - 4: PARTIAL - self un-optimizable with some un-optimizable children
*/
export type SSROptimizability = 0 | 1 | 2 | 3 | 4
export interface ASTModifiers {
[key: string]: boolean;
}
export interface ASTIfCondition {
exp: string | undefined;
block: ASTElement;
}
export interface ASTElementHandler {
value: string;
params?: any[];
modifiers: ASTModifiers | undefined;
}
export interface ASTElementHandlers {
[key: string]: ASTElementHandler | ASTElementHandler[];
}
export interface ASTDirective {
name: string;
rawName: string;
value: string;
arg: string | undefined;
modifiers: ASTModifiers | undefined;
}
export type ASTNode = ASTElement | ASTText | ASTExpression;
export interface ASTElement {
type: 1;
tag: string;
attrsList: { name: string; value: any }[];
attrsMap: Record<string, any>;
parent: ASTElement | undefined;
children: ASTNode[];
processed?: true;
static?: boolean;
staticRoot?: boolean;
staticInFor?: boolean;
staticProcessed?: boolean;
hasBindings?: boolean;
text?: string;
attrs?: { name: string; value: any }[];
props?: { name: string; value: string }[];
plain?: boolean;
pre?: true;
ns?: string;
component?: string;
inlineTemplate?: true;
transitionMode?: string | null;
slotName?: string;
slotTarget?: string;
slotScope?: string;
scopedSlots?: Record<string, ASTElement>;
ref?: string;
refInFor?: boolean;
if?: string;
ifProcessed?: boolean;
elseif?: string;
else?: true;
ifConditions?: ASTIfCondition[];
for?: string;
forProcessed?: boolean;
key?: string;
alias?: string;
iterator1?: string;
iterator2?: string;
staticClass?: string;
classBinding?: string;
staticStyle?: string;
styleBinding?: string;
events?: ASTElementHandlers;
nativeEvents?: ASTElementHandlers;
transition?: string | true;
transitionOnAppear?: boolean;
model?: {
value: string;
callback: string;
expression: string;
};
directives?: ASTDirective[];
forbidden?: true;
once?: true;
onceProcessed?: boolean;
wrapData?: (code: string) => string;
wrapListeners?: (code: string) => string;
// 2.4 ssr optimization
ssrOptimizability?: SSROptimizability;
// weex specific
appendAsTree?: boolean;
}
export interface ASTExpression {
type: 2;
expression: string;
text: string;
tokens: (string | Record<string, any>)[];
static?: boolean;
// 2.4 ssr optimization
ssrOptimizability?: SSROptimizability;
}
export interface ASTText {
type: 3;
text: string;
static?: boolean;
isComment?: boolean;
// 2.4 ssr optimization
ssrOptimizability?: SSROptimizability;
}
/*
* SFC parser related types
*/
interface SFCParserOptions {
pad?: true | 'line' | 'space';
deindent?: boolean
}
export interface SFCBlock {
type: string;
content: string;
attrs: Record<string, string>;
start?: number;
end?: number;
lang?: string;
src?: string;
scoped?: boolean;
module?: string | boolean;
}
export interface SFCDescriptor {
template: SFCBlock | undefined;
script: SFCBlock | undefined;
styles: SFCBlock[];
customBlocks: SFCBlock[];
}
/*
* Exposed functions
*/
export function compile(
template: string,
options: CompilerOptionsWithSourceRange
): CompiledResult<ErrorWithRange>
export function compile(
template: string,
options?: CompilerOptions
): CompiledResult<string>;
export function compileToFunctions(template: string): CompiledResultFunctions;
export function ssrCompile(
template: string,
options: CompilerOptionsWithSourceRange
): CompiledResult<ErrorWithRange>;
export function ssrCompile(
template: string,
options?: CompilerOptions
): CompiledResult<string>;
export function ssrCompileToFunctions(template: string): CompiledResultFunctions;
export function parseComponent(
file: string,
options?: SFCParserOptions
): SFCDescriptor;
export function generateCodeFrame(
template: string,
start: number,
end: number
): string;
import Vue, { VNode } from "vue";
import {
compile,
compileToFunctions,
ssrCompile,
ssrCompileToFunctions,
parseComponent,
generateCodeFrame
} from "./";
// check compile options
const compiled = compile("<div>hi</div>", {
outputSourceRange: true,
preserveWhitespace: false,
whitespace: 'condense',
modules: [
{
preTransformNode: el => el,
transformNode: el => el,
postTransformNode: el => {
el.tag = "p";
},
genData: el => el.tag,
transformCode: (el, code) => code,
staticKeys: ["test"]
}
],
directives: {
test: (node, directiveMeta) => {
node.tag;
directiveMeta.value;
}
}
});
// can be passed to function constructor
new Function(compiled.render);
compiled.staticRenderFns.map(fn => new Function(fn));
// with outputSourceRange: true
// errors should be objects with range
compiled.errors.forEach(e => {
console.log(e.msg)
})
// without option or without outputSourceRange: true, should be strings
const { errors } = compile(`foo`)
errors.forEach(e => {
console.log(e.length)
})
const { errors: errors2 } = compile(`foo`, {})
errors2.forEach(e => {
console.log(e.length)
})
const { errors: errors3 } = compile(`foo`, {
outputSourceRange: false
})
errors3.forEach(e => {
console.log(e.length)
})
const compiledFns = compileToFunctions("<div>hi</div>");
// can be passed to component render / staticRenderFns options
const vm = new Vue({
data() {
return {
test: "Test"
};
},
render: compiledFns.render,
staticRenderFns: compiledFns.staticRenderFns
});
// can be called with component instance
const vnode: VNode = compiledFns.render.call(vm);
// check SFC parser
const desc = parseComponent("<template></template>", {
pad: "space",
deindent: false
});
const templateContent: string = desc.template!.content;
const scriptContent: string = desc.script!.content;
const styleContent: string = desc.styles.map(s => s.content).join("\n");
const codeframe: string = generateCodeFrame(`foobar`, 0, 4)
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"strict": true,
"noEmit": true
},
"compileOnSave": false,
"include": [
"**/*.ts"
]
}
......@@ -47,13 +47,19 @@ module.exports = function(source) {
const modules = Object.create(null)
descriptor.customBlocks = descriptor.customBlocks.filter(block => {
if (block.type === FILTER_TAG && block.attrs.module) {
if (
block.attrs.module ||
(
block.type === FILTER_TAG ||
block.attrs.lang === FILTER_TAG
)
) {
modules[block.attrs.module] = block
return true
}
})
if (Object.keys(modules)) {
if (Object.keys(modules).length) {
const filterModules = JSON.parse(JSON.stringify(modules))
Object.keys(filterModules).forEach(name => {
const filterModule = filterModules[name]
......
......@@ -125,7 +125,7 @@ function touchstart (evt) {
startPageY = pageY
longPressTimer = setTimeout(function () {
evt.target.dispatchEvent(new TouchEvent('longpress', {
evt.target.dispatchEvent(new CustomEvent('longpress', {
bubbles: true,
cancelable: true,
target: evt.target,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册