├── .babelrc ├── .gitignore ├── .npmignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── package.json ├── source └── index.js └── test ├── fixtures ├── already-transformed │ ├── actual.js │ └── expected.js ├── mapped-members │ ├── actual.js │ └── expected.js ├── members │ ├── actual.js │ └── expected.js ├── mixed │ ├── actual.js │ └── expected.js ├── namespace │ ├── actual.js │ └── expected.js ├── no-specifier │ ├── actual.js │ └── expected.js ├── only-default │ ├── actual.js │ └── expected.js └── unrelated │ ├── actual.js │ └── expected.js └── index.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"], 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | distribution/ 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | source/ 2 | test/ 3 | node_modules/ 4 | .babelrc 5 | .gitignore 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## [1.0.2](https://github.com/nerdlabs/babel-plugin-transform-react-router-optimize/compare/v1.0.1...v1.0.2) (2017-09-04) 3 | 4 | 5 | ### Bug Fixes 6 | 7 | * **transform:** Map non-default named exports to the correct file ([3574c8c](https://github.com/nerdlabs/babel-plugin-transform-react-router-optimize/commit/3574c8c)) 8 | 9 | 10 | 11 | 12 | ## [1.0.1](https://github.com/nerdlabs/babel-plugin-transform-react-router-optimize/compare/v1.0.0...v1.0.1) (2016-06-12) 13 | 14 | 15 | ### Bug Fixes 16 | 17 | * **transformation:** Leave imports which have no specifiers unchanged ([9a9738d](https://github.com/nerdlabs/babel-plugin-transform-react-router-optimize/commit/9a9738d)) 18 | 19 | 20 | 21 | 22 | # 1.0.0 (2016-06-11) 23 | 24 | 25 | ### Features 26 | 27 | * **transform:** transform react-router imports ([ffbe2f0](https://github.com/nerdlabs/babel-plugin-transform-react-router-optimize/commit/ffbe2f0)) 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 nerdlabs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) 2 | 3 | # babel-plugin-transform-react-router-optimize 4 | 5 | The [React Router][0] library exposes all methods on the top level import, but 6 | allows developers to use imports referencing files directly inside `/lib`, 7 | which can result in smaller bundle sizes as it doesn't import all of the 8 | Router's dependencies. 9 | 10 | See here for more information: [Minimizing Bundle Size][1]. 11 | 12 | This plugin can be added to your `.babelrc` file and automatically transform 13 | ES2015 imports to their size optimized counterpart. 14 | 15 | ## Example 16 | **In** 17 | ```javascript 18 | import { Route, IndexRoute } from 'react-router'; 19 | ``` 20 | 21 | **Out** 22 | ```javascript 23 | import Route from 'react-router/lib/Route'; 24 | import IndexRoute from 'react-router/lib/IndexRoute'; 25 | ``` 26 | 27 | ## Installation 28 | **Note** This plugin is built for babel 6 and does not work with babel 5. 29 | ```sh 30 | npm install --save-dev babel-plugin-transform-react-router-optimize 31 | ``` 32 | 33 | ## Usage 34 | 35 | ### Via `.babelrc` (recommended) 36 | **.babelrc** 37 | ```json 38 | { 39 | "plugins": ["transform-react-router-optimize"] 40 | } 41 | ``` 42 | 43 | ### Via CLI 44 | ```sh 45 | babel --plugins transform-react-router-optimize script.js 46 | ``` 47 | 48 | ### Via Node API 49 | ```javascript 50 | require('babel-core').transform('code', { 51 | plugins: ['transform-react-router-optimize'] 52 | }); 53 | ``` 54 | 55 | ## License 56 | 57 | MIT 58 | 59 | [0]: https://github.com/reactjs/react-router/ 60 | [1]: https://github.com/reactjs/react-router/blob/master/docs/guides/MinimizingBundleSize.md -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-transform-react-router-optimize", 3 | "description": "Babel plugin to optimize the bundle size of projects using react-router.", 4 | "version": "1.0.2", 5 | "license": "MIT", 6 | "main": "distribution/index.js", 7 | "scripts": { 8 | "clean": "rm -rf distribution", 9 | "build": "babel -d distribution source", 10 | "test": "node test/index.js", 11 | "prepublish": "npm run clean && npm run build && npm run test" 12 | }, 13 | "author": { 14 | "name": "Bjoern Brauer", 15 | "email": "zaubernerd@nerdlabs.it" 16 | }, 17 | "config": { 18 | "commitizen": { 19 | "path": "cz-conventional-changelog-lint" 20 | } 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/nerdlabs/babel-plugin-transform-react-router-optimize.git" 25 | }, 26 | "bugs": { 27 | "url": "https://github.com/nerdlabs/babel-plugin-transform-react-router-optimize/issues" 28 | }, 29 | "homepage": "https://github.com/nerdlabs/babel-plugin-transform-react-router-optimize#readme", 30 | "keywords": [ 31 | "babel-plugin", 32 | "react-router", 33 | "optimization", 34 | "minify", 35 | "react", 36 | "reactjs" 37 | ], 38 | "devDependencies": { 39 | "babel-cli": "^6.10.1", 40 | "babel-core": "^6.9.1", 41 | "babel-preset-es2015": "^6.9.0", 42 | "chalk": "^1.1.3", 43 | "cz-conventional-changelog-lint": "^0.1.3", 44 | "diff": "^2.2.3" 45 | }, 46 | "peerDependencies": { 47 | "react-router": ">=2.0.0" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /source/index.js: -------------------------------------------------------------------------------- 1 | export default function ({types: t}) { 2 | const namespace = 'react-router/lib' 3 | const importMap = { 4 | createRoutes: 'RouteUtils', 5 | locationShape: 'PropTypes', 6 | routerShape: 'PropTypes', 7 | formatPattern: 'PatternUtils' 8 | } 9 | 10 | const canReplace = ({ specifiers }) => { 11 | return specifiers.length > 0 && specifiers.every((specifier) => { 12 | return t.isImportSpecifier(specifier) 13 | && specifier.imported.name !== 'default'; 14 | }); 15 | }; 16 | 17 | const replace = (specifiers) => { 18 | return specifiers.map(({local, imported}) => { 19 | const mapped = importMap[imported.name] 20 | 21 | if (typeof mapped !== 'undefined') { 22 | return t.importDeclaration( 23 | [t.importSpecifier(local, imported)], 24 | t.stringLiteral(`${namespace}/${mapped}`) 25 | ); 26 | } 27 | 28 | return t.importDeclaration( 29 | [t.importDefaultSpecifier(local)], 30 | t.stringLiteral(`${namespace}/${imported.name}`) 31 | ); 32 | }); 33 | }; 34 | 35 | return { 36 | visitor: { 37 | ImportDeclaration(path) { 38 | if (path.node.source.value === 'react-router') { 39 | if (canReplace(path.node)) { 40 | path.replaceWithMultiple(replace(path.node.specifiers)); 41 | } 42 | } 43 | } 44 | } 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /test/fixtures/already-transformed/actual.js: -------------------------------------------------------------------------------- 1 | import member from 'react-router/lib/member'; 2 | -------------------------------------------------------------------------------- /test/fixtures/already-transformed/expected.js: -------------------------------------------------------------------------------- 1 | import member from 'react-router/lib/member'; 2 | -------------------------------------------------------------------------------- /test/fixtures/mapped-members/actual.js: -------------------------------------------------------------------------------- 1 | import { createRoutes, locationShape, routerShape } from 'react-router'; 2 | import { formatPattern as format } from 'react-router'; 3 | -------------------------------------------------------------------------------- /test/fixtures/mapped-members/expected.js: -------------------------------------------------------------------------------- 1 | import { createRoutes } from 'react-router/lib/RouteUtils'; 2 | import { locationShape } from 'react-router/lib/PropTypes'; 3 | import { routerShape } from 'react-router/lib/PropTypes'; 4 | import { formatPattern as format } from 'react-router/lib/PatternUtils'; 5 | -------------------------------------------------------------------------------- /test/fixtures/members/actual.js: -------------------------------------------------------------------------------- 1 | import { member } from 'react-router'; 2 | import { member as alias } from 'react-router'; 3 | import { member1 , member2 } from 'react-router'; 4 | import { member3 , member2 as alias2 } from 'react-router'; 5 | -------------------------------------------------------------------------------- /test/fixtures/members/expected.js: -------------------------------------------------------------------------------- 1 | import member from 'react-router/lib/member'; 2 | import alias from 'react-router/lib/member'; 3 | import member1 from 'react-router/lib/member1'; 4 | import member2 from 'react-router/lib/member2'; 5 | import member3 from 'react-router/lib/member3'; 6 | import alias2 from 'react-router/lib/member2'; 7 | -------------------------------------------------------------------------------- /test/fixtures/mixed/actual.js: -------------------------------------------------------------------------------- 1 | import Router, { member } from 'react-router'; 2 | -------------------------------------------------------------------------------- /test/fixtures/mixed/expected.js: -------------------------------------------------------------------------------- 1 | import Router, { member } from 'react-router'; 2 | -------------------------------------------------------------------------------- /test/fixtures/namespace/actual.js: -------------------------------------------------------------------------------- 1 | import * as Router from 'react-router'; 2 | -------------------------------------------------------------------------------- /test/fixtures/namespace/expected.js: -------------------------------------------------------------------------------- 1 | import * as Router from 'react-router'; 2 | -------------------------------------------------------------------------------- /test/fixtures/no-specifier/actual.js: -------------------------------------------------------------------------------- 1 | import 'react-router'; 2 | -------------------------------------------------------------------------------- /test/fixtures/no-specifier/expected.js: -------------------------------------------------------------------------------- 1 | import 'react-router'; 2 | -------------------------------------------------------------------------------- /test/fixtures/only-default/actual.js: -------------------------------------------------------------------------------- 1 | import Router from 'react-router'; 2 | -------------------------------------------------------------------------------- /test/fixtures/only-default/expected.js: -------------------------------------------------------------------------------- 1 | import Router from 'react-router'; 2 | -------------------------------------------------------------------------------- /test/fixtures/unrelated/actual.js: -------------------------------------------------------------------------------- 1 | import { A, B } from 'react'; 2 | -------------------------------------------------------------------------------- /test/fixtures/unrelated/expected.js: -------------------------------------------------------------------------------- 1 | import { A, B } from 'react'; 2 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const babel = require('babel-core'); 3 | const chalk = require('chalk'); 4 | const diff = require('diff'); 5 | const fs = require('fs'); 6 | const path = require('path'); 7 | 8 | const pluginPath = require.resolve('../distribution/index.js'); 9 | 10 | function runTests() { 11 | const testsPath = __dirname + '/fixtures/'; 12 | 13 | fs.readdirSync(testsPath) 14 | .map((item) => ({ path: path.join(testsPath, item), name: item })) 15 | .filter((item) => fs.statSync(item.path).isDirectory()) 16 | .forEach(runTest); 17 | } 18 | 19 | function runTest(dir) { 20 | const actual = babel.transformFileSync(dir.path + '/actual.js', { 21 | plugins: [pluginPath], 22 | babelrc: false 23 | }); 24 | 25 | const expected = fs.readFileSync(dir.path + '/expected.js', 'utf-8'); 26 | 27 | function normalizeLines(str) { 28 | return str.trimRight().replace(/\r\n/g, '\n'); 29 | } 30 | 31 | process.stdout.write(chalk.bgWhite.black(dir.name)); 32 | process.stdout.write('\n\n'); 33 | 34 | diff.diffLines(normalizeLines(expected), normalizeLines(actual.code)) 35 | .forEach((part) => { 36 | const colorize = part.added ? chalk.green : 37 | part.removed ? chalk.red : chalk.grey; 38 | 39 | process.stdout.write(colorize(part.value.trim()) + '\n'); 40 | }); 41 | 42 | assert.equal(normalizeLines(expected), normalizeLines(actual.code)); 43 | 44 | process.stdout.write('\n\n\n'); 45 | } 46 | 47 | 48 | runTests(); --------------------------------------------------------------------------------