with id "vis_tree"', () => {
 41 | 		const { wrapper } = setup()
 42 | 		expect(wrapper.type()).to.eql('div');
 43 | 		expect(wrapper.prop('id')).to.eql('vis_tree');
 44 | 	});
 45 | 
 46 | 	it('should have a Tooltip, a Mask, and a ButtonGroup', () => {
 47 | 		const { wrapper } = setup();
 48 | 		expect(wrapper.find(Tooltip)).to.have.length(1);
 49 | 		expect(wrapper.find(Mask)).to.have.length(1);
 50 | 		expect(wrapper.find('ButtonGroup')).to.have.length(1);
 51 | 	});
 52 | 
 53 | 	describe('child: Tooltip', () => {
 54 | 		it('should contain title, content, and footer', () => {
 55 | 			const { wrapper } = setup()
 56 | 			expect(wrapper.find('.app-tooltip-title')).to.have.length(1);
 57 | 			expect(wrapper.find('.app-tooltip-content')).to.have.length(1);
 58 | 			expect(wrapper.find('.app-tooltip-footer')).to.have.length(1);
 59 | 		});
 60 | 
 61 | 		it('should contain title, content, and footer', () => {
 62 | 			const { wrapper } = setup()
 63 | 			expect(wrapper.find('.app-tooltip-title')).to.have.length(1);
 64 | 			expect(wrapper.find('.app-tooltip-content')).to.have.length(1);
 65 | 			expect(wrapper.find('.app-tooltip-footer')).to.have.length(1);
 66 | 		});
 67 | 
 68 | 		it('should contain description if state.desc exists', () => {
 69 | 			const { wrapper } = setup()
 70 | 			expect(wrapper.find('.app-tooltip-desc')).to.have.length(0);
 71 | 
 72 | 			wrapper.setState({ "desc": "This is a description." });
 73 | 			expect(wrapper.find('.app-tooltip-desc')).to.have.length(1);
 74 | 		});
 75 | 
 76 | 		it('should contain "trash" icon if state.data exists', () => {
 77 | 			const { wrapper } = setup()
 78 | 			expect(wrapper.find('i[className="fas fa-pen app-action-icon"]')).to.have.length(1);
 79 | 			expect(wrapper.find('i[className="far fa-trash-alt app-action-icon"]')).to.have.length(0);
 80 | 
 81 | 			wrapper.setState({ "data": {} });
 82 | 			expect(wrapper.find('i[className="far fa-trash-alt app-action-icon"]')).to.have.length(1);
 83 | 		});
 84 | 
 85 | 		describe('child: "edit" icon', () => {
 86 | 			it('should call showEditModal() if clicked', () => {
 87 | 				const { props, wrapper } = setup()
 88 | 				wrapper.find('i[className="fas fa-pen app-action-icon"]').first().simulate('click');
 89 | 				expect(props.ComponentActions.showEditModal).calledOnce;
 90 | 			});
 91 | 		});
 92 | 
 93 | 		describe('child: "trash" icon', () => {
 94 | 			it('should call showConfirmModal() if clicked', () => {
 95 | 				const { wrapper } = setup();
 96 | 				wrapper.setState({ "data": {} });
 97 | 				wrapper.find('i[className="far fa-trash-alt app-action-icon"]').first().simulate('click');
 98 | 				expect(Tree.prototype.showConfirmModal).calledOnce;
 99 | 			});
100 | 		});
101 | 	});
102 | 
103 | 	describe('child: "Go back" Button', () => {
104 | 		it('should call goBack() if clicked', () => {
105 | 			const { wrapper } = setup()
106 | 			expect(wrapper.find('Button')).to.have.length(1);
107 | 
108 | 			wrapper.find('Button').first().simulate('click');
109 | 			expect(Tree.prototype.goBack).calledOnce;
110 | 		});
111 | 	});
112 | 
113 | 	describe('child: "Reset" Button', () => {
114 | 		it('should call reset() if clicked', () => {
115 | 			const { wrapper } = setup()
116 | 			wrapper.setState({ isTranslatedOrScaled: true });
117 | 			expect(wrapper.find('Button')).to.have.length(2);
118 | 
119 | 			wrapper.find('Button').last().simulate('click');
120 | 			expect(Tree.prototype.reset).calledOnce;
121 | 		});
122 | 	});
123 | });
124 | 
--------------------------------------------------------------------------------
/tests/src/reducers/counts.js:
--------------------------------------------------------------------------------
 1 | 'use strict';
 2 | import {INIT_COUNTS} from '../../../src/constants/InitStates'
 3 | import reducer from '../../../src/reducers/counts'
 4 | 
 5 | const counts = {
 6 | 	"p1": 24,
 7 | 	"p2": 1
 8 | };
 9 | 
