rewrite in es6
diff --git a/weex-loader/.eslintrc b/weex-loader/.eslintrc
new file mode 100644
index 0000000..52151b0
--- /dev/null
+++ b/weex-loader/.eslintrc
@@ -0,0 +1,141 @@
+{
+  "parserOptions": {
+    "ecmaVersion": 6,
+    "sourceType": "module"
+  },
+
+  "env": {
+    "es6": true,
+    "node": true,
+    "mocha": true
+  },
+
+  "globals": {
+    "document": false,
+    "navigator": false,
+    "window": false,
+    "location": false,
+    "callNative": false,
+    "callJS": false
+  },
+
+  "rules": {
+    "accessor-pairs": 2,
+    "arrow-spacing": [2, { "before": true, "after": true }],
+    "block-spacing": [2, "always"],
+    "brace-style": [2, "stroustrup", { "allowSingleLine": true }],
+    "camelcase": [2, { "properties": "never" }],
+    "comma-dangle": [2, "never"],
+    "comma-spacing": [2, { "before": false, "after": true }],
+    "comma-style": [2, "last"],
+    "constructor-super": 2,
+    "curly": [2, "multi-line"],
+    "dot-location": [2, "property"],
+    "eol-last": 2,
+    "eqeqeq": [2, "allow-null"],
+    "generator-star-spacing": [2, { "before": true, "after": true }],
+    "handle-callback-err": [2, "^(err|error)$" ],
+    "indent": [2, 2, { "SwitchCase": 1 }],
+    "key-spacing": [2, { "beforeColon": false, "afterColon": true }],
+    "keyword-spacing": [2, { "before": true, "after": true }],
+    "new-cap": [2, { "newIsCap": true, "capIsNew": false }],
+    "new-parens": 2,
+    "no-array-constructor": 2,
+    "no-caller": 2,
+    "no-class-assign": 2,
+    "no-cond-assign": 2,
+    "no-const-assign": 2,
+    "no-control-regex": 2,
+    "no-debugger": 2,
+    "no-delete-var": 2,
+    "no-dupe-args": 2,
+    "no-dupe-class-members": 2,
+    "no-dupe-keys": 2,
+    "no-duplicate-case": 2,
+    "no-empty-character-class": 2,
+    "no-empty-pattern": 2,
+    "no-eval": 2,
+    "no-ex-assign": 2,
+    "no-extend-native": 2,
+    "no-extra-bind": 2,
+    "no-extra-boolean-cast": 2,
+    "no-extra-parens": [2, "functions"],
+    "no-fallthrough": 2,
+    "no-floating-decimal": 2,
+    "no-func-assign": 2,
+    "no-implied-eval": 2,
+    "no-inner-declarations": [2, "functions"],
+    "no-invalid-regexp": 2,
+    "no-irregular-whitespace": 2,
+    "no-iterator": 2,
+    "no-label-var": 2,
+    "no-labels": [2, { "allowLoop": false, "allowSwitch": false }],
+    "no-lone-blocks": 2,
+    "no-mixed-spaces-and-tabs": 2,
+    "no-multi-spaces": 2,
+    "no-multi-str": 2,
+    "no-multiple-empty-lines": [2, { "max": 1 }],
+    "no-native-reassign": 2,
+    "no-negated-in-lhs": 2,
+    "no-new-object": 2,
+    "no-new-require": 2,
+    "no-new-symbol": 2,
+    "no-new-wrappers": 2,
+    "no-obj-calls": 2,
+    "no-octal": 2,
+    "no-octal-escape": 2,
+    "no-path-concat": 2,
+    "no-proto": 2,
+    "no-redeclare": 2,
+    "no-regex-spaces": 2,
+    "no-return-assign": [2, "except-parens"],
+    "no-self-assign": 2,
+    "no-self-compare": 2,
+    "no-sequences": 2,
+    "no-shadow-restricted-names": 2,
+    "no-spaced-func": 2,
+    "no-sparse-arrays": 2,
+    "no-this-before-super": 2,
+    "no-throw-literal": 2,
+    "no-trailing-spaces": 2,
+    "no-undef": 2,
+    "no-undef-init": 2,
+    "no-unexpected-multiline": 2,
+    "no-unmodified-loop-condition": 2,
+    "no-unneeded-ternary": [2, { "defaultAssignment": false }],
+    "no-unreachable": 2,
+    "no-unsafe-finally": 2,
+    "no-unused-vars": [2, { "vars": "all", "args": "none" }],
+    "no-useless-call": 2,
+    "no-useless-computed-key": 2,
+    "no-useless-constructor": 2,
+    "no-useless-escape": 2,
+    "no-whitespace-before-property": 2,
+    "no-with": 2,
+    "one-var": [2, { "initialized": "never" }],
+    // "operator-linebreak": [2, "after", { "overrides": { "?": "before", ":": "before" } }],
+    "padded-blocks": [2, "never"],
+    "quotes": [2, "single", {"avoidEscape": true, "allowTemplateLiterals": true}],
+    "semi": [2, "never"],
+    "semi-spacing": [2, { "before": false, "after": true }],
+    "space-before-blocks": [2, "always"],
+    "space-before-function-paren": [2, "always"],
+    "space-in-parens": [2, "never"],
+    "space-infix-ops": 2,
+    "space-unary-ops": [2, { "words": true, "nonwords": false }],
+    "spaced-comment": [2, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }],
+    "template-curly-spacing": [2, "never"],
+    "use-isnan": 2,
+    "valid-typeof": 2,
+    "wrap-iife": [2, "any"],
+    "yield-star-spacing": [2, "both"],
+    "yoda": [2, "never"],
+
+    "no-var": 2,
+    "prefer-const": 2,
+    "object-curly-spacing": [2, "always", {
+      objectsInObjects: false
+    }],
+    "array-bracket-spacing": [2, "never"]
+  }
+}
diff --git a/weex-loader/.gitignore b/weex-loader/.gitignore
index 9730c19..a76bb72 100644
--- a/weex-loader/.gitignore
+++ b/weex-loader/.gitignore
@@ -1,4 +1,5 @@
 node_modules
