Weex2Vue Tools
- Weex2Vue Tools
- Webpack config file for weex2vue.
- Optimize official webpack config. Add virtual files for vue entries. (优化官方webpack配置,使用虚拟文件作为vue-entry。)
- FooterPlugin for debugging js code. (给JS源文件添加调试注释)
- px-loader for weex css. (给weex文件的无单位数字添加px)
- weex2vue: transform weex files to vue files. (批量转换weex文件为vue文件)
- Webpack config file for weex2vue.
webpack.vue.config.js
const path = require('path');
const fs = require('fs');
const VirtualModulePlugin = require('virtual-module-webpack-plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
/* 添加 @sourceURL 方便动态脚本的调试 */
const FooterPlugin = require('./libs/FooterPlugin.js');
const entry = {};
const EXTNAME = '.vue';
const plugins = [new FooterPlugin()];
let outputPath = `${__dirname}/dist/browser`;
/* release 参数表示需要压缩当前js文件 */
if (process.argv.indexOf('--release') !== -1) {
outputPath = `${__dirname}/dist/release/browser`;
plugins.push(new UglifyJSPlugin());
}
/*
* 遍历所有后缀为 EXTNAME 的文件
*/
const walk = (dir, root) => {
const directory = path.join(__dirname, root, dir);
fs.readdirSync(directory).forEach((file) => {
const fullpath = path.join(directory, file);
const stat = fs.statSync(fullpath);
if (stat.isFile() && path.extname(fullpath) === EXTNAME) {
const name = path.join(dir, path.basename(file, EXTNAME));
// 加载一个虚拟的 entry.js 文件
entry[`${name}`] = `${name}.js`;
// 设置虚拟 entry.js 文件的内容,初始化 Vue
plugins.push(new VirtualModulePlugin({
moduleName: `./src/${name}.js`,
contents: `
var App = require('./${file}');
App.el = '#root';
new Vue(App);
`,
}));
} else if (stat.isDirectory()) {
const subdir = path.join(dir, file);
walk(subdir, root);
}
});
};
walk('./', 'src');
module.exports = {
entry,
output: {
path: outputPath,
filename: '[name].js',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
['env', {
targets: {
chrome: 52,
browsers: ['ie >= 8'],
},
}],
],
plugins: [
['transform-runtime', {
polyfill: false,
regenerator: true,
}],
],
},
},
}, {
test: /\.vue$/,
// 修复 weex 文件中,不带 px 的 bug
use: ['vue-loader', './libs/px-loader.js'],
}, {
test: /\.we$/,
// 修复 weex 文件中,不带 px 的 bug
use: ['vue-loader', './libs/px-loader.js'],
},
],
},
plugins,
resolve: {
modules: [
path.join(__dirname, 'src'),
'node_modules',
],
alias: {
components: path.resolve(__dirname, 'src/components')
}
},
};
px-loader
module.exports = function (source) {
this.cacheable && this.cacheable();
source = source
.replace(/height: (\d*);/g, 'height: $1px;')
.replace(/width: (\d*);/g, 'width: $1px;')
.replace(/top: (\d*);/g, 'top: $1px;')
.replace(/bottom: (\d*);/g, 'bottom: $1px;')
.replace(/left: (\d*);/g, 'left: $1px;')
.replace(/right: (\d*);/g, 'right: $1px;')
.replace(/margin-top: (\d*);/g, 'margin-top: $1px;')
.replace(/margin-bottom: (\d*);/g, 'margin-bottom: $1px;')
.replace(/margin-left: (\d*);/g, 'margin-left: $1px;')
.replace(/margin-right: (\d*);/g, 'margin-right: $1px;')
.replace(/padding-top: (\d*);/g, 'padding-top: $1px;')
.replace(/padding-bottom: (\d*);/g, 'padding-bottom: $1px;')
.replace(/padding-left: (\d*);/g, 'padding-left: $1px;')
.replace(/padding-right: (\d*);/g, 'padding-right: $1px;')
.replace(/line-height: (\d*);/g, 'line-height: $1px;')
.replace(/font-size: (\d*);/g, 'font-size: $1px;')
return source;
}
weex2vue
We can use weex-vue-migration
to transform our weex code to vue code. Of course, not all of the code can be transformed. So we need to modify some code if needed.
const fs = require('fs');
const path = require('path');
const migrater = require('weex-vue-migration')
/**
* 遍历文件夹
*/
const walkSync = (dir, files = []) => {
fs.readdirSync(dir).map((file) => {
fs.statSync(path.join(dir, file)).isDirectory()
? walkSync(path.join(dir, file), files)
: files.push({
name: file,
path: path.join(dir, file),
});
});
return files;
};
/*
* 转换单位
*/
const addPx = c => c
.replace(/height: (\d*);/g, 'height: $1px;')
.replace(/width: (\d*);/g, 'width: $1px;')
.replace(/top: (\d*);/g, 'top: $1px;')
.replace(/bottom: (\d*);/g, 'bottom: $1px;')
.replace(/left: (\d*);/g, 'left: $1px;')
.replace(/right: (\d*);/g, 'right: $1px;')
.replace(/margin-top: (\d*);/g, 'margin-top: $1px;')
.replace(/margin-bottom: (\d*);/g, 'margin-bottom: $1px;')
.replace(/margin-left: (\d*);/g, 'margin-left: $1px;')
.replace(/margin-right: (\d*);/g, 'margin-right: $1px;')
.replace(/padding-top: (\d*);/g, 'padding-top: $1px;')
.replace(/padding-bottom: (\d*);/g, 'padding-bottom: $1px;')
.replace(/padding-left: (\d*);/g, 'padding-left: $1px;')
.replace(/padding-right: (\d*);/g, 'padding-right: $1px;')
.replace(/line-height: (\d*);/g, 'line-height: $1px;')
.replace(/font-size: (\d*);/g, 'font-size: $1px;')
/*
* 转换表达式
*/
const expression = c => c
.replace(/\sv-for=['"](\S*?)['"]/g, ' v-for="(item, index) in $1"')
// 修改 $index
.replace(/\$index/g, 'index')
.replace(/([\S]*?-[\S]*?): require/g, ' "$1": require')
.replace(/wxcForm: require\('\.\/form\.vue'\)/g, 'wxcForm: require(\'wxc-form\')')
.replace(/textarea: require/g, '// textarea: require')
.replace(/toomaoWeb: require/g, '// toomaoWeb: require')
.replace('wxccomponents/navpage', 'wxccomponents/wxc-navpage')
.replace('wxccomponents/tabitem', 'wxccomponents/wxc-tabitem')
.replace('./navbar', './wxc-navbar')
.replace('./tabitem', './wxc-tabitem')
// 把wxc-form的依赖,转成相对路径
.replace('wxcForm: require(\'wxc-form\')', 'wxcForm: require(\'components/wxc-form/wxc-form.vue\')')
// 把wxc-form依赖去掉
.replace('require(\'wxc-form\')', '')
/**
* 标签转换
*/
const transformTag = c => c
.replace(/<style scoped="">/, '<style scoped>');
const dir = process.argv.find(arg => !/node|weex2vue/.test(arg)) || '../src';
walkSync(path.join(__dirname, dir)).map(file => {
if (/\.we$/.test(file.name)) {
let context = String(fs.readFileSync(file.path));
context = migrater.transform(context).content;
context = addPx(context);
context = expression(context);
context = transformTag(context);
context += '<!-- This file is created by weex2vue. -->';
fs.writeFileSync(file.path.replace(/\.we$/, '.vue'), context);
}
});
console.log('Done!');
Comments
Leave a comment