10 | describe('(reducer) counts', function() {
11 | 	it('should return the initial state', () => {
12 | 		expect(
13 | 			reducer(undefined, {})
14 | 		).to.deep.equal(INIT_COUNTS)
15 | 	})
16 | 
17 | 	it('should handle LOAD_COUNTS', () => {
18 | 		expect(
19 | 			reducer(INIT_COUNTS, {
20 | 				type: 'LOAD_COUNTS',
21 | 				counts: counts
22 | 			})
23 | 		).to.deep.equal(counts)
24 | 	})
25 | 
26 | });
27 | 
--------------------------------------------------------------------------------
/tests/src/reducers/errors.js:
--------------------------------------------------------------------------------
 1 | 'use strict';
 2 | import {INIT_ERRORS} from '../../../src/constants/InitStates'
 3 | import reducer from '../../../src/reducers/errors'
 4 | 
 5 | const errors = [{
 6 | 	action: "c",
 7 | 	key: "ui.common.add",
 8 | 	match: ["p1"],
 9 | 	origin: null,
10 | 	params: {
11 | 		"en-US": "Add",
12 | 		"key": "ui.common.add",
13 | 		"project": ["p1", "p2"],
14 | 		"zh-TW": "新增"
15 | 	},
16 | 	type: "equals"
17 | }];
18 | 
19 | describe('(reducer) errors', function() {
20 | 	it('should return the initial state', () => {
21 | 		expect(
22 | 			reducer(undefined, {})
23 | 		).to.deep.equal(INIT_ERRORS);
24 | 	})
25 | 
26 | 	it('should handle ALERT_ERRORS', () => {
27 | 		const ary = reducer(INIT_ERRORS, {
28 | 			type: 'ALERT_ERRORS',
29 | 			errors
30 | 		});
31 | 
32 | 		expect(ary)
33 | 		.to.be.an('array')
34 | 		.to.have.length.above(0)
35 | 
36 | 		expect(ary[0])
37 | 		.to.have.property('action')
38 | 			.that.is.a('string')
39 | 			.to.be.oneOf(['c', 'u']);
40 | 
41 | 		expect(ary[0])
42 | 		.to.have.property('type')
43 | 			.that.is.an('string')
44 | 			.to.be.oneOf(["emptyfield", "equals", "belongsTo", "contains"]);
45 | 	})
46 | 
47 | 	it('should handle CLEAR_ERRORS', () => {
48 | 		expect(
49 | 			reducer(errors, {
50 | 				type: 'LOAD_MESSAGES',
51 | 				errors: []
52 | 			})
53 | 		)
54 | 		.to.be.an('array')
55 | 		.to.have.lengthOf(0);
56 | 
57 | 		expect(
58 | 			reducer(errors, {
59 | 				type: 'LOAD_COUNTS',
60 | 				errors: []
61 | 			})
62 | 		)
63 | 		.to.be.an('array')
64 | 		.to.have.lengthOf(0);
65 | 
66 | 		expect(
67 | 			reducer(errors, {
68 | 				type: 'SHOW_EDITMODAL',
69 | 				errors: []
70 | 			})
71 | 		)
72 | 		.to.be.an('array')
73 | 		.to.have.lengthOf(0);
74 | 
75 | 		expect(
76 | 			reducer(errors, {
77 | 				type: 'SHOW_IMPORTMODAL',
78 | 				errors: []
79 | 			})
80 | 		)
81 | 		.to.be.an('array')
82 | 		.to.have.lengthOf(0);
83 | 
84 | 		expect(
85 | 			reducer(errors, {
86 | 				type: 'CLEAR_ERRORS',
87 | 				errors: []
88 | 			})
89 | 		)
90 | 		.to.be.an('array')
91 | 		.to.have.lengthOf(0);
92 | 	})
93 | });
94 | 
--------------------------------------------------------------------------------
/tests/src/reducers/messages.js:
--------------------------------------------------------------------------------
 1 | 'use strict';
 2 | import {INIT_MESSAGES} from '../../../src/constants/InitStates'
 3 | import reducer from '../../../src/reducers/messages'
 4 | 
 5 | const lang = 'en-US'
 6 | const messages = {
 7 | 	'ui': {
 8 | 		'common': {
 9 | 			'add': 'Add'
10 | 		},
11 | 		'message': {
12 | 			'unread': 'You have {0} unread messages.'
13 | 		}
14 | 	}
15 | }
16 | 
17 | describe('(reducer) messages', function() {
18 | 	it('should return the initial state', () => {
19 | 		expect(
20 | 			reducer(undefined, {})
21 | 		).to.deep.equal(INIT_MESSAGES)
22 | 	})
23 | 
24 | 	it('should handle LOAD_MESSAGES', () => {
25 | 		expect(
26 | 			reducer(INIT_MESSAGES, {
27 | 				type: 'LOAD_MESSAGES',
28 | 				lang,
29 | 				messages
30 | 			})
31 | 		).to.deep.equal({
32 | 			lang: lang,
33 | 			messages: messages
34 | 		})
35 | 	})
36 | });
37 | 
--------------------------------------------------------------------------------
/tests/src/reducers/socket.js:
--------------------------------------------------------------------------------
 1 | 'use strict';
 2 | import {INIT_SOCKET} from '../../../src/constants/InitStates'
 3 | import reducer from '../../../src/reducers/socket'
 4 | 
 5 | const record = {
 6 | 	"_id": "56e6509a7267ce4016109550",
 7 | 	"en-US": "Add",
 8 | 	"key": "ui.common.add",
 9 | 	"project": ["p1", "p2"],
10 | 	"zh-TW": "新增"
11 | };
12 | 
13 | describe('(reducer) socket', function() {
14 | 	it('should return the initial state', () => {
15 | 		expect(
16 | 			reducer(undefined, {})
17 | 		).to.deep.equal(INIT_SOCKET)
18 | 	})
19 | 
20 | 	it('should handle ADD_TRANSLATION', () => {
21 | 		expect(
22 | 			reducer({
23 | 				emitdatachange: false
24 | 			}, {
25 | 				type: 'ADD_TRANSLATION'
26 | 			})
27 | 		).to.be.an('object')
28 | 		.to.have.property('emitdatachange')
29 | 			.that.is.true
30 | 	})
31 | 
32 | 	it('should handle REMOVE_TRANSLATION', () => {
33 | 		expect(
34 | 			reducer({
35 | 				emitdatachange: false
36 | 			}, {
37 | 				type: 'REMOVE_TRANSLATION'
38 | 			})
39 | 		).to.be.an('object')
40 | 		.to.have.property('emitdatachange')
41 | 			.that.is.true
42 | 	})
43 | 
44 | 	it('should handle UPDATE_TRANSLATION', () => {
45 | 		expect(
46 | 			reducer({
47 | 				emitdatachange: false
48 | 			}, {
49 | 				type: 'UPDATE_TRANSLATION'
50 | 			})
51 | 		).to.be.an('object')
52 | 		.to.have.property('emitdatachange')
53 | 			.that.is.true
54 | 	})
55 | 
56 | 	it('should handle IMPORT_LOCALE', () => {
57 | 		expect(
58 | 			reducer({
59 | 				emitdatachange: false
60 | 			}, {
61 | 				type: 'IMPORT_LOCALE'
62 | 			})
63 | 		).to.be.an('object')
64 | 		.to.have.property('emitdatachange')
65 | 			.that.is.true
66 | 	})
67 | 
68 | 	it('should handle END_DATACHANGE', () => {
69 | 		expect(
70 | 			reducer({
71 | 				emitdatachange: true
72 | 			}, {
73 | 				type: 'END_DATACHANGE'
74 | 			})
75 | 		).to.be.an('object')
76 | 		.to.have.property('emitdatachange')
77 | 			.that.is.false
78 | 	})
79 | });
80 | 
--------------------------------------------------------------------------------
/tests/src/reducers/translations.js:
--------------------------------------------------------------------------------
  1 | 'use strict';
  2 | import {INIT_TRANSLATIONS} from '../../../src/constants/InitStates'
  3 | import reducer from '../../../src/reducers/translations'
  4 | 
  5 | const translations = [{
  6 | 	"_id": "56d7037a0b70e760104ddf10",
  7 | 	"en-US": "Edit",
  8 | 	"key": "ui.common.edit",
  9 | 	"project": ["p1"],
 10 | 	"zh-TW": "編輯"
 11 | }, {
 12 | 	"_id": "56d7034f0b70e760104ddf0e",
 13 | 	"en-US": "Add",
 14 | 	"key": "ui.common.add",
 15 | 	"project": ["p1"],
 16 | 	"zh-TW": "新增"
 17 | }]
 18 | 
 19 | describe('(reducer) translations', function() {
 20 | 	it('should return the initial state', () => {
 21 | 		expect(
 22 | 			reducer(undefined, {})
 23 | 		).to.deep.equal(INIT_TRANSLATIONS)
 24 | 	})
 25 | 
 26 | 	it('should handle ADD_TRANSLATION', () => {
 27 | 		expect(
 28 | 			reducer(translations, {
 29 | 				type: 'ADD_TRANSLATION',
 30 | 				data: {
 31 | 					"_id": "56d7038b0b70e760104ddf11",
 32 | 					"en-US": "Delete",
 33 | 					"key": "ui.common.delete",
 34 | 					"project": ["p1"],
 35 | 					"zh-TW": "刪除"
 36 | 				}
 37 | 			})
 38 | 		).to.deep.equal([{
 39 | 			"_id": "56d7038b0b70e760104ddf11",
 40 | 			"en-US": "Delete",
 41 | 			"key": "ui.common.delete",
 42 | 			"project": ["p1"],
 43 | 			"zh-TW": "刪除"
 44 | 		}, {
 45 | 			"_id": "56d7037a0b70e760104ddf10",
 46 | 			"en-US": "Edit",
 47 | 			"key": "ui.common.edit",
 48 | 			"project": ["p1"],
 49 | 			"zh-TW": "編輯"
 50 | 		}, {
 51 | 			"_id": "56d7034f0b70e760104ddf0e",
 52 | 			"en-US": "Add",
 53 | 			"key": "ui.common.add",
 54 | 			"project": ["p1"],
 55 | 			"zh-TW": "新增"
 56 | 		}])
 57 | 	})
 58 | 
 59 | 	it('should handle LOAD_TRANSLATIONS', () => {
 60 | 		expect(
 61 | 			reducer(INIT_TRANSLATIONS, {
 62 | 				type: 'LOAD_TRANSLATIONS',
 63 | 				data: translations
 64 | 			})
 65 | 		).to.deep.equal(translations)
 66 | 	})
 67 | 
 68 | 	it('should handle IMPORT_LOCALE', () => {
 69 | 		expect(
 70 | 			reducer(INIT_TRANSLATIONS, {
 71 | 				type: 'IMPORT_LOCALE',
 72 | 				data: translations
 73 | 			})
 74 | 		).to.deep.equal(translations)
 75 | 	})
 76 | 
 77 | 	it('should handle MERGE_TRANSLATIONS', () => {
 78 | 		expect(
 79 | 			reducer(INIT_TRANSLATIONS, {
 80 | 				type: 'MERGE_TRANSLATIONS',
 81 | 				data: translations
 82 | 			})
 83 | 		).to.deep.equal(translations)
 84 | 	})
 85 | 
 86 | 	it('should handle REMOVE_TRANSLATION', () => {
 87 | 		expect(
 88 | 			reducer(translations, {
 89 | 				type: 'REMOVE_TRANSLATION',
 90 | 				id: "56d7037a0b70e760104ddf10"
 91 | 			})
 92 | 		).to.deep.equal([{
 93 | 			"_id": "56d7034f0b70e760104ddf0e",
 94 | 			"en-US": "Add",
 95 | 			"key": "ui.common.add",
 96 | 			"project": ["p1"],
 97 | 			"zh-TW": "新增"
 98 | 		}])
 99 | 	})
100 | 
101 | 	it('should handle UPDATE_TRANSLATION', () => {
102 | 		expect(
103 | 			reducer(translations, {
104 | 				type: 'UPDATE_TRANSLATION',
105 | 				data: {
106 | 					"_id": "56d7034f0b70e760104ddf0e",
107 | 					"en-US": "Add",
108 | 					"key": "ui.common.add",
109 | 					"project": ["p1", "p2"],
110 | 					"zh-TW": "增加"
111 | 				}
112 | 			})
113 | 		).to.deep.equal([{
114 | 			"_id": "56d7037a0b70e760104ddf10",
115 | 			"en-US": "Edit",
116 | 			"key": "ui.common.edit",
117 | 			"project": ["p1"],
118 | 			"zh-TW": "編輯"
119 | 		}, {
120 | 			"_id": "56d7034f0b70e760104ddf0e",
121 | 			"en-US": "Add",
122 | 			"key": "ui.common.add",
123 | 			"project": ["p1", "p2"],
124 | 			"zh-TW": "增加"
125 | 		}])
126 | 	})
127 | });
128 | 
--------------------------------------------------------------------------------
/tests/src/reducers/vis.js:
--------------------------------------------------------------------------------
 1 | 'use strict';
 2 | import {INIT_VIS} from '../../../src/constants/InitStates'
 3 | import reducer from '../../../src/reducers/vis'
 4 | 
 5 | const data = [{
 6 | 		"name": "ui",
 7 | 		"children": [{
 8 | 			"name": "common",
 9 | 			"children": [{
10 | 				"name": "delete",
11 | 				"translations": {
12 | 					"description": "",
13 | 					"key": "ui.common.delete",
14 | 					"en-US": "Delete",
15 | 					"zh-TW": "刪除",
16 | 					"_id": "577a868da4d9538f0f7e4ef6",
17 | 					"__v": 0,
18 | 					"project": ["p1", "p2"]
19 | 				}
20 | 			}, {
21 | 				"name": "add",
22 | 				"translations": {
23 | 					"description": "",
24 | 					"key": "ui.common.add",
25 | 					"en-US": "Add",
26 | 					"zh-TW": "新增",
27 | 					"_id": "577a8684a4d9538f0f7e4ef5",
28 | 					"__v": 0,
29 | 					"project": ["p1", "p2"]
30 | 				}
31 | 			}]
32 | 		}]
33 | 	}];
34 | 
35 | describe('(reducer) vis', function() {
36 | 	it('should return the initial state', () => {
37 | 		expect(
38 | 			reducer(undefined, {})
39 | 		).to.deep.equal(INIT_VIS)
40 | 	})
41 | 
42 | 	it('should handle LOAD_TREE_DATA', () => {
43 | 		expect(
44 | 			reducer({
45 | 				treedata: null
46 | 			}, {
47 | 				type: "LOAD_TREE_DATA",
48 | 				data: data
49 | 			})
50 | 		).to.deep.equal({
51 | 			treedata: data
52 | 		})
53 | 	})
54 | 
55 | });
56 | 
--------------------------------------------------------------------------------
/tests/testHelper.js:
--------------------------------------------------------------------------------
 1 | import ES6Promise from 'es6-promise'
 2 | ES6Promise.polyfill();
 3 | import 'isomorphic-fetch'
 4 | import jsdom from 'jsdom'
 5 | import React from 'react'
 6 | import chai from 'chai'
 7 | import sinon from 'sinon'
 8 | import sinonChai from 'sinon-chai'
 9 | import configureStore from 'redux-mock-store'