+lib
 
 test/actual
 test/expect/*.js
diff --git a/weex-loader/.npmignore b/weex-loader/.npmignore
index 79e6ea4..246c4aa 100644
--- a/weex-loader/.npmignore
+++ b/weex-loader/.npmignore
@@ -1,2 +1,3 @@
 node_modules
-test
\ No newline at end of file
+src
+test
diff --git a/weex-loader/index.js b/weex-loader/index.js
index a4b96d7..9615572 100644
--- a/weex-loader/index.js
+++ b/weex-loader/index.js
@@ -1,284 +1 @@
-'use strict';
-
-var path = require('path');
-var fs = require('fs');
-var md5 = require('md5');
-var loaderUtils = require('loader-utils');
-var blocker = require('weex-transformer/lib/blocker');
-
-var pkg = require('./package.json');
-var transformerVersion = pkg.dependencies['weex-transformer'].match(/\d+(?:\.\d+){0,2}/)[0];
-
-var templater = require('weex-templater');
-var styler = require('weex-styler');
-var scripter = require('weex-scripter');
-
-var MODULE_EXPORTS_REG = /module\.exports/g;
-var REQUIRE_REG = /require\((["'])(\@weex\-module\/[^\)\1]+)\1\)/g;
-
-function parseScript(loader, params, source, config, data, elementName, elements) {
-    elements = elements || []
-
-    if (!scripter) {
-        return Promise.reject('please use a script parser. e.g. weex-scripter');
-    }
-
-    var target = scripter.fix(source);
-    var name = elementName || params.resourceQuery.name ||
-                    path.basename(params.resourcePath).replace(/\..*$/, '');
-
-    if (!elementName && params.resourceQuery.entry === true) {
-        name = md5(source);
-    }
-
-    target = target.replace(MODULE_EXPORTS_REG, '__weex_module__.exports')
-                .replace(REQUIRE_REG, '__weex_require__($1$2$1)');
-
-    target = ';__weex_define__("@weex-component/' + name + '", [], ' + 
-                'function(__weex_require__, __weex_exports__, __weex_module__)' + 
-                '{\n' + target + '\n})';
-
-    if (!elementName && params.resourceQuery.entry === true) {
-        target += '\n;__weex_bootstrap__("@weex-component/' + name + '", ' + 
-                    String(config) + ',' + 
-                    String(data) + ')';
-    }
-
-    target = elements.concat(target).join(';\n\n')
-
-    return Promise.resolve(target);
-}
-
-var logLevel = false;
-function logWarning(loader, log) {
-    if (logLevel === false) return;
-
-    if (log && log instanceof Array) {
-        log.forEach(function(l) {
-            loader.emitWarning(l.reason + '\t@' + l.line + ':' + l.column)
-        });
-    }
-}
-
-function parseStyle(loader, params, source) {
-    return new Promise(function(resolve, reject) {
-        if (!styler) {
-            return reject('please use a style parser. e.g. weex-styler');
-        }
-
-        styler.parse(source, function(err, obj) {
-            if (err) {
-                reject(err);
-            } else {
-                logWarning(loader, obj.log);
-                var target = JSON.stringify(obj.jsonStyle, null, '  ');
-                resolve(target);
-            }
-        });
-    });
-}
-
-var FUNC_START = '#####FUN_S#####';
-var FUNC_START_REG = new RegExp('["\']' + FUNC_START, 'g');
-var FUNC_END = '#####FUN_E#####';
-var FUNC_END_REG = new RegExp(FUNC_END + '["\']', 'g');
-function stringifyFunction(key, value) {
-    if (typeof value === 'function') {
-      return  FUNC_START + value.toString() + '#####FUN_E#####';
-    }
-    return value;
-}
-
-function parseTemplate(loader, params, source, deps) {
-    return new Promise(function(resolve, reject) {
-        if (!templater) {
-            return reject('please use a template parser. e.g. weex-templater');
-        }
-
-        templater.parse(source, function(err, obj) {
-            if (err) {
-                reject(err);
-            } else {
-                logWarning(loader, obj.log);
-
-                if (deps && obj.deps) {
-                    var context = path.dirname(params.resourcePath);
-                    obj.deps.map(function(dep) {
-                        var filename = './' + dep + '.we';
-                        var filepath = path.resolve(context, filename);
-                        if (fs.existsSync(filepath)) {
-                            return filename;
-                        }
-                    }).forEach(function(dep) {
-                        if (dep) {
-                            deps.push(dep);
-                        }
-                    });
-                }
-
-                var target = JSON.stringify(obj.jsonTemplate, stringifyFunction, '  ');
-                target = target.replace(FUNC_START_REG, '')
-                        .replace(FUNC_END_REG, '');
-
-                resolve(target);
-            }
-        });
-    });
-}
-
-function parseWeexFile(loader, params, source, deps, elementName) {
-    var results;
-    deps = deps || [];
-
-    return new Promise(function(resolve, reject) {
-        blocker.format(source, function(err, ret) {
-            if (err) {
-                reject(err);
-            } else {
-                results = ret;
-                resolve();
-            }
-        });
-    }).then(function() {
-        var promises = [Promise.resolve(), Promise.resolve(), Promise.resolve()];
-        var content;
-        if (results.elements) {
-            var elPromises = []
-            Object.keys(results.elements).forEach(function (key) {
-                var el = results.elements[key];
-                elPromises.push(parseWeexFile(loader, params, el.content, deps, el.name));
-            });
-            promises[0] = Promise.all(elPromises);
-        }
-        if (results.template) {
-            content = results.template.content;
-            promises[1] = parseTemplate(loader, params, content, deps);
-        }
-        if (results.styles) {
-            content = results.styles.reduce(function(pre, cur) {
-                return pre + '\n' + cur.content;
-            }, '');
-            promises[2] = parseStyle(loader, params, content);
-        }
-
-        return Promise.all(promises);
-    }).then(function(ret) {
-        var elements = ret[0] || [];
-        var template = ret[1];
-        var style = ret[2];
-
-        var content = '';
-        var config = {};
-        var data;
-
-        if (results.scripts) {
-            content += results.scripts.reduce(function(pre, cur) {
-                return pre + '\n;' + cur.content;
-            }, '');
-        }
-
-        var requireContent = '';
-        if (deps.length) {
-            requireContent += deps.map(function(dep) {
-                if (!content.match(new RegExp('require\\(["\']./' + path.basename(dep) + '(\.we)?["\']\\)', 'g'))) {
-                    return 'require("' + dep + '");';
-                } else {
-                    return '';
-                }
-            }).join('\n');
-            content = requireContent + '\n' + content;
-        }
-
-        if (template) {
-            content += '\n;module.exports.template = module.exports.template || {}' + 
-                        '\n;Object.assign(module.exports.template, ' + template + ')';
-        }
-
-        if (style) {
-            content += '\n;module.exports.style = module.exports.style || {}' + 
-                        '\n;Object.assign(module.exports.style, ' + style + ')';
-        }
-
-        if (results.config) {
-            config = new Function('return ' + results.config.content.replace(/\n/g, ''))();
-        }
-        config.transformerVersion = transformerVersion;
-        config = JSON.stringify(config, null, '  ');
-
-        if (results.data) {
-            data = new Function('return ' + results.data.content.replace(/\n/g, ''))();
-            data = JSON.stringify(data, null, ' ');
-        }
-        return parseScript(loader, params, content, config, data, elementName, elements);
-    });
-}
-
-function partedLoader(type, loader, params, source) {
-    var promise;
-    switch(type) {
-        case 'js':
-        case 'script':
-            var config = JSON.stringify({
-                transformerVersion: transformerVersion
-            });
-            promise = parseScript(loader, params, source, config);
-            break;
-        case 'css':
-        case 'style':
-            promise = parseStyle(loader, params, source);
-            break;
-        case 'html':
-        case 'tpl':
-        case 'template':
-            promise = parseTemplate(loader, params, source);
-            break;
-        case 'we':
-        default:
-            promise = parseWeexFile(loader, params, source);
-            break;
-    }
-    return promise;
-}
-
-function loader(source) {
-    var self = this;
-    this.cacheable && this.cacheable();
-
-    var callback = this.async();
-    var params = {
-        loaderQuery: loaderUtils.parseQuery(this.query),
-        resourceQuery: loaderUtils.parseQuery(this.resourceQuery),
-        resourcePath: this.resourcePath
-    };
-    var type = params.loaderQuery.type || 'we';
-    var promise = partedLoader(type, this, params, source);
-
-    promise.then(function(result) {
-        if (type === 'style' || type === 'css' ||
-            type === 'html' || type === 'tpl' || type === 'template') {
-            result = 'module.exports=' + result;
-        }
-        callback(null, result);
-    }).catch(function(err) {
-        self.emitError(err.toString());
-        callback(err.toString(), '');
-    });
-}
-
-loader.useScripter = function(module) {
-    console.warn('\u001b[1;32m[Warn]\u001b[0m: method useScripter() in weex-loader is no more necessary');
-}
-
-loader.useStyler = function(module) {
-    console.warn('\u001b[1;32m[Warn]\u001b[0m: method useStyler() in weex-loader is no more necessary');
-}
-
-loader.useTemplater = function(module) {
-    console.warn('\u001b[1;32m[Warn]\u001b[0m: method useTemplater() in weex-loader is no more necessary');
-}
-
-loader.setLogLevel = function(level) {
-    logLevel = level
-}
-
-module.exports = loader;
+module.exports = require('./lib/')
diff --git a/weex-loader/package.json b/weex-loader/package.json
index fd2adc4..bc50969 100644
--- a/weex-loader/package.json
+++ b/weex-loader/package.json
@@ -16,17 +16,21 @@
     "transformer"
   ],
   "scripts": {
+    "prepublish": "node_modules/babel-cli/bin/babel.js src --out-dir lib",
+    "test:lint": "eslint src",
     "test:build": "webpack --config test/webpack.config.js",
     "test:transform": "transformer test/expect/*.we -o test/expect",
-    "test:mocha": "mocha --compilers js:babel-core/register test/test.js",
-    "test": "npm run test:build && npm run test:transform && npm run test:mocha",
+    "test:mocha": "mocha test/test.js",
+    "test": "npm run prepublish && npm run test:lint && npm run test:build && npm run test:transform && npm run test:mocha",
     "serve": "serve ./test -p 12581"
   },
   "devDependencies": {
-    "babel-core": "^6.7.6",
+    "babel-cli": "^6.10.1",
+    "babel-core": "^6.10.4",
     "babel-loader": "^6.2.4",
-    "babel-preset-es2015": "^6.6.0",
+    "babel-preset-es2015": "^6.9.0",
     "chai": "^3.5.0",
+    "eslint": "^2.13.1",
     "less": "^2.6.1",
     "less-loader": "^2.2.3",
     "mocha": "^2.4.5",
@@ -38,9 +42,13 @@
   "dependencies": {
     "loader-utils": "~0.2.14",
     "md5": "^2.1.0",
+    "source-map": "^0.5.6",
     "weex-scripter": "^0.1.4",
     "weex-styler": "^0.0.17",
     "weex-templater": "^0.2.1",
     "weex-transformer": "^0.3.1"
+  },
+  "babel": {
+    "presets": ["es2015"]
   }
 }
diff --git a/weex-loader/src/config.js b/weex-loader/src/config.js
new file mode 100644
index 0000000..c1e9e30
--- /dev/null
+++ b/weex-loader/src/config.js
@@ -0,0 +1,3 @@
+import pkg from '../package.json'
+export const transformerVersion = pkg.dependencies['weex-transformer'].match(/\d+(?:\.\d+){0,2}/)[0]
+export const logLevel = false
diff --git a/weex-loader/src/index.js b/weex-loader/src/index.js
new file mode 100644
index 0000000..fbec04e
--- /dev/null
+++ b/weex-loader/src/index.js
@@ -0,0 +1,70 @@
+import loaderUtils from 'loader-utils'
+
+import {
+  parseScript,
+  parseStyle,
+  parseTemplate,
+  parseWeexFile
+} from './parser'
+import * as config from './config'
+import * as legacy from './legacy'
+
+function partedLoader (type, loader, params, source) {
+  let promise
+  switch (type) {
+    case 'js':
+    case 'script':
+      const transformerVersion = config.transformerVersion
+      promise = parseScript(loader, params, source,
+        { config: JSON.stringify({ transformerVersion }) })
+      break
+    case 'css':
+    case 'style':
+      promise = parseStyle(loader, params, source)
+      break
+    case 'html':
+    case 'tpl':
+    case 'template':
+      promise = parseTemplate(loader, params, source)
+      break
+    case 'we':
+    default:
+      promise = parseWeexFile(loader, params, source)
+      break
+  }
+  return promise
+}
+
+function loader (source) {
+  this.cacheable && this.cacheable()
+
+  const callback = this.async()
+  const params = {
+    loaderQuery: loaderUtils.parseQuery(this.query),
+    resourceQuery: loaderUtils.parseQuery(this.resourceQuery),
+    resourcePath: this.resourcePath
+  }
+  const type = params.loaderQuery.type || 'we'
+  const promise = partedLoader(type, this, params, source)
+
+  promise.then(result => {
+    if (type === 'style' || type === 'css' ||
+      type === 'html' || type === 'tpl' || type === 'template') {
+      result = 'module.exports=' + result
+    }
+    callback(null, result)
+  }).catch(err => {
+    this.emitError(err.toString())
+    callback(err.toString(), '')
+  })
+}
+
+loader.setLogLevel = level => {
+  config.logLevel = level
+}
+
+for (const key in legacy) {
+  loader[key] = legacy[key]
+}
+
+module.exports = loader
diff --git a/weex-loader/src/legacy.js b/weex-loader/src/legacy.js
new file mode 100644
index 0000000..4754970
--- /dev/null
+++ b/weex-loader/src/legacy.js
@@ -0,0 +1,13 @@
+export function useScripter () {
+  warn('useScripter()')
+}
+export function useStyler () {
+  warn('useStyler()')
+}
+export function useTemplater () {
+  warn('useTemplater()')
+}
+
+function warn (method) {
+  console.warn(`\u001b[1;32m[Warn]\u001b[0m: method ${method} in weex-loader is no more necessary`)
+}
diff --git a/weex-loader/src/parser.js b/weex-loader/src/parser.js
new file mode 100644
index 0000000..ac1dd76
--- /dev/null
+++ b/weex-loader/src/parser.js
@@ -0,0 +1,211 @@
+import blocker from 'weex-transformer/lib/blocker'
+import templater from 'weex-templater'
+import styler from 'weex-styler'
+import scripter from 'weex-scripter'
+
+import md5 from 'md5'
+
+import { transformerVersion } from './config'
+import {
+  MODULE_EXPORTS_REG,
+  REQUIRE_REG,
+  FUNC_START_REG,
+  FUNC_END_REG,
+  getNameByPath,
+  checkFileExist,
+  depHasRequired,
+  stringifyFunction,
+  appendToWarn
+} from './util'
+
+export function parseWeexFile (loader, params, source, deps, elementName) {
+  return new Promise(
+    // separate source into <element>s, <template>, <style>s and <script>s
+    separateBlocks(source, deps || []))
+    // pre-parse non-javascript parts
+    .then(preParseBlocks(loader, params, elementName))
+    // join blocks together and parse as javascript finally
+    .then(parseBlocks(loader, params, elementName))
+}
+
+function separateBlocks (source, deps) {
+  return (resolve, reject) => {
+    blocker.format(source, (err, ret) => {
+      if (err) {
+        reject(err)
+      }
+      else {
+        ret.deps = deps
+        resolve(ret)
+      }
+    })
+  }
+}
+
+function preParseBlocks (loader, params) {
+  return (blocks) => {
+    const { deps, elements, template, styles, scripts, config, data } = blocks
+    const promises = [
+      Promise.resolve(),
+      Promise.resolve(),
+      Promise.resolve(),
+      Promise.resolve(scripts),
+      Promise.resolve(deps),
+      Promise.resolve(config),
+      Promise.resolve(data)
+    ]
+    let content
+    // pre-parse sub elements
+    if (elements) {
+      const elPromises = []
+      Object.keys(elements).forEach(key => {
+        const el = elements[key]
+        elPromises.push(parseWeexFile(loader, params, el.content, deps, el.name))
+      })
+      promises[0] = Promise.all(elPromises)
+    }
+    // pre-parse template
+    if (template) {
+      content = template.content
+      promises[1] = parseTemplate(loader, params, content, deps)
+    }
+    // pre-parse styles
+    if (styles) {
+      content = styles.reduce((pre, cur) => {
+        return pre + '\n' + cur.content
+      }, '')
+      promises[2] = parseStyle(loader, params, content)
+    }
+    return Promise.all(promises)
+  }
+}
+
+function parseBlocks (loader, params, elementName) {
+  return (results) => {
+    const elements = results[0] || []
+    const template = results[1]
+    const style = results[2]
+    const scripts = results[3]
+    const deps = results[4] || []
+    const configResult = results[5]
+    const dataResult = results[6]
+
+    let content = ''
+    let config = {}
+    let data
+
+    if (scripts) {
+      content += scripts.reduce((pre, cur) => {
+        return pre + '\n;' + cur.content
+      }, '')
+    }
+
+    let requireContent = ''
+    if (deps.length) {
+      requireContent += deps.map(dep =>
+        depHasRequired(content, dep) ? 'require("' + dep + '");' : ''
+      ).join('\n')
+      content = requireContent + '\n' + content
+    }
+
+    if (template) {
+      content += '\n;module.exports.template = module.exports.template || {}' +
+        '\n;Object.assign(module.exports.template, ' + template + ')'
+    }
+
+    if (style) {
+      content += '\n;module.exports.style = module.exports.style || {}' +
+        '\n;Object.assign(module.exports.style, ' + style + ')'
+    }
+
+    if (configResult) {
+      config = new Function('return ' + configResult.content.replace(/\n/g, ''))()
+    }
+    config.transformerVersion = transformerVersion
+    config = JSON.stringify(config, null, 2)
+
+    if (dataResult) {
+      data = new Function('return ' + dataResult.content.replace(/\n/g, ''))()
+      data = JSON.stringify(data, null, 2)
+    }
+
+    return parseScript(loader, params, content, { config, data, elementName, elements })
+  }
+}
+
+export function parseTemplate (loader, params, source, deps) {
+  return new Promise((resolve, reject) => {
+    templater.parse(source, (err, obj) => {
+      if (err) {
+        reject(err)
+      }
+      else {
+        appendToWarn(loader, obj.log)
+        // push valid obj.deps to deps
+        if (deps && obj.deps) {
+          obj.deps.map(
+            dep => checkFileExist(dep, params.resourcePath)
+          ).forEach(dep => {
+            if (dep) {
+              deps.push(dep)
+            }
+          })
+        }
+        // parse json to string and treat function specially
+        let target = JSON.stringify(obj.jsonTemplate, stringifyFunction, '  ')
+        target = target.replace(FUNC_START_REG, '').replace(FUNC_END_REG, '')
+        resolve(target)
+      }
+    })
+  })
+}
+
+export function parseStyle (loader, params, source) {
+  return new Promise((resolve, reject) => {
+    styler.parse(source, (err, obj) => {
+      if (err) {
+        reject(err)
+      }
+      else {
+        appendToWarn(loader, obj.log)
+        resolve(JSON.stringify(obj.jsonStyle, null, 2))
+      }
+    })
+  })
+}
+
+export function parseScript (loader, params, source, env) {
+  const { config, data, elementName, elements } = env
+
+  // the entry component has a special resource query and not a sub element tag
+  const isEntry = params.resourceQuery.entry === true && !elementName
+
+  // resolve component name
+  const name = isEntry
+    ? md5(source)
+    : (elementName || params.resourceQuery.name || getNameByPath(params.resourcePath))
+
+  // fix data option from an object to a function
+  let target = scripter.fix(source)
+
+  // wrap with __weex_define__(name, [], (r, e, m) {...})
+  target = target
+      .replace(MODULE_EXPORTS_REG, '__weex_module__.exports')
+      .replace(REQUIRE_REG, '__weex_require__($1$2$1)')
+  target = ';__weex_define__("@weex-component/' + name + '", [], ' +
+      'function(__weex_require__, __weex_exports__, __weex_module__)' +
+      '{\n' + target + '\n})'
+
+  // append __weex_bootstrap__ for entry component
+  if (isEntry) {
+    target += '\n;__weex_bootstrap__("@weex-component/' + name + '", ' +
+        String(config) + ',' +
+        String(data) + ')'
+  }
+
+  // join with elements deps
+  target = (elements || []).concat(target).join(';\n\n')
+
+  return Promise.resolve(target)
+}
+
diff --git a/weex-loader/src/util.js b/weex-loader/src/util.js
new file mode 100644
index 0000000..3417388
--- /dev/null
+++ b/weex-loader/src/util.js
@@ -0,0 +1,42 @@
+import fs from 'fs'
+import path from 'path'
+
+import * as config from './config'
+
+export const MODULE_EXPORTS_REG = /module\.exports/g
+export const REQUIRE_REG = /require\((["'])(@weex\-module\/[^\)\1]+)\1\)/g
+
+export function getNameByPath (filepath) {
+  return path.basename(filepath).replace(/\..*$/, '')
+}
+
+export const FUNC_START = '#####FUN_S#####'
+export const FUNC_START_REG = new RegExp('["\']' + FUNC_START, 'g')
+export const FUNC_END = '#####FUN_E#####'
+export const FUNC_END_REG = new RegExp(FUNC_END + '["\']', 'g')
+
+export function stringifyFunction (key, value) {
+  if (typeof value === 'function') {
+    return FUNC_START + value.toString() + '#####FUN_E#####'
+  }
+  return value
+}
+
+export function appendToWarn (loader, logs) {
+  if (config.logLevel && logs && logs.length) {
+    logs.forEach(log => {
+      loader.emitWarning(log.reason + '\t@' + log.line + ':' + log.column)
+    })
+  }
+}
+
+export function checkFileExist (name, resourcePath) {
+  const context = path.dirname(resourcePath)
+  const filename = './' + name + '.we'
+  const filepath = path.resolve(context, filename)
+  return fs.existsSync(filepath) ? filename : null
+}
+
+export function depHasRequired (content, dep) {
+  return !content.match(new RegExp('require\\(["\']./' + path.basename(dep) + '(.we)?["\']\\)', 'g'))
+}
diff --git a/weex-loader/test/webpack.config.js b/weex-loader/test/webpack.config.js
index 6f306fe..4833d07 100644
--- a/weex-loader/test/webpack.config.js
+++ b/weex-loader/test/webpack.config.js
@@ -1,6 +1,4 @@
-var path = require('path');
-var webpack = require('webpack');
-var loader = require('../index.js');
+var path = require('path')
 
 module.exports = {
   entry: {
@@ -42,4 +40,4 @@
   resolveLoader: {
     modulesDirectories: ['./', './node_modules']
   }
-};
+}