├── .babelrc ├── .editorconfig ├── .eslintrc ├── .gitignore ├── .npmignore ├── README.md ├── dist ├── vue-base64-file-upload.js └── vue-base64-file-upload.min.js ├── example.gif ├── example ├── bundle.js ├── index.html └── index.js ├── index.js ├── package.json ├── src └── index.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "stage-0" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | 4 | "extends": "eslint:recommended", 5 | 6 | env: { 7 | "browser": true, 8 | "mocha": true, 9 | "node": true, 10 | "es6": true 11 | }, 12 | 13 | "parserOptions": { 14 | "ecmaFeatures": { 15 | "modules": true 16 | } 17 | }, 18 | 19 | rules: { 20 | "strict": 0, 21 | "quotes": [2, "single"], 22 | "indent": [2, 2, {SwitchCase: 1}], 23 | "semi": [2, "always"], 24 | "no-underscore-dangle": 0, 25 | "no-unused-vars": 1, 26 | "no-unused-expressions": 0, 27 | "new-cap": 0, 28 | "no-extra-boolean-cast": 0, 29 | "yoda": 0, 30 | "no-empty": 0, 31 | "no-use-before-define": 0, 32 | "camelcase": 0, 33 | "object-curly-spacing": 0, 34 | "array-bracket-spacing": 0, 35 | "max-len": 0, 36 | "comma-dangle": [2, "never"], 37 | "space-before-function-paren": 0, 38 | "arrow-body-style": 0, 39 | "no-param-reassign": 0, 40 | "consistent-return": 0, 41 | "no-console": 0, 42 | "no-void": 0, 43 | "func-names": 0, 44 | "no-nested-ternary": 0, 45 | "quote-props": 0, 46 | "space-infix-ops": 0, 47 | "prefer-const": 0, 48 | "prefer-template": 0, 49 | "spaced-comment": 0, 50 | "prefer-rest-params": 0, 51 | "no-unreachable": 0 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | *.log 4 | *.map 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | example 2 | src 3 | .editorconfig 4 | .babelrc 5 | .eslintrc 6 | webpack.config.js 7 | example.gif 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-base64-file-upload 2 | 3 | > Upload files as base64 data-uris (URL representing the file's data as a base64 encoded string). 4 | 5 | 6 | 7 | ## Install 8 | 9 | ```bash 10 | npm i vue-base64-file-upload --save 11 | ``` 12 | 13 | ## Example 14 | 15 | ```js 16 | import Vue from 'vue'; 17 | import VueBase64FileUpload from 'vue-base64-file-upload'; 18 | 19 | const app = new Vue({ 20 | components: { 21 | VueBase64FileUpload 22 | }, 23 | 24 | data() { 25 | return { 26 | customImageMaxSize: 3 // megabytes 27 | }; 28 | }, 29 | 30 | methods: { 31 | onFile(file) { 32 | console.log(file); // file object 33 | }, 34 | 35 | onLoad(dataUri) { 36 | console.log(dataUri); // data-uri string 37 | }, 38 | 39 | onSizeExceeded(size) { 40 | alert(`Image ${size}Mb size exceeds limits of ${this.customImageMaxSize}Mb!`); 41 | } 42 | }, 43 | 44 | template: ` 45 |
46 |

Upload file

47 | 56 |
57 | ` 58 | }); 59 | 60 | app.$mount('#app'); 61 | ``` 62 | 63 | ## API 64 | 65 | ## Props 66 | 67 | - `image-class` - pass additional classes for preview `img` tag 68 | - `input-class` - pass additional classes for text `input` tag 69 | - `accept` - mimetypes allowed for upload, _defaults to `'image/png,image/gif,image/jpeg'`_ 70 | - `max-size` - number of megabytes allowed for upload, _defaults to `10`_ 71 | - `disable-preview` - not show preview image, _defaults to `false`_ 72 | - `default-preview` - pass url or data-uri to be displayed as default image 73 | - `file-name` - pass custom filename to be displayed in text `input` tag 74 | - `placeholder` - pass placeholder text for text `input` tag 75 | 76 | ## Events 77 | 78 | - `file` - fired when file object is ready 79 | - `load` - fired when data-uri is ready 80 | - `size-exceeded` - fired if uploaded image size exceeds limits 81 | 82 | ## References 83 | 84 | - [FileReader API](https://developer.mozilla.org/en-US/docs/Web/API/FileReader) 85 | - [`readAsDataURL`](https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL) 86 | 87 | --- 88 | 89 | **MIT Licensed** 90 | -------------------------------------------------------------------------------- /dist/vue-base64-file-upload.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(); 4 | else if(typeof define === 'function' && define.amd) 5 | define("VueBase64FileUpload", [], factory); 6 | else if(typeof exports === 'object') 7 | exports["VueBase64FileUpload"] = factory(); 8 | else 9 | root["VueBase64FileUpload"] = factory(); 10 | })(this, function() { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) 20 | /******/ return installedModules[moduleId].exports; 21 | 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ exports: {}, 25 | /******/ id: moduleId, 26 | /******/ loaded: false 27 | /******/ }; 28 | 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | 32 | /******/ // Flag the module as loaded 33 | /******/ module.loaded = true; 34 | 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | 39 | 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | 46 | /******/ // __webpack_public_path__ 47 | /******/ __webpack_require__.p = ""; 48 | 49 | /******/ // Load entry module and return exports 50 | /******/ return __webpack_require__(0); 51 | /******/ }) 52 | /************************************************************************/ 53 | /******/ ([ 54 | /* 0 */ 55 | /***/ function(module, exports) { 56 | 57 | 'use strict'; 58 | 59 | Object.defineProperty(exports, "__esModule", { 60 | value: true 61 | }); 62 | if (!window.FileReader) { 63 | console.error('Your browser does not support FileReader API!'); 64 | } 65 | 66 | exports.default = { 67 | name: 'vue-base64-file-upload', 68 | 69 | props: { 70 | imageClass: { 71 | type: String, 72 | default: '' 73 | }, 74 | inputClass: { 75 | type: String, 76 | default: '' 77 | }, 78 | accept: { 79 | type: String, 80 | default: 'image/png,image/gif,image/jpeg' 81 | }, 82 | maxSize: { 83 | type: Number, 84 | default: 10 // megabytes 85 | }, 86 | disablePreview: { 87 | type: Boolean, 88 | default: false 89 | }, 90 | fileName: { 91 | type: String, 92 | default: '' 93 | }, 94 | placeholder: { 95 | type: String, 96 | default: 'Click here to upload image' 97 | }, 98 | defaultPreview: { 99 | type: String, 100 | default: '' 101 | } 102 | }, 103 | 104 | data: function data() { 105 | return { 106 | file: null, 107 | preview: null, 108 | visiblePreview: false 109 | }; 110 | }, 111 | 112 | 113 | computed: { 114 | wrapperStyles: function wrapperStyles() { 115 | return { 116 | 'position': 'relative', 117 | 'width': '100%' 118 | }; 119 | }, 120 | fileInputStyles: function fileInputStyles() { 121 | return { 122 | 'width': '100%', 123 | 'position': 'absolute', 124 | 'top': 0, 125 | 'left': 0, 126 | 'right': 0, 127 | 'bottom': 0, 128 | 'opacity': 0, 129 | 'overflow': 'hidden', 130 | 'outline': 'none', 131 | 'cursor': 'pointer' 132 | }; 133 | }, 134 | textInputStyles: function textInputStyles() { 135 | return { 136 | 'width': '100%', 137 | 'cursor': 'pointer' 138 | }; 139 | }, 140 | previewImage: function previewImage() { 141 | return this.preview || this.defaultPreview; 142 | } 143 | }, 144 | 145 | methods: { 146 | onChange: function onChange(e) { 147 | var _this = this; 148 | 149 | var files = e.target.files || e.dataTransfer.files; 150 | 151 | if (!files.length) { 152 | return; 153 | } 154 | 155 | var file = files[0]; 156 | var size = file.size && file.size / Math.pow(1000, 2); 157 | 158 | // check file max size 159 | if (size > this.maxSize) { 160 | this.$emit('size-exceeded', size); 161 | return; 162 | } 163 | 164 | // update file 165 | this.file = file; 166 | this.$emit('file', file); 167 | 168 | var reader = new FileReader(); 169 | 170 | reader.onload = function (e) { 171 | var dataURI = e.target.result; 172 | 173 | if (dataURI) { 174 | _this.$emit('load', dataURI); 175 | 176 | _this.preview = dataURI; 177 | } 178 | }; 179 | 180 | // read blob url from file data 181 | reader.readAsDataURL(file); 182 | } 183 | }, 184 | 185 | template: '\n
\n \n
\n \n \n
\n
\n ' 186 | }; 187 | 188 | /***/ } 189 | /******/ ]) 190 | }); 191 | ; -------------------------------------------------------------------------------- /dist/vue-base64-file-upload.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("VueBase64FileUpload",[],t):"object"==typeof exports?exports.VueBase64FileUpload=t():e.VueBase64FileUpload=t()}(this,function(){return function(e){function t(n){if(i[n])return i[n].exports;var a=i[n]={exports:{},id:n,loaded:!1};return e[n].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var i={};return t.m=e,t.c=i,t.p="",t(0)}([function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),window.FileReader||console.error("Your browser does not support FileReader API!"),t.default={name:"vue-base64-file-upload",props:{imageClass:{type:String,default:""},inputClass:{type:String,default:""},accept:{type:String,default:"image/png,image/gif,image/jpeg"},maxSize:{type:Number,default:10},disablePreview:{type:Boolean,default:!1},fileName:{type:String,default:""},placeholder:{type:String,default:"Click here to upload image"},defaultPreview:{type:String,default:""}},data:function(){return{file:null,preview:null,visiblePreview:!1}},computed:{wrapperStyles:function(){return{position:"relative",width:"100%"}},fileInputStyles:function(){return{width:"100%",position:"absolute",top:0,left:0,right:0,bottom:0,opacity:0,overflow:"hidden",outline:"none",cursor:"pointer"}},textInputStyles:function(){return{width:"100%",cursor:"pointer"}},previewImage:function(){return this.preview||this.defaultPreview}},methods:{onChange:function(e){var t=this,i=e.target.files||e.dataTransfer.files;if(i.length){var n=i[0],a=n.size&&n.size/Math.pow(1e3,2);if(a>this.maxSize)return void this.$emit("size-exceeded",a);this.file=n,this.$emit("file",n);var r=new FileReader;r.onload=function(e){var i=e.target.result;i&&(t.$emit("load",i),t.preview=i)},r.readAsDataURL(n)}}},template:'\n
\n \n
\n \n \n
\n
\n '}}])}); -------------------------------------------------------------------------------- /example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dhhb/vue-base64-file-upload/e2d57dcecf80181e26d2c4b57a7508f207895cbc/example.gif -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vue Base64 File Upload Example 7 | 38 | 39 | 40 | 41 |
42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue/dist/vue'; 2 | import VueBase64FileUpload from '../dist/vue-base64-file-upload'; 3 | 4 | const app = new Vue({ 5 | components: { 6 | VueBase64FileUpload 7 | }, 8 | 9 | data() { 10 | return { 11 | customImageMaxSize: 3 // megabytes 12 | }; 13 | }, 14 | 15 | methods: { 16 | onFile(file) { 17 | console.log(file); 18 | }, 19 | 20 | onLoad(dataUri) { 21 | console.log('data-uri is ready!'); 22 | }, 23 | 24 | onSizeExceeded(size) { 25 | console.log(size); 26 | alert(`Image size exceeds limits of ${this.customImageMaxSize}Mb!`); 27 | } 28 | }, 29 | 30 | template: ` 31 |
32 |

Vue Base64 File Upload

33 |
34 | 43 |
44 |
45 | 51 |
52 |
53 | ` 54 | }); 55 | 56 | app.$mount('#app'); 57 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | if (!window.FileReader) { 7 | console.error('Your browser does not support FileReader API!'); 8 | } 9 | 10 | exports.default = { 11 | name: 'vue-base64-file-upload', 12 | 13 | props: { 14 | imageClass: { 15 | type: String, 16 | default: '' 17 | }, 18 | inputClass: { 19 | type: String, 20 | default: '' 21 | }, 22 | accept: { 23 | type: String, 24 | default: 'image/png,image/gif,image/jpeg' 25 | }, 26 | maxSize: { 27 | type: Number, 28 | default: 10 // megabytes 29 | }, 30 | disablePreview: { 31 | type: Boolean, 32 | default: false 33 | }, 34 | fileName: { 35 | type: String, 36 | default: '' 37 | }, 38 | placeholder: { 39 | type: String, 40 | default: 'Click here to upload image' 41 | }, 42 | defaultPreview: { 43 | type: String, 44 | default: '' 45 | } 46 | }, 47 | 48 | data: function data() { 49 | return { 50 | file: null, 51 | preview: null, 52 | visiblePreview: false 53 | }; 54 | }, 55 | 56 | 57 | computed: { 58 | wrapperStyles: function wrapperStyles() { 59 | return { 60 | 'position': 'relative', 61 | 'width': '100%' 62 | }; 63 | }, 64 | fileInputStyles: function fileInputStyles() { 65 | return { 66 | 'width': '100%', 67 | 'position': 'absolute', 68 | 'top': 0, 69 | 'left': 0, 70 | 'right': 0, 71 | 'bottom': 0, 72 | 'opacity': 0, 73 | 'overflow': 'hidden', 74 | 'outline': 'none', 75 | 'cursor': 'pointer' 76 | }; 77 | }, 78 | textInputStyles: function textInputStyles() { 79 | return { 80 | 'width': '100%', 81 | 'cursor': 'pointer' 82 | }; 83 | }, 84 | previewImage: function previewImage() { 85 | return this.preview || this.defaultPreview; 86 | } 87 | }, 88 | 89 | methods: { 90 | onChange: function onChange(e) { 91 | var _this = this; 92 | 93 | var files = e.target.files || e.dataTransfer.files; 94 | 95 | if (!files.length) { 96 | return; 97 | } 98 | 99 | var file = files[0]; 100 | var size = file.size && file.size / Math.pow(1000, 2); 101 | 102 | // check file max size 103 | if (size > this.maxSize) { 104 | this.$emit('size-exceeded', size); 105 | return; 106 | } 107 | 108 | // update file 109 | this.file = file; 110 | this.$emit('file', file); 111 | 112 | var reader = new FileReader(); 113 | 114 | reader.onload = function (e) { 115 | var dataURI = e.target.result; 116 | 117 | if (dataURI) { 118 | _this.$emit('load', dataURI); 119 | 120 | _this.preview = dataURI; 121 | } 122 | }; 123 | 124 | // read blob url from file data 125 | reader.readAsDataURL(file); 126 | } 127 | }, 128 | 129 | template: '\n
\n \n
\n \n \n
\n
\n ' 130 | }; 131 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-base64-file-upload", 3 | "version": "1.0.4", 4 | "description": "Upload files as base64 data-uris", 5 | "main": "./index.js", 6 | "directories": { 7 | "example": "example" 8 | }, 9 | "scripts": { 10 | "build": "npm run build-babel && npm run build-dist-dev && npm run build-dist-prod", 11 | "build-dist-dev": "NODE_ENV=development webpack --config webpack.config --colors", 12 | "build-dist-prod": "NODE_ENV=production webpack --config webpack.config --progress --colors -p", 13 | "build-babel": "babel ./src/index.js --out-file ./index.js", 14 | "build-example": "browserify ./example/index.js -t [ babelify --presets [ es2015 stage-0 ] --plugins [ transform-object-assign ] ] -o ./example/bundle.js", 15 | "lint": "eslint ./src --fix", 16 | "test": "echo \"Comming soon ;)\" && exit 0" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/dhhb/vue-base64-file-upload.git" 21 | }, 22 | "keywords": [ 23 | "vue", 24 | "component", 25 | "upload", 26 | "input", 27 | "file", 28 | "base64", 29 | "data-uri", 30 | "blob" 31 | ], 32 | "author": "Dmitri Voronianski ", 33 | "license": "MIT", 34 | "bugs": { 35 | "url": "https://github.com/dhhb/vue-base64-file-upload/issues" 36 | }, 37 | "homepage": "https://github.com/dhhb/vue-base64-file-upload#readme", 38 | "devDependencies": { 39 | "babel-cli": "^6.23.0", 40 | "babel-core": "^6.23.1", 41 | "babel-eslint": "^7.1.1", 42 | "babel-loader": "^6.3.2", 43 | "babel-plugin-add-module-exports": "^0.2.1", 44 | "babel-plugin-transform-object-assign": "^6.22.0", 45 | "babel-preset-es2015": "^6.22.0", 46 | "babel-preset-stage-0": "^6.22.0", 47 | "babelify": "^7.3.0", 48 | "browserify": "^14.1.0", 49 | "eslint": "^3.15.0", 50 | "webpack": "^1.14.0", 51 | "webpack-umd-external": "^1.0.2" 52 | }, 53 | "dependencies": { 54 | "vue": "^2.1.10" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | if (!window.FileReader) { 2 | console.error('Your browser does not support FileReader API!'); 3 | } 4 | 5 | export default { 6 | name: 'vue-base64-file-upload', 7 | 8 | props: { 9 | imageClass: { 10 | type: String, 11 | default: '' 12 | }, 13 | inputClass: { 14 | type: String, 15 | default: '' 16 | }, 17 | accept: { 18 | type: String, 19 | default: 'image/png,image/gif,image/jpeg' 20 | }, 21 | maxSize: { 22 | type: Number, 23 | default: 10 // megabytes 24 | }, 25 | disablePreview: { 26 | type: Boolean, 27 | default: false 28 | }, 29 | fileName: { 30 | type: String, 31 | default: '' 32 | }, 33 | placeholder: { 34 | type: String, 35 | default: 'Click here to upload image' 36 | }, 37 | defaultPreview: { 38 | type: String, 39 | default: '' 40 | } 41 | }, 42 | 43 | data() { 44 | return { 45 | file: null, 46 | preview: null, 47 | visiblePreview: false 48 | }; 49 | }, 50 | 51 | computed: { 52 | wrapperStyles() { 53 | return { 54 | 'position': 'relative', 55 | 'width': '100%' 56 | }; 57 | }, 58 | 59 | fileInputStyles() { 60 | return { 61 | 'width': '100%', 62 | 'position': 'absolute', 63 | 'top': 0, 64 | 'left': 0, 65 | 'right': 0, 66 | 'bottom': 0, 67 | 'opacity': 0, 68 | 'overflow': 'hidden', 69 | 'outline': 'none', 70 | 'cursor': 'pointer' 71 | }; 72 | }, 73 | 74 | textInputStyles() { 75 | return { 76 | 'width': '100%', 77 | 'cursor': 'pointer' 78 | }; 79 | }, 80 | 81 | previewImage() { 82 | return this.preview || this.defaultPreview; 83 | } 84 | }, 85 | 86 | methods: { 87 | onChange(e) { 88 | const files = e.target.files || e.dataTransfer.files; 89 | 90 | if (!files.length) { 91 | return; 92 | } 93 | 94 | const file = files[0]; 95 | const size = file.size && (file.size / Math.pow(1000, 2)); 96 | 97 | // check file max size 98 | if (size > this.maxSize) { 99 | this.$emit('size-exceeded', size); 100 | return; 101 | } 102 | 103 | // update file 104 | this.file = file; 105 | this.$emit('file', file); 106 | 107 | const reader = new FileReader(); 108 | 109 | reader.onload = e => { 110 | const dataURI = e.target.result; 111 | 112 | if (dataURI) { 113 | this.$emit('load', dataURI); 114 | 115 | this.preview = dataURI; 116 | } 117 | }; 118 | 119 | // read blob url from file data 120 | reader.readAsDataURL(file); 121 | } 122 | }, 123 | 124 | template: ` 125 |
126 | 130 |
131 | 136 | 143 |
144 |
145 | ` 146 | }; 147 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const env = process.env.NODE_ENV || 'development'; 4 | 5 | const webpack = require('webpack'); 6 | const path = require('path'); 7 | const webpackUMDExternal = require('webpack-umd-external'); 8 | 9 | const pluginsList = []; 10 | const outputFileName = env === 'production' ? 11 | 'vue-base64-file-upload.min.js' : 12 | 'vue-base64-file-upload.js'; 13 | 14 | if (env === 'production') { 15 | pluginsList.push( 16 | new webpack.optimize.UglifyJsPlugin({ 17 | compress: { warnings: false }, 18 | output: { comments: false } 19 | }) 20 | ); 21 | } 22 | 23 | const config = { 24 | entry: path.join(__dirname, 'src/index.js'), 25 | 26 | output: { 27 | path: path.join(__dirname, 'dist'), 28 | filename: outputFileName, 29 | library: 'VueBase64FileUpload', 30 | libraryTarget: 'umd', 31 | umdNamedDefine: true 32 | }, 33 | 34 | externals: webpackUMDExternal({ 35 | 'vue': 'Vue' 36 | }), 37 | 38 | resolve: { 39 | extensions: ['', '.js'], 40 | alias: { 41 | vue: 'vue/dist/vue.js' 42 | } 43 | }, 44 | 45 | plugins: pluginsList, 46 | 47 | module: { 48 | loaders: [{ 49 | test: /\.jsx?$/, 50 | exclude: /node_modules/, 51 | loaders: ['babel'] 52 | }] 53 | } 54 | }; 55 | 56 | module.exports = config; 57 | --------------------------------------------------------------------------------