├── example-react-ts-app ├── tests │ ├── __mocks__ │ │ ├── styleMock.js │ │ ├── fileMock.js │ │ └── shim.js │ └── App.test.tsx ├── .gitignore ├── src │ ├── assets │ │ ├── scss │ │ │ └── App.scss │ │ └── img │ │ │ └── react_logo.svg │ ├── index.tsx │ ├── index.html.ejs │ └── components │ │ └── App.tsx ├── express.js ├── .babelrc ├── configs │ ├── webpack │ │ ├── prod.js │ │ ├── dev.js │ │ └── common.js │ ├── jest.preprocessor.js │ └── jest.json ├── tsconfig.json ├── LICENSE ├── README.md ├── package.json └── tslint.json ├── requirements.txt ├── LICENSE ├── .gitignore ├── README.md └── unwebpack_sourcemap.py /example-react-ts-app/tests/__mocks__/styleMock.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /example-react-ts-app/tests/__mocks__/fileMock.js: -------------------------------------------------------------------------------- 1 | module.exports = 'test-file-stub'; 2 | -------------------------------------------------------------------------------- /example-react-ts-app/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | dist/ 3 | node_modules/ 4 | src/**/*.jsx 5 | tests/__coverage__/ 6 | tests/**/*.jsx 7 | -------------------------------------------------------------------------------- /example-react-ts-app/tests/__mocks__/shim.js: -------------------------------------------------------------------------------- 1 | global.requestAnimationFrame = (callback) => { 2 | setTimeout(callback, 0); 3 | }; 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | beautifulsoup4==4.7.1 2 | certifi==2019.3.9 3 | chardet==3.0.4 4 | idna==2.8 5 | requests==2.22.0 6 | soupsieve==1.9.1 7 | urllib3==1.25.3 8 | -------------------------------------------------------------------------------- /example-react-ts-app/src/assets/scss/App.scss: -------------------------------------------------------------------------------- 1 | $bg-color: yellow; 2 | $border-color: red; 3 | 4 | .app { 5 | font-family: helvetica, arial, sans-serif; 6 | padding: 2em; 7 | border: 5px solid $border-color; 8 | 9 | p { 10 | background-color: $bg-color; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /example-react-ts-app/express.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | const portNumber = 3000; 4 | const sourceDir = 'dist'; 5 | 6 | app.use(express.static(sourceDir)); 7 | 8 | app.listen(portNumber, () => { 9 | console.log(`Express web server started: http://localhost:${portNumber}`); 10 | console.log(`Serving content from /${sourceDir}/`); 11 | }); 12 | -------------------------------------------------------------------------------- /example-react-ts-app/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["@babel/preset-env", {"modules": false}], 4 | "@babel/preset-react" 5 | ], 6 | "plugins": [ 7 | "react-hot-loader/babel" 8 | ], 9 | "env": { 10 | "production": { 11 | "presets": ["minify"] 12 | }, 13 | "test": { 14 | "presets": ["@babel/preset-env", "@babel/preset-react"] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /example-react-ts-app/configs/webpack/prod.js: -------------------------------------------------------------------------------- 1 | // production config 2 | const merge = require('webpack-merge'); 3 | const {resolve} = require('path'); 4 | 5 | const commonConfig = require('./common'); 6 | 7 | module.exports = merge(commonConfig, { 8 | mode: 'production', 9 | entry: './index.tsx', 10 | output: { 11 | filename: 'js/bundle.[hash].min.js', 12 | path: resolve(__dirname, '../../dist'), 13 | publicPath: '/', 14 | }, 15 | devtool: 'source-map', 16 | plugins: [], 17 | }); 18 | -------------------------------------------------------------------------------- /example-react-ts-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist/", 4 | "sourceMap": true, 5 | "noImplicitAny": false, 6 | "module": "commonjs", 7 | "target": "es5", 8 | "jsx": "react", 9 | "lib": ["es5", "es6", "dom"] 10 | }, 11 | "include": [ 12 | "./src/**/*" 13 | ], 14 | "awesomeTypescriptLoaderOptions": { 15 | "reportFiles": [ 16 | "./src/**/*" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /example-react-ts-app/tests/App.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDOM from 'react-dom'; 3 | import * as TestUtils from 'react-dom/test-utils'; 4 | import App from '../src/components/App'; 5 | 6 | it('App is rendered', () => { 7 | // Render App in the document 8 | const appElement: App = TestUtils.renderIntoDocument( 9 | 10 | ); 11 | 12 | const appNode = ReactDOM.findDOMNode(appElement); 13 | 14 | // Verify text content 15 | expect(appNode.textContent).toEqual('Hello World!Foo to the barz'); 16 | }); 17 | -------------------------------------------------------------------------------- /example-react-ts-app/configs/jest.preprocessor.js: -------------------------------------------------------------------------------- 1 | const tsc = require('typescript'); 2 | const tsConfig = require('./../tsconfig.json'); 3 | 4 | module.exports = { 5 | process(src, path) { 6 | const isTs = path.endsWith('.ts'); 7 | const isTsx = path.endsWith('.tsx'); 8 | const isTypescriptFile = (isTs || isTsx); 9 | 10 | if ( isTypescriptFile ) { 11 | return tsc.transpileModule( 12 | src, 13 | { 14 | compilerOptions: tsConfig.compilerOptions, 15 | fileName: path 16 | } 17 | ).outputText; 18 | } 19 | 20 | return src; 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /example-react-ts-app/src/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import {render} from "react-dom"; 3 | import {AppContainer} from "react-hot-loader"; 4 | import App from "./components/App"; 5 | 6 | const rootEl = document.getElementById("root"); 7 | 8 | render( 9 | 10 | 11 | , 12 | rootEl 13 | ); 14 | 15 | // Hot Module Replacement API 16 | declare let module: { hot: any }; 17 | 18 | if (module.hot) { 19 | module.hot.accept("./components/App", () => { 20 | const NewApp = require("./components/App").default; 21 | 22 | render( 23 | 24 | 25 | , 26 | rootEl 27 | ); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /example-react-ts-app/configs/jest.json: -------------------------------------------------------------------------------- 1 | { 2 | "rootDir": "..", 3 | "coverageDirectory": "/tests/__coverage__/", 4 | "setupFiles": [ 5 | "/tests/__mocks__/shim.js" 6 | ], 7 | "roots": [ 8 | "/src/", 9 | "/tests/" 10 | ], 11 | "moduleNameMapper": { 12 | "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/tests/__mocks__/fileMock.js", 13 | "\\.(css|scss|less)$": "/tests/__mocks__/styleMock.js" 14 | }, 15 | "moduleFileExtensions": ["ts", "tsx", "js", "jsx"], 16 | "transform": { 17 | "^.+\\.(ts|tsx)$": "/configs/jest.preprocessor.js" 18 | }, 19 | "transformIgnorePatterns": [ 20 | "/node_modules/" 21 | ], 22 | "testRegex": "/tests/.*\\.(ts|tsx)$", 23 | "moduleDirectories": [ 24 | "node_modules" 25 | ], 26 | "globals": { 27 | "DEVELOPMENT": false, 28 | "FAKE_SERVER": false 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /example-react-ts-app/configs/webpack/dev.js: -------------------------------------------------------------------------------- 1 | // development config 2 | const merge = require('webpack-merge'); 3 | const webpack = require('webpack'); 4 | const commonConfig = require('./common'); 5 | 6 | module.exports = merge(commonConfig, { 7 | mode: 'development', 8 | entry: [ 9 | 'react-hot-loader/patch', // activate HMR for React 10 | 'webpack-dev-server/client?http://localhost:8080',// bundle the client for webpack-dev-server and connect to the provided endpoint 11 | 'webpack/hot/only-dev-server', // bundle the client for hot reloading, only- means to only hot reload for successful updates 12 | './index.tsx' // the entry point of our app 13 | ], 14 | devServer: { 15 | hot: true, // enable HMR on the server 16 | }, 17 | devtool: 'cheap-module-eval-source-map', 18 | plugins: [ 19 | new webpack.HotModuleReplacementPlugin(), // enable HMR globally 20 | new webpack.NamedModulesPlugin(), // prints more readable module names in the browser console on HMR updates 21 | ], 22 | }); 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 rarecoil. 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 | -------------------------------------------------------------------------------- /example-react-ts-app/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Viktor Persson 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 | -------------------------------------------------------------------------------- /example-react-ts-app/src/index.html.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Hello React! 7 | 8 | 9 |
10 | 11 | 12 | <% if (webpackConfig.mode == 'production') { %> 13 | 14 | 15 | <% } else { %> 16 | 17 | 18 | <% } %> 19 | 20 | 21 | -------------------------------------------------------------------------------- /example-react-ts-app/src/components/App.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import "./../assets/scss/App.scss"; 3 | import { FakeLibrary } from "../lib/LibraryCode"; 4 | 5 | // initialize a fakelibrary to use here. 6 | const fakeLibraryInstance = new FakeLibrary(); 7 | let helloStr = fakeLibraryInstance.helloWorld(); 8 | 9 | export interface AppProps { 10 | } 11 | 12 | export default class App extends React.Component { 13 | render() { 14 | return ( 15 |
16 |

{helloStr}

17 |

18 | This is a React.Component that has been Webpacked. Note that this 19 | source code, as well as the others, are published in the source map for this 20 | application. 21 |

22 |

23 | This is originally a TypeScript project that has been compiled to JS and then 24 | minified by Webpack's TerserPlugin. However, the source maps exist 25 | here, so we can extract them and recover the original build tree and source from 26 | these maps. 27 |

28 |

29 | To try it for yourself, run the source map script on this URI. 30 |

31 |
32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /example-react-ts-app/configs/webpack/common.js: -------------------------------------------------------------------------------- 1 | // shared config (dev and prod) 2 | const {resolve} = require('path'); 3 | const {CheckerPlugin} = require('awesome-typescript-loader'); 4 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 5 | 6 | module.exports = { 7 | resolve: { 8 | extensions: ['.ts', '.tsx', '.js', '.jsx'], 9 | }, 10 | context: resolve(__dirname, '../../src'), 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.js$/, 15 | use: ['babel-loader', 'source-map-loader'], 16 | exclude: /node_modules/, 17 | }, 18 | { 19 | test: /\.tsx?$/, 20 | use: ['babel-loader', 'awesome-typescript-loader'], 21 | }, 22 | { 23 | test: /\.css$/, 24 | use: ['style-loader', { loader: 'css-loader', options: { importLoaders: 1 } }], 25 | }, 26 | { 27 | test: /\.scss$/, 28 | loaders: [ 29 | 'style-loader', 30 | { loader: 'css-loader', options: { importLoaders: 1 } }, 31 | 'sass-loader', 32 | ], 33 | }, 34 | { 35 | test: /\.(jpe?g|png|gif|svg)$/i, 36 | loaders: [ 37 | 'file-loader?hash=sha512&digest=hex&name=img/[hash].[ext]', 38 | 'image-webpack-loader?bypassOnDebug&optipng.optimizationLevel=7&gifsicle.interlaced=false', 39 | ], 40 | }, 41 | ], 42 | }, 43 | plugins: [ 44 | new CheckerPlugin(), 45 | new HtmlWebpackPlugin({template: 'index.html.ejs',}), 46 | ], 47 | externals: { 48 | 'react': 'React', 49 | 'react-dom': 'ReactDOM', 50 | }, 51 | performance: { 52 | hints: false, 53 | }, 54 | }; 55 | -------------------------------------------------------------------------------- /example-react-ts-app/README.md: -------------------------------------------------------------------------------- 1 | # React Webpack Typescript Starter 2 | > Minimal starter with hot module replacement (HMR) for rapid development. 3 | 4 | * **[React](https://facebook.github.io/react/)** (16.x) 5 | * **[Webpack](https://webpack.js.org/)** (4.x) 6 | * **[Typescript](https://www.typescriptlang.org/)** (3.x) 7 | * **[Hot Module Replacement (HMR)](https://webpack.js.org/concepts/hot-module-replacement/)** using [React Hot Loader](https://github.com/gaearon/react-hot-loader) (4.x) 8 | * [Babel](http://babeljs.io/) (7.x) 9 | * [SASS](http://sass-lang.com/) 10 | * [Jest](https://facebook.github.io/jest/) - Testing framework for React applications 11 | * Production build script 12 | * Image loading/minification using [Image Webpack Loader](https://github.com/tcoopman/image-webpack-loader) 13 | * Typescript compiling using [Awesome Typescript Loader](https://github.com/s-panferov/awesome-typescript-loader) (5.x) 14 | * Code quality (linting) for Typescript. 15 | 16 | ## Installation 17 | 1. Clone/download repo 18 | 2. `yarn install` (or `npm install` for npm) 19 | 20 | ## Usage 21 | **Development** 22 | 23 | `yarn run start-dev` 24 | 25 | * Build app continuously (HMR enabled) 26 | * App served @ `http://localhost:8080` 27 | 28 | **Production** 29 | 30 | `yarn run start-prod` 31 | 32 | * Build app once (HMR disabled) to `/dist/` 33 | * App served @ `http://localhost:3000` 34 | 35 | --- 36 | 37 | **All commands** 38 | 39 | Command | Description 40 | --- | --- 41 | `yarn run start-dev` | Build app continuously (HMR enabled) and serve @ `http://localhost:8080` 42 | `yarn run start-prod` | Build app once (HMR disabled) to `/dist/` and serve @ `http://localhost:3000` 43 | `yarn run build` | Build app to `/dist/` 44 | `yarn run test` | Run tests 45 | `yarn run lint` | Run Typescript linter 46 | `yarn run start` | (alias of `yarn run start-dev`) 47 | 48 | **Note**: replace `yarn` with `npm` if you use npm. 49 | 50 | ## See also 51 | * [React Webpack Babel Starter](https://github.com/vikpe/react-webpack-babel-starter) 52 | * [Isomorphic Webapp Starter](https://github.com/vikpe/isomorphic-webapp-starter) 53 | -------------------------------------------------------------------------------- /example-react-ts-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-webpack-typescript-starter", 3 | "version": "0.1.0", 4 | "description": "Starter kit for React, Webpack (with Hot Module Replacement), Typescript and Babel.", 5 | "keywords": [ 6 | "react", 7 | "webpack", 8 | "typescript", 9 | "babel", 10 | "sass", 11 | "hmr", 12 | "starter", 13 | "boilerplate" 14 | ], 15 | "author": "Viktor Persson", 16 | "license": "MIT", 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/vikpe/react-webpack-typescript-starter.git" 20 | }, 21 | "bugs": { 22 | "url": "https://github.com/vikpe/react-webpack-typescript-starter/issues" 23 | }, 24 | "homepage": "https://github.com/vikpe/react-webpack-typescript-starter", 25 | "scripts": { 26 | "build": "yarn run clean-dist && webpack -p --config=configs/webpack/prod.js", 27 | "clean-dist": "rm -f -r -d dist", 28 | "lint": "tslint './src/**/*.ts*' --format stylish --force", 29 | "start": "yarn run start-dev", 30 | "start-dev": "webpack-dev-server --config=configs/webpack/dev.js", 31 | "start-prod": "yarn run build && node express.js", 32 | "test": "jest --watch --coverage --config=configs/jest.json" 33 | }, 34 | "devDependencies": { 35 | "@babel/cli": "^7.4.4", 36 | "@babel/core": "^7.4.5", 37 | "@babel/preset-env": "^7.4.5", 38 | "@babel/preset-react": "^7.0.0", 39 | "@types/jest": "^24.0.13", 40 | "@types/node": "^12.0.8", 41 | "@types/react": "^16.8.19", 42 | "@types/react-dom": "^16.8.4", 43 | "awesome-typescript-loader": "^5.2.1", 44 | "babel-loader": "^8.0.6", 45 | "css-loader": "^3.0.0", 46 | "express": "^4.17.1", 47 | "file-loader": "^4.0.0", 48 | "html-webpack-plugin": "^3.2.0", 49 | "image-webpack-loader": "^5.0.0", 50 | "jest": "^24.8.0", 51 | "node-sass": "^4.13.0", 52 | "react": "^16.8.6", 53 | "react-dom": "^16.8.6", 54 | "react-hot-loader": "^4.11.0", 55 | "sass-loader": "^7.1.0", 56 | "style-loader": "^0.23.1", 57 | "tslint": "^5.17.0", 58 | "typescript": "^3.5.1", 59 | "uglifyjs-webpack-plugin": "^2.1.3", 60 | "webpack": "^4.33.0", 61 | "webpack-cli": "^3.3.4", 62 | "webpack-dev-middleware": "^3.7.0", 63 | "webpack-dev-server": "^3.7.1", 64 | "webpack-merge": "^4.2.1" 65 | }, 66 | "dependencies": {} 67 | } 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | 53 | # Translations 54 | *.mo 55 | *.pot 56 | 57 | # Django stuff: 58 | *.log 59 | local_settings.py 60 | db.sqlite3 61 | db.sqlite3-journal 62 | 63 | # Flask stuff: 64 | instance/ 65 | .webassets-cache 66 | 67 | # Scrapy stuff: 68 | .scrapy 69 | 70 | # Sphinx documentation 71 | docs/_build/ 72 | 73 | # PyBuilder 74 | target/ 75 | 76 | # Jupyter Notebook 77 | .ipynb_checkpoints 78 | 79 | # IPython 80 | profile_default/ 81 | ipython_config.py 82 | 83 | # pyenv 84 | .python-version 85 | 86 | # pipenv 87 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 88 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 89 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 90 | # install all needed dependencies. 91 | #Pipfile.lock 92 | 93 | # celery beat schedule file 94 | celerybeat-schedule 95 | 96 | # SageMath parsed files 97 | *.sage.py 98 | 99 | # Environments 100 | .env 101 | .venv 102 | env/ 103 | venv/ 104 | ENV/ 105 | env.bak/ 106 | venv.bak/ 107 | 108 | # Spyder project settings 109 | .spyderproject 110 | .spyproject 111 | 112 | # Rope project settings 113 | .ropeproject 114 | 115 | # mkdocs documentation 116 | /site 117 | 118 | # mypy 119 | .mypy_cache/ 120 | .dmypy.json 121 | dmypy.json 122 | 123 | # Pyre type checker 124 | .pyre/ 125 | 126 | .vscode/ 127 | output/ 128 | -------------------------------------------------------------------------------- /example-react-ts-app/src/assets/img/react_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example-react-ts-app/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "jsRules": { 3 | "class-name": true, 4 | "comment-format": [ 5 | true, 6 | "check-space" 7 | ], 8 | "indent": [ 9 | true, 10 | "spaces" 11 | ], 12 | "no-duplicate-variable": true, 13 | "no-eval": true, 14 | "no-trailing-whitespace": true, 15 | "no-unsafe-finally": true, 16 | "one-line": [ 17 | true, 18 | "check-open-brace", 19 | "check-whitespace" 20 | ], 21 | "quotemark": [ 22 | true, 23 | "double" 24 | ], 25 | "semicolon": [ 26 | true, 27 | "always" 28 | ], 29 | "triple-equals": [ 30 | true, 31 | "allow-null-check" 32 | ], 33 | "variable-name": [ 34 | true, 35 | "ban-keywords" 36 | ], 37 | "whitespace": [ 38 | true, 39 | "check-branch", 40 | "check-decl", 41 | "check-operator", 42 | "check-separator", 43 | "check-type" 44 | ] 45 | }, 46 | "rules": { 47 | "class-name": true, 48 | "comment-format": [ 49 | true, 50 | "check-space" 51 | ], 52 | "indent": [ 53 | true, 54 | "spaces" 55 | ], 56 | "no-eval": true, 57 | "no-internal-module": true, 58 | "no-trailing-whitespace": true, 59 | "no-unsafe-finally": true, 60 | "no-var-keyword": true, 61 | "one-line": [ 62 | true, 63 | "check-open-brace", 64 | "check-whitespace" 65 | ], 66 | "quotemark": [ 67 | true, 68 | "double" 69 | ], 70 | "semicolon": [ 71 | true, 72 | "always" 73 | ], 74 | "triple-equals": [ 75 | true, 76 | "allow-null-check" 77 | ], 78 | "typedef-whitespace": [ 79 | true, 80 | { 81 | "call-signature": "nospace", 82 | "index-signature": "nospace", 83 | "parameter": "nospace", 84 | "property-declaration": "nospace", 85 | "variable-declaration": "nospace" 86 | } 87 | ], 88 | "variable-name": [ 89 | true, 90 | "ban-keywords" 91 | ], 92 | "whitespace": [ 93 | true, 94 | "check-branch", 95 | "check-decl", 96 | "check-operator", 97 | "check-separator", 98 | "check-type" 99 | ] 100 | } 101 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # unwebpack-sourcemap 2 | 3 | # Archive Notice (April 15 2022) 4 | 5 | This script seems to be helpful for many, but unfortunately I also do not have time to maintain it and properly code review the work of potential contributors. I'll leave it in an archived state for a while for anyone that wants to fork it, but I will eventually delete this repository. 6 | 7 | 8 | 9 | ### Recover uncompiled TypeScript sources, JSX, and more from Webpack sourcemaps. 10 | 11 | As single-page applications take over the world, more and more is being asked of the browser as a client. It is common for SPAs to use [Webpack](https://webpack.js.org/) to handle browser script build processes. Usually, Webpack will transpile React/Vue/TypeScript/etc. to JavaScript, minify/compress it, and then serve it as a single bundle to the application. 12 | 13 | However, Webpack also produces [JavaScript source maps](https://www.html5rocks.com/en/tutorials/developertools/sourcemaps/) to assist in the debugging and development process; when things go wrong, the browser's debugger can use the SourceMap to point to a line in the code that contains the issue at hand. Most developers do not adequately protect the source maps and ship them to production environments. 14 | 15 | When the browser was simply handling an array of JavaScript files concatenated and (maybe) packed, this wasn't so much of an issue. However, developers of SPAs assume the use of JavaScript as an **intermediate representation**. Developers often expect production to contain obfuscated and/or otherwise-processed scripts, and do not understand just what the sourcemaps contain in many cases. This model aligns closely with shipping binaries: source is compiled and you ship the interpretable version. If this is the case, the sourcemap is akin to leaking your source alongside the "binary" (bundle) you have made. The bundle can be reverse engineered just as a binary can, but sourcemaps make this far easier. 16 | 17 | 18 | ## Usage 19 | 20 | The script requires Python3, `BeautifulSoup4` and `requests`. Install dependencies with `pip3 install -r requirements.txt`. The script can handle downloaded sourcemaps, or attempt to parse them from remote sources for you. In all of these cases, we will assume that you have a directory you have created called `output` alongside the script: 21 | 22 | ``` 23 | \$ mkdir output 24 | ``` 25 | 26 | In order of increasing noisiness, to unpack a local sourcemap: 27 | 28 | ``` 29 | \$ ./unwebpack_sourcemap.py --local /path/to/source.map output 30 | ``` 31 | 32 | To unpack a remote sourcemap: 33 | 34 | ``` 35 | \$ ./unwebpack_sourcemap.py https://pathto.example.com/source.map output 36 | ``` 37 | 38 | To attempt to read all `