added test case for sourcemap
diff --git a/src/map.js b/src/map.js
index 6a925dd..b859690 100644
--- a/src/map.js
+++ b/src/map.js
@@ -26,6 +26,7 @@
     const current = this.current
     this.current = {}
 
+    // re-order the elements and scripts into history
     const length = current.elements.length
     if (length > 0) {
       const children = this.history.splice(-length, length)
@@ -50,10 +51,12 @@
     if (!this.enabled) { return }
     this.current.elements.push({ name, index, line, length })
   }
+
   addScript (name, info, externalOffset) {
     if (!this.enabled) { return }
     this.current.scripts.push({ name, info, externalOffset })
   }
+
   setElementPosition (name, line, column) {
     if (!this.enabled) { return }
     this.elements[name] = { line, column }
@@ -73,9 +76,9 @@
       const { original, generated } = info
       const scriptLength = info.length
       this.add(
-        original.line + (elInfo.line || 1) - 2,
+        original.line + (elInfo.line || 1) - 1,
         scriptLength,
-        generated.line + startLine + (line || 1) + externalOffset
+        generated.line + startLine + (line || 1) - 1 + externalOffset
       )
     });
 
diff --git a/src/parser.js b/src/parser.js
index 24910de..03b9a80 100644
--- a/src/parser.js
+++ b/src/parser.js
@@ -60,6 +60,7 @@
       const elPromises = []
       Object.keys(elements).forEach(key => {
         const el = elements[key]
+        // record original positions of each <element>
         map.setElementPosition(el.name, el.line, el.column)
         elPromises.push(parseWeex(loader, params, el.content, map, deps, el.name))
       })
@@ -98,17 +99,23 @@
     const mapOffset = { basic: 0, subs: [] }
 
     if (scripts) {
-      content += scripts.reduce((pre, cur) => {
-        const line = pre.split(/\r?\n/g).length
+      // record original and generated position of each <script>
+      // the generated content is begin with empty string
+      // so later the template, styles and elements will be appended/prepended
+      // and mapOffset.basic will record lines of prepended *required* content
+      content += scripts.reduce((prev, next, i) => {
+        // length of previous content
+        const line = prev.split(/\r?\n/g).length + 1
         const column = 1
-        const oriLine = cur.line - 1
-        const oriColumn = cur.column
+        const oriLine = next.line
+        const oriColumn = next.column
         mapOffset.subs.push({
           original: { line: oriLine, column: oriColumn },
           generated: { line, column },
-          length: cur.content.split(/\r?\n/g).length
+          // length of next content
+          length: next.content.split(/\r?\n/g).length
         })
-        return pre + '\n;' + cur.content
+        return prev + '\n;' + next.content
       }, '')
     }
 
@@ -118,27 +125,32 @@
         depHasRequired(content, dep) ? 'require("' + dep + '");' : ''
       ).join('\n')
       if (requireContent) {
-        content = requireContent + '\n' + content
+        // length of implicitly requires
         mapOffset.basic = requireContent.split(/\r?\n/g).length
+        content = requireContent + '\n' + content
       }
     }
 
     if (template) {
+      // append template content, not impact sourcemap
       content += '\n;module.exports.template = module.exports.template || {}' +
         '\n;Object.assign(module.exports.template, ' + template + ')'
     }
 
     if (style) {
+      // append style content, not impact sourcemap
       content += '\n;module.exports.style = module.exports.style || {}' +
         '\n;Object.assign(module.exports.style, ' + style + ')'
     }
 
+    // prepare entry config
     if (configResult) {
       config = new Function('return ' + configResult.content.replace(/\n/g, ''))()
     }
     config.transformerVersion = transformerVersion
     config = JSON.stringify(config, null, 2)
 
