add sourcemap generator
diff --git a/.gitignore b/.gitignore
index 81ee3b6..a9f497d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 node_modules
 lib
 test/actual/*.js
+test/actual/*.map
 *.log
\ No newline at end of file
diff --git a/package.json b/package.json
index 93cd7cb..441d91f 100644
--- a/package.json
+++ b/package.json
@@ -34,7 +34,10 @@
     "babel-preset-es2015": "^6.9.0",
     "babel-runtime": "^6.9.2",
     "chai": "^3.5.0",
+    "coffee-loader": "^0.7.2",
+    "coffee-script": "^1.10.0",
     "eslint": "^2.13.1",
+    "jade": "^1.11.0",
     "jade-html-loader": "0.0.3",
     "mocha": "^2.4.5",
     "parse5": "^2.1.5",
diff --git a/src/extract.js b/src/extract.js
index df79ddb..c507912 100644
--- a/src/extract.js
+++ b/src/extract.js
@@ -3,6 +3,10 @@
 import {
   extractBlocks
 } from './parser'
+import {
+  splitSourceLine,
+  generateMap
+} from './util'
 
 module.exports = function (source) {
   this.cacheable && this.cacheable()
@@ -21,9 +25,44 @@
       if (index != null) {
         result = result[index]
       }
-      return result.content
-    }).then(content => {
-      callback(null, content)
+      const content = result.content.trim()
+      let map
+      if (this.sourceMap && type === 'scripts') {
+        let contentLineCount = 0
+        const iterator = splitSourceLine(content)
+                          .map((input, line) => {
+                            contentLineCount++
+                            line = line + 1
+                            return {
+                              original: {
+                                line: line + result.line,
+                                column: 0
+                              },
+                              generated: {
+                                line: line,
+                                column: 0
+                              }
+                            }
+                          })
+
+        const commentSource = splitSourceLine(source)
+                          .map((input, line) => {
+                            line = line + 1
+                            if (line <= result.line
+                                  || line > result.line + contentLineCount) {
+                              return '// ' + input + ' /* generated by weex-loader */'
+                            }
+                            else {
+                              return input
+                            }
+                          }).join('\n')
+
+        map = generateMap(this, commentSource, iterator)
+      }
+
+      return [content, map]
+    }).then(([content, map]) => {
+      callback(null, content, map && map.toJSON())
     }).catch(e => {
       callback(e, '')
     })
diff --git a/src/script.js b/src/script.js
index 95f385a..23b1eae 100644
--- a/src/script.js
+++ b/src/script.js
@@ -2,7 +2,7 @@
   parseScript
 } from './parser'
 
-module.exports = function (source) {
+module.exports = function (source, map) {
   this.cacheable && this.cacheable()
 
   const callback = this.async()
@@ -23,8 +23,9 @@
         }).join('\n')
       }
 
-      const result = `module.exports = function(module, exports, __weex_require__){${parsed}}`
-      callback(null, result)
+      let result = `module.exports = function(module, exports, __weex_require__){${parsed}}`
+      result += '\n/* generated by weex-loader */\n'
+      callback(null, result, map)
     }).catch(e => {
       callback(e, '')
     })
diff --git a/src/util.js b/src/util.js
index 29a7cca..325a734 100644
--- a/src/util.js
+++ b/src/util.js
@@ -1,10 +1,18 @@
 import path from 'path'
 import loaderUtils from 'loader-utils'
+import hash from 'hash-sum'
+import { SourceMapGenerator } from 'source-map'
 
 import * as config from './config'
 
-export function getNameByPath (filepath) {
-  return path.basename(filepath).replace(/\..*$/, '')
+export function getNameByPath (resourcePath) {
+  return path.basename(resourcePath).replace(/\..*$/, '')
+}
+
+export function getFileNameWithHash (resourcePath, content) {
+  const filename = path.relative('.', resourcePath)
+  const cacheKey = hash(filename + content)
+  return `${filename}?${cacheKey}`
 }
 
 export const FUNC_START = '#####FUN_S#####'
@@ -64,3 +72,24 @@
     }
   }).join('!')
 }