10 | import nock from 'nock'
11 | import thunk from 'redux-thunk'
12 | import config from '../ktm.config'
13 | import configUtil from '../src/configUtil'
14 | import Enzyme from 'enzyme'
15 | import Adapter from 'enzyme-adapter-react-16'
16 | 
17 | Enzyme.configure({ adapter: new Adapter() })
18 | 
19 | const { JSDOM } = jsdom
20 | const dom = new JSDOM('')
21 | // const win = doc.defaultView
22 | const expect = chai.use(sinonChai).expect
23 | const middlewares = [thunk];
24 | const mockStore = configureStore(middlewares)
25 | 
26 | global.document = dom.window.document
27 | global.window = dom.window
28 | global.navigator = window.navigator
29 | global.React = React
30 | global.sinon = sinon
31 | global.expect = expect
32 | global.configureStore = configureStore
33 | global.nock = nock
34 | global.config = config
35 | global.configUtil = configUtil
36 | global.mockStore = mockStore
37 | global.shallow = Enzyme.shallow
38 | global.mount = Enzyme.mount
39 | global.render = Enzyme.render
40 | 
--------------------------------------------------------------------------------
/views/index.ejs:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 
 4 | 		
Keys-Translations Manager
 5 | 		
 6 | 		
 7 | 		
 8 | 		
 9 | 		