+    // prepare entry data
     if (dataResult) {
       data = new Function('return ' + dataResult.content.replace(/\n/g, ''))()
       data = JSON.stringify(data, null, 2)
@@ -201,11 +213,14 @@
     : (elementName || params.resourceQuery.name || getNameByPath(params.resourcePath))
 
   // join with elements deps
-  // 2 more lines at end
+  // 2 more lines between each element and the end
   map && map.start()
-  const prefix = (elements || []).reduce((current, next, index) => {
-    map && map.addElement(name, index, current.split(/\r?\n/g).length, next.split(/\r?\n/g).length)
-    return current + next + ';\n\n'
+  const prefix = (elements || []).reduce((prev, next, index) => {
+    const prevLength = prev.split(/\r?\n/g).length
+    const nextLength = next.split(/\r?\n/g).length
+    // record generated positions of each <element>
+    map && map.addElement(name, index, prevLength, nextLength)
+    return prev + next + ';\n\n'
   }, '')
 
   // fix data option from an object to a function
@@ -219,12 +234,19 @@
   target = ';__weex_define__("@weex-component/' + name + '", [], ' +
       'function(__weex_require__, __weex_exports__, __weex_module__)' +
       '{\n' + target + '\n})'
-  mapOffset && mapOffset.subs.forEach(info => {
-    map.addScript(elementName || name, info, prefix.split(/\r?\n/g).length + mapOffset.basic)
-  })
+
+  // record mapOffset into sourcemap
+  if (mapOffset) {
+    // length of generated prefix (elements) and basic (implicitly requires)
+    const preLines = prefix.split(/\r?\n/g).length + mapOffset.basic
+    mapOffset.subs.forEach(info => {
+      map.addScript(elementName || name, info, preLines)
+    })
+  }
   map && map.end()
 
   // append __weex_bootstrap__ for entry component
+  // not impact sourcemap
   if (isEntry) {
     target += '\n;__weex_bootstrap__("@weex-component/' + name + '", ' +
         String(config) + ',' +
diff --git a/test/a.js b/test/a.js
index b8f9f49..574e715 100644
--- a/test/a.js
+++ b/test/a.js
@@ -10,4 +10,4 @@
 }
 
 module.exports.style = require('./a.less');
-module.exports.template = require('./a.tpl');
\ No newline at end of file
+module.exports.template = require('./a.tpl');
diff --git a/test/expect/a.we b/test/expect/a.we
index 2ea3b36..2565076 100644
--- a/test/expect/a.we
+++ b/test/expect/a.we
@@ -24,4 +24,4 @@
         text: 'Hello ' + c.name
     }
 }
-</script>
\ No newline at end of file
+</script>
diff --git a/test/expect/sourcemap.we b/test/expect/sourcemap.we
new file mode 100644
index 0000000..f798f7f
--- /dev/null
+++ b/test/expect/sourcemap.we
@@ -0,0 +1,26 @@
+<element name="foo">
+  <template>
+    <text>Hello</text>
+  </template>
+  <script>
+    console.log(6)
+    console.log(7)
+    console.log(8)
+    console.log(9)
+    console.log(0)
+  </script>
+</element>
+
+<template>
+  <div>
+    <foo></foo>
+  </div>
+</template>
+
+<script>
+  console.log(1)
+  console.log(2)
+  require('../lib/3rd.js')
+  console.log(4)
+  console.log(5)
+</script>
diff --git a/test/lib/3rd.js b/test/lib/3rd.js
index e132ec8..cc00e41 100644
--- a/test/lib/3rd.js
+++ b/test/lib/3rd.js
@@ -1 +1,4 @@
 'Hello 3rd-party JavaScript'
+'Hello 3rd-party JavaScript 2'
+'Hello 3rd-party JavaScript 3'
+'Hello 3rd-party JavaScript 4'
diff --git a/test/test.js b/test/test.js
index ab14972..e2a616d 100644
--- a/test/test.js
+++ b/test/test.js
@@ -7,6 +7,9 @@
 var expect = chai.expect;
 chai.use(sinonChai);
 
+var webpack = require('webpack')
+var SourceMapConsumer = require('source-map').SourceMapConsumer
+
 require('./lib/jsfm');
 var createInstance = global.createInstance;
 var getRoot = global.getRoot;
@@ -25,10 +28,10 @@
     var name = 'a.js';
 
     var actualCodePath = path.resolve(__dirname, 'actual', name);
-    var actualCodeContent = fs.readFileSync(actualCodePath);
+    var actualCodeContent = fs.readFileSync(actualCodePath, { encoding: 'utf8' });
 
     var expectCodePath = path.resolve(__dirname, 'expect', name);
-    var expectCodeContent = fs.readFileSync(expectCodePath);
+    var expectCodeContent = fs.readFileSync(expectCodePath, { encoding: 'utf8' });
 
 
     var actualResult = createInstance('actual/' + name, actualCodeContent);
@@ -44,10 +47,10 @@
     var name = 'b.js';
 
     var actualCodePath = path.resolve(__dirname, 'actual', name);
-    var actualCodeContent = fs.readFileSync(actualCodePath);
+    var actualCodeContent = fs.readFileSync(actualCodePath, { encoding: 'utf8' });
 
     var expectCodePath = path.resolve(__dirname, 'expect', name);
-    var expectCodeContent = fs.readFileSync(expectCodePath);
+    var expectCodeContent = fs.readFileSync(expectCodePath, { encoding: 'utf8' });
 
 
     var actualResult = createInstance('actual/' + name, actualCodeContent);
@@ -63,10 +66,10 @@
     var name = 'z.js';
 
     var actualCodePath = path.resolve(__dirname, 'actual', name);
-    var actualCodeContent = fs.readFileSync(actualCodePath);
+    var actualCodeContent = fs.readFileSync(actualCodePath, { encoding: 'utf8' });
 
     var expectCodePath = path.resolve(__dirname, 'expect', name);
-    var expectCodeContent = fs.readFileSync(expectCodePath);
+    var expectCodeContent = fs.readFileSync(expectCodePath, { encoding: 'utf8' });
 
 
     var actualResult = createInstance('actual/' + name, actualCodeContent);
@@ -77,4 +80,53 @@
 
     expect(actualJson).eql(expectJson);
   });