+
+export function generateMap (loader, source, iterator) {
+  const fileNameWithHash = getFileNameWithHash(loader.resourcePath)
+  const map = new SourceMapGenerator()
+  map.setSourceContent(fileNameWithHash, source)
+
+  for (const { original, generated } of iterator) {
+    map.addMapping({
+      source: fileNameWithHash,
+      original,
+      generated
+    })
+  }
+
+  return map
+}
+
+const LINE_REG = /\r?\n/g
+export function splitSourceLine (source) {
+  return source.split(LINE_REG)
+}
diff --git a/test/expect/c.js b/test/expect/c.js
index e8a9e2b..05aeac1 100644
--- a/test/expect/c.js
+++ b/test/expect/c.js
@@ -1,6 +1,6 @@
 {
   "@weex-component/192c464938a57dbd89308b3f2aaa0b18": {
-    "data": "function data() {\n\t        return {\n\t            name: 'Weex'\n\t        };\n\t    }",
+    "data": "function data() {\n\t    return {\n\t        name: 'Weex'\n\t    };\n\t}",
     "template": {
       "type": "div",
       "children": [
diff --git a/test/expect/d.js b/test/expect/d.js
index 4c2c59f..beb89fe 100644
--- a/test/expect/d.js
+++ b/test/expect/d.js
@@ -23,7 +23,7 @@
     }
   },
   "@weex-component/efd01076a5d363118b9fa68bbab98216": {
-    "data": "function data() {\n\t        return {\n\t            name: 'Weex'\n\t        };\n\t    }",
+    "data": "function data() {\n\t    return {\n\t        name: 'Weex'\n\t    };\n\t}",
     "template": {
       "type": "div",
       "style": {
diff --git a/test/expect/e.js b/test/expect/e.js
index 26c91cb..12a0ae9 100644
--- a/test/expect/e.js
+++ b/test/expect/e.js
@@ -46,7 +46,7 @@
     }
   },
   "@weex-component/3f7bb5c2b95329dedd5cb4556f4df361": {
-    "data": "function data() {\n\t        return {\n\t            hi: 'Hello',\n\t            name: 'Weex'\n\t        };\n\t    }",
+    "data": "function data() {\n\t    return {\n\t        hi: 'Hello',\n\t        name: 'Weex'\n\t    };\n\t}",
     "template": {
       "type": "div",
       "style": {
diff --git a/test/expect/f.js b/test/expect/f.js
index f2ce0b4..b662d15 100644
--- a/test/expect/f.js
+++ b/test/expect/f.js
@@ -23,7 +23,7 @@
     }
   },
   "@weex-component/name": {
-    "data": "function data() {\n\t        return {\n\t            name: ''\n\t        };\n\t    }",
+    "data": "function data() {\n\t        console.log('Name Component Comment');\n\t        return {\n\t            name: ''\n\t        };\n\t    }",
     "template": {
       "type": "div",
       "children": [
@@ -46,7 +46,7 @@
     }
   },
   "@weex-component/ce75098d1d76e52a00b0d2b2613d990c": {
-    "data": "function data() {\n\t        return {\n\t            hi: 'Hello',\n\t            name: 'Weex'\n\t        };\n\t    }",
+    "data": "function data() {\n\t    return {\n\t        hi: 'Hello',\n\t        name: 'Weex'\n\t    };\n\t}",
     "template": {
       "type": "div",
       "classList": [
diff --git a/test/expect/g.js b/test/expect/g.js
index 982053d..5446409 100644
--- a/test/expect/g.js
+++ b/test/expect/g.js
@@ -1,6 +1,6 @@
 {
   "@weex-component/name1": {
-    "data": "function data() {\n\t        return {\n\t            name: ''\n\t        };\n\t    }",
+    "data": "function data() {\n\t        console.log('Name Component Comment');\n\t        return {\n\t            name: ''\n\t        };\n\t    }",
     "template": {
       "type": "div",
       "children": [
diff --git a/test/expect/h.js b/test/expect/h.js
index 7855392..bb0753b 100644
--- a/test/expect/h.js
+++ b/test/expect/h.js
@@ -23,7 +23,7 @@
     }
   },
   "@weex-component/name": {
-    "data": "function data() {\n\t        return {\n\t            name: ''\n\t        };\n\t    }",
+    "data": "function data() {\n\t        console.log('Name Component Comment');\n\t        return {\n\t            name: ''\n\t        };\n\t    }",
     "template": {
       "type": "div",
       "children": [
diff --git a/test/expect/j.js b/test/expect/j.js
index 916aa22..1a1152a 100644
--- a/test/expect/j.js
+++ b/test/expect/j.js
@@ -1,6 +1,6 @@
 {
   "@weex-component/75ade3685ace094b4dd3622093f2ac3e": {
-    "ready": "function ready() {\n\t        modal.toast({ 'message': 'ready' });\n\t    }",
+    "ready": "function ready() {\n\t        _modal2.default.toast({ 'message': 'ready' });\n\t    }",
     "data": "function data() {\n\t        return {\n\t            hi: 'Hello',\n\t            name: 'Weex'\n\t        };\n\t    }",
     "template": {
       "type": "div",
diff --git a/test/expect/k.js b/test/expect/k.js
index a906a3e..7401d48 100644
--- a/test/expect/k.js
+++ b/test/expect/k.js
@@ -1,7 +1,7 @@
 {
   "@weex-component/6461408a6e72015716c3e75aedb3f4f8": {
-    "ready": "function ready() {\n\t        _modal2.default.toast({ 'message': 'ready' });\n\t    }",
-    "data": "function data() {\n\t        return {\n\t            hi: 'Hello',\n\t            name: 'Weex'\n\t        };\n\t    }",
+    "ready": "function () {\n\t    return modal.toast({\n\t      'message': 'ready'\n\t    });\n\t  }",
+    "data": "function () {\n\t    return {\n\t      hi: 'Hello',\n\t      name: 'Weex'\n\t    };\n\t  }",
     "template": {
       "type": "div",
       "classList": [
diff --git a/test/expect/l.js b/test/expect/l.js
index c835b11..48739e0 100644
--- a/test/expect/l.js
+++ b/test/expect/l.js
@@ -1,7 +1,7 @@
 {
   "@weex-component/b88790ebbe39cc44c23e81e6ef2a07e2": {
-    "ready": "function ready() {\n\t        modal.toast({ message: this.name });\n\t    }",
-    "data": "function data() {\n\t        return {\n\t            name: getName()\n\t        };\n\t    }",
+    "ready": "function ready() {\n\t    _modal2.default.toast({ message: this.name });\n\t}",
+    "data": "function data() {\n\t    return {\n\t        name: (0, _getName2.default)()\n\t    };\n\t}",
     "template": {
       "type": "div",
       "children": [
diff --git a/test/expect/m.js b/test/expect/m.js
index b4d7953..8522912 100644
--- a/test/expect/m.js
+++ b/test/expect/m.js
@@ -1,7 +1,7 @@
 {
   "@weex-component/toast": {},
   "@weex-component/27bd9f030aa3c2c01f3168b3f623e61e": {
-    "ready": "function ready() {\n\t        toast(this.name);\n\t    }",
+    "ready": "function ready() {\n\t        (0, _toast2.default)(this.name);\n\t    }",
     "data": "function data() {\n\t        return {\n\t            name: 'Weex'\n\t        };\n\t    }",
     "template": {
       "type": "div",
diff --git a/test/expect/n.js b/test/expect/n.js
new file mode 100644
index 0000000..af965a5
--- /dev/null
+++ b/test/expect/n.js
@@ -0,0 +1,76 @@
+{
+  "@weex-component/hi": {
+    "data": "function data() {\n\t        console.log('Hi Component Comment');\n\t        return {\n\t            hi: ''\n\t        };\n\t    }",
+    "template": {
+      "type": "div",
+      "children": [
+        {
+          "type": "text",
+          "classList": [
+            "hi"
+          ],
+          "attr": {
+            "value": "function () {return this.hi}"
+          }
+        }
+      ]
+    },
+    "style": {
+      "hi": {
+        "fontSize": 26,
+        "color": "#008000"
+      }
+    }
+  },
+  "@weex-component/name": {
+    "data": "function data() {\n\t        console.log('Name Component Comment');\n\t        return {\n\t            name: ''\n\t        };\n\t    }",
+    "template": {
+      "type": "div",
+      "children": [
+        {
+          "type": "text",
+          "classList": [
+            "name"
+          ],
+          "attr": {
+            "value": "function () {return this.name}"
+          }
+        }
+      ]
+    },
+    "style": {
+      "name": {
+        "fontSize": 26,
+        "color": "#FF0000"
+      }
+    }
+  },
+  "@weex-component/57a447a57bba51ef8a7697040ca71e75": {
+    "data": "function data() {\n\t    console.log('N comment');\n\t    return {\n\t        hi: 'Hello',\n\t        name: 'Weex'\n\t    };\n\t}",
+    "template": {
+      "type": "div",
+      "classList": [
+        "wrap"
+      ],
+      "children": [
+        {
+          "type": "hi",
+          "attr": {
+            "hi": "function () {return this.hi}"
+          }
+        },
+        {
+          "type": "name",
+          "attr": {
+            "name": "function () {return this.name}"
+          }
+        }
+      ]
+    },
+    "style": {
+      "wrap": {
+        "flexDirection": "row"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/spec/c.we b/test/spec/c.we
index 62ac6f9..874fdb7 100644
--- a/test/spec/c.we
+++ b/test/spec/c.we
@@ -14,11 +14,9 @@
 
 
 <script>
-module.exports = {
-    data: function() {
-        return {
-            name: 'Weex'
-        }
+export function data() {
+    return {
+        name: 'Weex'
     }
 }
 </script>
\ No newline at end of file
diff --git a/test/spec/d.we b/test/spec/d.we
index 37208c2..8d6c8f1 100644
--- a/test/spec/d.we
+++ b/test/spec/d.we
@@ -38,11 +38,9 @@
 
 
 <script>
-module.exports = {
-    data: function() {
-        return {
-            name: 'Weex'
-        }
+export function data() {
+    return {
+        name: 'Weex'
     }
 }
 </script>
\ No newline at end of file
diff --git a/test/spec/e.we b/test/spec/e.we
index 06d79d0..8e287cc 100644
--- a/test/spec/e.we
+++ b/test/spec/e.we
@@ -52,12 +52,10 @@
 </template>
 
 <script>
-module.exports = {
-    data: function() {
-        return {
-            hi: 'Hello',
-            name: 'Weex'
-        }
+export function data() {
+    return {
+        hi: 'Hello',
+        name: 'Weex'
     }
 }
 </script>
\ No newline at end of file
diff --git a/test/spec/f.js b/test/spec/f.js
index f8879f6..65d0da9 100644
--- a/test/spec/f.js
+++ b/test/spec/f.js
@@ -1,8 +1,6 @@
-module.exports = {
-    data: function() {
-        return {
-            hi: 'Hello',
-            name: 'Weex'
-        }
+export function data() {
+    return {
+        hi: 'Hello',
+        name: 'Weex'
     }
 }
\ No newline at end of file
diff --git a/test/spec/g.we b/test/spec/g.we
index 84fec79..f4c462e 100644
--- a/test/spec/g.we
+++ b/test/spec/g.we
@@ -14,10 +14,10 @@
 </style>
 
 <script>
-require('./hi.we?name=hi1')
+import './hi.we?name=hi1'
 
-module.exports = {
-    data: function() {
+export default {
+    data() {
         return {
             hi: 'Hello',
             name: 'Weex'
diff --git a/test/spec/getName.js b/test/spec/getName.js
index 10878a0..8ef944c 100644
--- a/test/spec/getName.js
+++ b/test/spec/getName.js
@@ -1,3 +1 @@
-module.exports = function() {
-    return 'Weex'
-}
\ No newline at end of file
+export default () => 'Weex'
\ No newline at end of file
diff --git a/test/spec/h.we b/test/spec/h.we
index f8faf4b..45ef9fa 100644
--- a/test/spec/h.we
+++ b/test/spec/h.we
@@ -12,8 +12,8 @@
 </style>
 
 <script>
-module.exports = {
-    data: function() {
+export default {
+    data() {
         return {
             hi: 'Hello',
             name: 'Weex'
diff --git a/test/spec/hi.we b/test/spec/hi.we
index 42ce783..88dbef1 100644
--- a/test/spec/hi.we
+++ b/test/spec/hi.we
@@ -10,8 +10,8 @@
 </style>
 
 <script>
-module.exports = {
-    data: function() {
+export default {
+    data() {
         return {
             hi: ''
         }
diff --git a/test/spec/j.we b/test/spec/j.we
index 8d2e8af..75d7cf9 100644
--- a/test/spec/j.we
+++ b/test/spec/j.we
@@ -12,13 +12,13 @@
 </style>
 
 <script>
-var modal = require('@weex-module/modal')
+import modal from '@weex-module/modal'
 
-module.exports = {
-    ready: function() {
+export default {
+    ready() {
         modal.toast({'message': 'ready'})
     },
-    data: function() {
+    data() {
         return {
             hi: 'Hello',
             name: 'Weex'
diff --git a/test/spec/k.we b/test/spec/k.we
index de0c0ba..88b1443 100644
--- a/test/spec/k.we
+++ b/test/spec/k.we
@@ -28,19 +28,16 @@
     }
 </style>
 
-<script>
-import modal from '@weex-module/modal'
+<script lang="coffee">
+modal = require '@weex-module/modal'
 
-export default {
-    ready() {
+module.exports = 
+    ready: () -> 
         modal.toast({'message': 'ready'})
-    },
 
-    data() {
+    data: () ->
         return {
             hi: 'Hello',
             name: 'Weex'
         }
-    }
-}
 </script>
\ No newline at end of file
diff --git a/test/spec/l.we b/test/spec/l.we
index a47501e..95d14cc 100644
--- a/test/spec/l.we
+++ b/test/spec/l.we
@@ -14,18 +14,16 @@
 
 
 <script>
-var modal = require('@weex-module/modal')
-var getName = require('./getName.js')
+import modal from '@weex-module/modal'
+import getName from './getName.js'
 
+export function ready() {
+    modal.toast({message: this.name})
+}
 
-module.exports = {
-    ready: function() {
-        modal.toast({message: this.name})
-    },
-    data: function() {
-        return {
-            name: getName()
-        }
+export function data() {
+    return {
+        name: getName()
     }
 }
 </script>
\ No newline at end of file
diff --git a/test/spec/m.we b/test/spec/m.we
index b7c5ddc..7f25542 100644
--- a/test/spec/m.we
+++ b/test/spec/m.we
@@ -14,13 +14,13 @@
 
 
 <script>
-var toast = require('./toast.js')
+import toast from './toast.js'
 
-module.exports = {
-    ready: function() {
+export default {
+    ready() {
         toast(this.name)
     },
-    data: function() {
+    data() {
         return {
             name: 'Weex'
         }
diff --git a/test/spec/n.we b/test/spec/n.we
new file mode 100644
index 0000000..b0b7292
--- /dev/null
+++ b/test/spec/n.we
@@ -0,0 +1,37 @@
+<element name="hi">
+<template>
+    <div><text class="hi">{{hi}}</text></div>
+</template>
+
+<style>
+.hi {
+    font-size: 26px;
+    color: green;
+}
+</style>
+
+<script>
+export default {
+    data() {
+        console.log('Hi Component Comment')
+        return {
+            hi: ''
+        }
+    }
+}
+</script>
+</element>
+
+<element name="name" src="./name.we"></element>
+
+<template src="./f.html"></template>
+<style src="./f.css"></style>
+<script>
+export function data() {
+    console.log('N comment')
+    return {
+        hi: 'Hello',
+        name: 'Weex'
+    }
+}
+</script>
\ No newline at end of file
diff --git a/test/spec/name.js b/test/spec/name.js
index d2074a3..934290b 100644
--- a/test/spec/name.js
+++ b/test/spec/name.js
@@ -1,5 +1,6 @@
 module.exports = {
     data: function() {
+        console.log('Name Component Comment')
         return {
             name: ''
         }
diff --git a/test/test.js b/test/test.js
index 5f08344..f9aaac8 100644
--- a/test/test.js
+++ b/test/test.js
@@ -43,8 +43,8 @@
     const fn = new Function('__weex_define__', '__weex_bootstrap__', actualStr);
     fn(__weex_define__, __weex_bootstrap__);
 
-    // const filepath = path.resolve(__dirname, 'expect', `${name}.js`);
-    // fs.writeFileSync(filepath, stringifyActual(components), 'utf-8');
+    const filepath = path.resolve(__dirname, 'expect', `${name}.js`);
+    fs.writeFileSync(filepath, stringifyActual(components), 'utf-8');
 
     const expectJSON = getExpectJSON(name);
     expect(JSON.parse(stringifyActual(components))).eql(expectJSON);
@@ -131,4 +131,8 @@
     expect(requireStub.callCount).eql(1);
     expect(requireStub.firstCall.args).eql(['@weex-module/modal']);
   });
+
+  it('template with sourcemap', () => {
+    expectActual('n');
+  })
 })
diff --git a/test/webpack.config.js b/test/webpack.config.js
index a72fd6d..bfd8e4a 100644
--- a/test/webpack.config.js
+++ b/test/webpack.config.js
@@ -3,7 +3,7 @@
 
 var entry = {}
 var start = 'a'
-var end = 'm'
+var end = 'n'
 var count = end.charCodeAt(0) - start.charCodeAt(0)
 
 new Array(count + 1).fill(0)
@@ -23,9 +23,14 @@
       {
         test: /\.we(\?[^?]+)?$/,
         loaders: ['lib/loader.js']
+      },
+      {
+        test: /\.js/,
+        loaders: ['babel?presets[]=es2015']
       }
     ]
   },
+  devtool: 'source-map',
   resolveLoader: {
     modulesDirectories: ['./', './node_modules']
   },
@@ -37,7 +42,8 @@
   weex: {
     lang: {
       cssnext: ['postcss'],
-      jade: ['jade-html']
+      jade: ['jade-html'],
+      coffee: ['coffee']
     }
   }
 }