10 | 		
11 | 		<%- css %>
12 | 
13 | 		
14 | 		
15 | 		
19 | 	
20 | 	
21 | 		
22 | 			<%- markup %>
23 | 		
24 | 		<%- initialState %>
25 | 		
26 | 		
27 | 		
28 | 		
29 | 		<%- vendor %>
30 | 		
31 | 	
32 | 
33 | 
--------------------------------------------------------------------------------
/webpack.config.dev.js:
--------------------------------------------------------------------------------
 1 | var path = require('path');
 2 | var webpack = require('webpack');
 3 | var dir = {
 4 | 	src: path.join(__dirname, 'src'),
 5 | 	dist: path.join(__dirname, 'public', 'js')
 6 | };
 7 | 
 8 | module.exports = {
 9 | 	mode: 'development',
10 | 	entry: [
11 | 		'eventsource-polyfill', // necessary for hot reloading with IE
12 | 		'webpack-hot-middleware/client',
13 | 		path.join(dir.src, 'client', 'index')
14 | 	],
15 | 	output: {
16 | 		path: dir.dist,
17 | 		filename: 'bundle.js',
18 | 		publicPath: '/public/js/'
19 | 	},
20 | 	plugins: [
21 | 		new webpack.HotModuleReplacementPlugin(),
22 | 		new webpack.NoEmitOnErrorsPlugin(),
23 | 		new webpack.DefinePlugin({
24 | 			'__DEV__': true
25 | 		})
26 | 	],
27 | 	devtool: 'cheap-module-eval-source-map',
28 | 	resolve: {
29 | 		extensions: ['.js', '.jsx'],
30 | 		alias: {
31 | 			'react-dom': '@hot-loader/react-dom'
32 | 		},
33 | 	},
34 | 	module: {
35 | 		rules: [{
36 | 			test: /\.jsx?$/,
37 | 			enforce: 'pre',
38 | 			exclude: path.resolve(__dirname, 'node_modules'),
39 | 			use: ['eslint-loader']
40 | 		}, {
41 | 			test: /\.jsx?$/,
42 | 			use: ['babel-loader'],
43 | 			include: dir.src
44 | 		}, {
45 | 			test: /\.(css|less)$/,
46 | 			use: [
47 | 				"style-loader",
48 | 				"css-loader",
49 | 				"less-loader"
50 | 			]
51 | 		}]
52 | 	}
53 | };
54 | 
--------------------------------------------------------------------------------
/webpack.config.prod.js:
--------------------------------------------------------------------------------
 1 | var path = require('path');
 2 | var webpack = require('webpack');
 3 | var CleanWebpackPlugin = require('clean-webpack-plugin').CleanWebpackPlugin;
 4 | var WebpackStrip = require('webpack-strip');
 5 | var dir = {
 6 | 	src: path.join(__dirname, 'src'),
 7 | 	dist: path.join(__dirname, 'public', 'js')
 8 | };
 9 | 