+
+  it('support source map', function() {
+    var name = 'sourcemap'
+
+    var mapPath = path.resolve(__dirname, 'actual', name + '.js.map');
+    var map = fs.readFileSync(mapPath, { encoding: 'utf8' });
+    var smc = new SourceMapConsumer(JSON.parse(map))
+
+    var oriPath = path.resolve(__dirname, 'expect', name + '.we');
+    var ori = fs.readFileSync(oriPath, { encoding: 'utf8' });
+
+    var genPath = path.resolve(__dirname, 'actual', name + '.js');
+    var gen = fs.readFileSync(genPath, { encoding: 'utf8' });
+
+    function matchPos(code, regexp) {
+      var line, col
+      code.split(/\r?\n/g).some(function (l, i) {
+        if (regexp.test(l)) {
+          line = i + 1
+          col = l.length
+          return true
+        }
+      })
+      return { line: line, col: col }
+    }
+
+    function checkPos(regexp) {
+      var genPos = matchPos(gen, regexp)
+      var oriPos = matchPos(ori, regexp)
+
+      var pos = smc.originalPositionFor({
+        line: genPos.line,
+        column: genPos.col
+      })
+
+      expect(pos.source.indexOf('sourcemap.we') > -1)
+      expect(pos.line).to.equal(oriPos.line)
+    }
+
+    checkPos(/console\.log\(1\)/)
+    checkPos(/console\.log\(2\)/)
+    checkPos(/console\.log\(4\)/)
+    checkPos(/console\.log\(5\)/)
+    checkPos(/console\.log\(6\)/)
+    checkPos(/console\.log\(7\)/)
+    checkPos(/console\.log\(8\)/)
+    checkPos(/console\.log\(9\)/)
+    checkPos(/console\.log\(0\)/)
+  })
 })
diff --git a/test/webpack.config.js b/test/webpack.config.js
index 4833d07..68792f3 100644
--- a/test/webpack.config.js
+++ b/test/webpack.config.js
@@ -2,6 +2,7 @@
 
 module.exports = {
   entry: {
+    sourcemap: path.resolve(__dirname, 'expect/sourcemap.we?entry=true'),
     a: path.resolve(__dirname, 'a.js?entry=true'),
     b: path.resolve(__dirname, 'expect/b.we?entry=true'),
     z: path.resolve(__dirname, 'expect/z.we?entry=true')
@@ -10,6 +11,7 @@
     path: path.resolve(__dirname, 'actual'),
     filename: '[name].js'
   },
+  devtool: 'source-map',
   module: {
     loaders: [
       {