10 | var config = {
11 | 	mode: 'production',
12 | 	entry: {
13 | 		bundle: path.join(dir.src, 'client', 'index')
14 | 	},
15 | 	output: {
16 | 		path: dir.dist,
17 | 		filename: "[name].js",
18 | 		publicPath: '/public/js/'
19 | 	},
20 | 	optimization: {
21 | 		splitChunks: {
22 | 			cacheGroups: {
23 | 				vendor: {
24 | 					test: /[\\/]node_modules[\\/](react|react-dom|redux|redux-thunk|react-redux|react-router|react-router-dom|socket.io-client)[\\/]/,
25 | 					name: 'vendor',
26 | 					chunks: 'all',
27 | 				}
28 | 			}
29 | 		}
30 | 	},
31 | 	plugins: [
32 | 		new CleanWebpackPlugin({
33 | 			cleanOnceBeforeBuildPatterns: ['./public/js'],
34 | 		}),
35 | 		new webpack.DefinePlugin({
36 | 			'__DEV__': false
37 | 		})
38 | 	],
39 | 	devtool: 'source-map',
40 | 	resolve: {
41 | 		extensions: ['.js', '.jsx'],
42 | 	},
43 | 	module: {
44 | 		rules: [{
45 | 			test: /\.jsx?$/,
46 | 			exclude: path.resolve(__dirname, 'node_modules'),
47 | 			use: ['babel-loader', WebpackStrip.loader('console.log', 'console.warn')]
48 | 		}, {
49 | 			test: /\.(css|less)$/,
50 | 			use: [
51 | 				"style-loader",
52 | 				"css-loader",
53 | 				"less-loader"
54 | 			]
55 | 		}/*, {
56 | 			test: /\.(png|jpg|gif|ttf|woff|woff2)$/,
57 | 			loader: 'url?limit=25000'
58 | 		}*/]
59 | 	}
60 | };
61 | 
62 | module.exports = config;
63 | 
--------------------------------------------------------------------------------