├── .gitignore ├── LICENSE ├── README.md ├── config ├── plugin │ ├── babel.js │ ├── eslint.js │ ├── paths.js │ └── webpack.js └── webview │ ├── babel.js │ ├── env.js │ ├── eslint.js │ ├── paths.js │ ├── polyfills.js │ ├── webpack-dev-server.js │ ├── webpack-dev.js │ └── webpack-prod.js ├── docs └── index.html ├── headers └── parsed │ └── .gitkeep ├── logo.svg ├── package.json ├── scripts ├── build.js ├── parse-headers.js ├── plugin │ ├── build.js │ └── bundle.js ├── start-webview.js ├── start.js ├── utils │ ├── build.js │ ├── fox.js │ ├── sketchtool.js │ └── todos.js └── webview │ ├── build-bak.js │ └── build.js ├── src ├── plugin │ ├── index.js │ ├── manifest.json │ └── utils │ │ ├── .gitkeep │ │ ├── core.js │ │ ├── debug │ │ ├── debug.js │ │ ├── index.js │ │ └── window.js │ │ ├── formatter.js │ │ └── webview │ │ ├── index.js │ │ ├── webview.js │ │ └── window.js └── webview │ ├── assets │ ├── fonts │ │ └── icomoon │ │ │ ├── fonts │ │ │ ├── icomoon.eot │ │ │ ├── icomoon.svg │ │ │ ├── icomoon.ttf │ │ │ └── icomoon.woff │ │ │ ├── selection.json │ │ │ └── style.css │ └── sketch-logo.svg │ ├── index.html │ ├── js │ ├── components │ │ ├── actions │ │ │ ├── action-details.js │ │ │ ├── action-timeline.js │ │ │ └── action.js │ │ ├── console │ │ │ └── log-list.js │ │ ├── elements │ │ │ ├── element-tree-item.js │ │ │ └── element-tree.js │ │ ├── link.js │ │ ├── log │ │ │ ├── array.js │ │ │ ├── class.js │ │ │ ├── empty.js │ │ │ ├── number.js │ │ │ ├── object.js │ │ │ ├── string.js │ │ │ └── value.js │ │ ├── network │ │ │ ├── network-request-details.js │ │ │ ├── network-request-timeline.js │ │ │ └── network-request.js │ │ └── screens │ │ │ ├── 404.js │ │ │ ├── actions.js │ │ │ ├── app.js │ │ │ ├── console.js │ │ │ ├── elements.js │ │ │ └── network.js │ ├── data │ │ ├── actions.js │ │ ├── console.js │ │ ├── elements.js │ │ └── network.js │ ├── index.js │ ├── routes.js │ ├── store.js │ └── utils │ │ ├── redux.js │ │ └── sketch.js │ └── scss │ ├── _colors.scss │ ├── _fonts.scss │ ├── _shadows.scss │ ├── actions.scss │ ├── app.scss │ ├── console.scss │ ├── elements.scss │ ├── filters.scss │ ├── network.scss │ ├── panel.scss │ └── tabs.scss └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | 3 | # Build folder 4 | Contents/ 5 | 6 | # Parsed ObjC class headers 7 | headers/parsed/*.json -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Julian Burr 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 | ![Logo](./logo.svg) 2 | 3 | 4 | 5 | # Sketch Plugin Debugger 6 | 7 | **Please note this repo is still in the experimental stage, things may or may not be working and APIs will most likely change in the future** 8 | 9 | This tool was born out of the frustration of existing debugging tools for Sketch plugin development. It is a concept for a debugger console in form of an easily instalable Sketch plugin, as well as a bundle of util functions that can be pulled into any project using npm. 10 | 11 | 12 | ## Util functions 13 | 14 | ### Why? 15 | 16 | In the Sketch plugin development environment, the global `log` function is provided to create system logs (alias for [`NSLog`](https://developer.apple.com/reference/foundation/1395275-nslog?language=objc) I guess?!). But this function is not very flexible. It can only take one argument and it cannot divide into different log levels. So I decided create some small util functions, that behave more like the [`console`](https://developer.mozilla.org/en/docs/Web/API/console) functions I am used to from usual JS development... 17 | 18 | The util functions also send the logs to a seperate plugin, that can be installed if you wish so (it is not required! You are very welcome to keep using the System Console if you prefer so :)). For more infos, see [the plugin section](#plugin) 19 | 20 | ### Get started 21 | 22 | To import the debugger util functions, simply use npm: 23 | ```bash 24 | npm install --save sketch-debugger 25 | 26 | # Or yarn 27 | yarn add sketch-debugger 28 | ``` 29 | 30 | Then import it wherever you need it... 31 | 32 | ```js 33 | import Debug from 'sketch-debugger'; 34 | //... 35 | Debug.log('Hello', 'World', foo); 36 | Debug.warn('Some warning'); 37 | Debug.error('This should not happen ;)'); 38 | ``` 39 | 40 | ### Methods 41 | 42 | The methods follow the same approach as the [console functions](https://developer.mozilla.org/en/docs/Web/API/console) JS developers are used to in the JS browser environment. 43 | 44 | **log(...args)** 45 | Default log method, takes any number of arguments and logs the passed value to the console (both the system log and the Sketch debugger plugin if available. 46 | 47 | **warn(...args)** 48 | Logs warnings (in the system console, the logs will have the leading `### WARN` and a trailing `#WARN END` log). 49 | 50 | **error(...args)** 51 | Logs errors (in the system console, the logs will have the leading `### ERROR` and a trailing `#ERROR END` log). 52 | 53 | **count(log)** *(work in progress)* 54 | Counts occurances of specified log (from last console.clear). In the system console, it adds the leading log `### COUNT: {count}`. 55 | 56 | **time(identifier)**/**timeEnd(identifier)** *(work in progress)* 57 | Creates a timer to measure time between two execution points. Creates the following logs in the system console: `### TIME START - {identifier}` / `### TIME END: {duration}ms - {identifier}`. 58 | 59 | **group(identifier)**/**groupEnd()** *(work in progress)* 60 | Creates a group and puts all following logs into this group until closed by groupEnd, which will always close the group that was opened last. This will add the following logs to the system console: `### GROUP START - {identifier}` / `### GROUP END - {identifier}`. 61 | 62 | **clear()** *(work in progress)* 63 | Clears the console memory. This will only affect the plugins console, not the system logs. 64 | 65 | 66 | ## Plugin 67 | 68 | ### Why? 69 | 70 | I use logs a lot during development. I grew up with Firebug and love the Chrome Debugger. And I hate the System Console :/ It is simply doesn't provide all the nice features I was used to from web development. 71 | 72 | So I decided to create a simple plugin with a GUI similar to those browser debuggers. Your logs can be classified (normal logs, warnings and erros), you can use other util functions like timers, groups and counters (*work in progress!*) and you have a lot of visual helpers to feel more comfortable during the debug process ;) 73 | 74 | ### Get started 75 | 76 | Download the `sketch-debugger.sketchplugin` file from this repo and double click (or manually move it into your Sketch plugin folder). That's it. 77 | 78 | Now you should have a new menu item under `Plugins` called `Open Debugger`. This will open a window with the debugger panels. Once this window is open, all logs (created by the sketch-debugger util functions) will be send to it! No further setup or anything else required :) 79 | 80 | ### Features 81 | 82 | **Console** 83 | Developers console with all the logs that have been created using the utils functions. Logs can be easily searched, filters, cleared, etc. 84 | 85 | *Work in progress:* It would nice to have a console functionality, where you can type in JS which will be executed on *Enter*, including that the selected log value gets copied into the namespace (e.g. as `$sel`), to be able e.g. to iterate through a logged collection... 86 | 87 | **Elements** *(work in progress)* 88 | This will give you a live representation of the Document / Page / Layer structure in your currently opened Sketch documents. Ideally at some point this will have an automated `MS*/NS*` documentation integrated showing all available methods on selected objects. 89 | 90 | **Actions** *(work in progress)* 91 | If possible I'd like to integrate a panel that show all actions, when they are triggered, what context they include, etc. Maybe also not limited to MSActions, but a general action observer. 92 | 93 | **Network** *(work in progress)* 94 | With a similar util library it would be possible to log network requests and responses, show timings, headers, parameters, etc. 95 | 96 |
97 |
98 | 99 | 100 | # Roadmap / Todos 101 | 102 | ## General 103 | 104 | - [x] ~~Pull bootstraped plugin out of [`sketch-plugin-boilerplate`](https://github.com/julianburr/sketch-plugin-boilerplate)~~ 105 | - [x] ~~Create build structure that also creates compiled and optimized util folder to be used as npm entry point~~ *TODO: simplify (build) scripts* 106 | - [x] ~~Publish npm package~~ 107 | - [ ] Create simple website with howtos and documentation of util functions 108 | - [ ] Debugger lib build 109 | 110 | ## Util Functions 111 | - [ ] .count method 112 | - [ ] .time* methods 113 | - [ ] .group* methods 114 | 115 | ## Plugin 116 | - [ ] Hook Sketch up to deliver data in specified format 117 | - [ ] Add stack trace now that I can get it with the preprocessor enabled + integrate [source map](https://github.com/mozilla/source-map) handling to show the original trace if plugin.js has a source map defined! 118 | - [x] ~~Finish console layout / design~~ 119 | - [x] ~~Add element tree panel~~ 120 | - [x] ~~Create HTTP request utils that also send data to debugger~~ see [`sketch-fetch`](https://github.com/julianburr/sketch-fetch) 121 | - [x] ~~Add network panel~~ 122 | - [x] ~~Add actions panel~~ 123 | - [ ] Add action listener (if possible without crashes :/) and add action panel 124 | - [ ] Integrate automated `MS*` documentation tool build on the [`class-dumps`](https://github.com/abynim/Sketch-Headers) if possible 125 | - [ ] Think about a way to read the system logs as well and turn them into a nicer/more readable format in the plugins console 126 | -------------------------------------------------------------------------------- /config/plugin/babel.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ['es2015', { 4 | modules: false 5 | }] 6 | ], 7 | 'plugins': [ 8 | 'transform-object-rest-spread', 9 | ['module-resolver', { 10 | alias: { 11 | utils: './src/plugin/utils' 12 | } 13 | }] 14 | ] 15 | } -------------------------------------------------------------------------------- /config/plugin/eslint.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['semistandard'], 3 | globals: { 4 | MSDocument: false, 5 | MSDocumentWindow: false, 6 | MSPage: false, 7 | MSSymbolInstance: false, 8 | MSSymbolMaster: false, 9 | MSTextLayer: false, 10 | NSAlert: false, 11 | NSApp: false, 12 | NSClassFromString: false, 13 | NSColor: false, 14 | NSData: false, 15 | NSDocument: false, 16 | NSDocumentController: false, 17 | NSFileManager: false, 18 | NSImage: false, 19 | NSJSONSerialization: false, 20 | NSMakeRect: false, 21 | NSMutableData: false, 22 | NSMutableURLRequest: false, 23 | NSSaveOperation: false, 24 | NSString: false, 25 | NSTextField: false, 26 | NSTextView: false, 27 | NSThread: false, 28 | NSTitledWindowMask: false, 29 | NSURL: false, 30 | NSURLRequest: false, 31 | NSUTF8StringEncoding: false, 32 | NSUserDefaults: false, 33 | NSView: false, 34 | NSViewHeightSizable: false, 35 | NSViewWidthSizable: false, 36 | NSWindow: false, 37 | NSWorkspace: false, 38 | WKWebView: false, 39 | WKWebViewConfiguration: false, 40 | Mocha: false, 41 | log: false, 42 | NSBackingStoreBuffered: false, 43 | NSPanel: false, 44 | NSResizableWindowMask: false, 45 | NSWindowStyleMaskClosable: false, 46 | SPBWebViewMessageHandler: false, 47 | SPBWebViewMessageUtils: false 48 | }, 49 | parser: 'babel-eslint', 50 | plugins: [ 51 | 'no-unused-vars-rest' 52 | ], 53 | rules: { 54 | eqeqeq: [ 55 | 0 56 | ] 57 | } 58 | } -------------------------------------------------------------------------------- /config/plugin/paths.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var fs = require('fs-extra'); 3 | 4 | var appDirectory = fs.realpathSync(process.cwd()); 5 | function resolveApp(relativePath) { 6 | return path.resolve(appDirectory, relativePath); 7 | } 8 | 9 | var src = resolveApp('src/plugin'); 10 | var frameworks = resolveApp('src/frameworks'); 11 | 12 | module.exports = { 13 | src, 14 | entry: resolveApp('src/plugin/index.js'), 15 | manifest: resolveApp('src/plugin/manifest.json'), 16 | build: resolveApp('Contents/Sketch'), 17 | bundle: resolveApp('sketch-plugin-boilerplate.sketchplugin'), 18 | frameworks, 19 | frameworksBuild: resolveApp('Contents/Resources/frameworks'), 20 | watch: [src, frameworks] 21 | }; 22 | -------------------------------------------------------------------------------- /config/plugin/webpack.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs-extra'); 2 | var path = require('path'); 3 | var chalk = require('chalk'); 4 | var webpack = require('webpack'); 5 | var objectAssign = require('object-assign'); 6 | 7 | var paths = require('./paths'); 8 | var babelConfig = require('./babel'); 9 | 10 | var isDevelopment = process.env.NODE_ENV !== 'production'; 11 | 12 | babelConfig = objectAssign(babelConfig, { 13 | cacheDirectory: isDevelopment, 14 | }); 15 | 16 | module.exports = { 17 | entry: paths.entry, 18 | output: { 19 | path: paths.build, 20 | filename: 'plugin.js', 21 | library: 'handlers', 22 | libraryTarget: 'var' 23 | }, 24 | module: { 25 | loaders: [ 26 | { 27 | test: /\.(js|jsx)$/, 28 | include: paths.src, 29 | exclude: /(node_modules)/, 30 | use: { 31 | loader: 'babel-loader', 32 | options: babelConfig 33 | } 34 | } 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /config/webview/babel.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 'react-app' ], 3 | plugins: [ 4 | 'transform-object-rest-spread', 5 | 'transform-decorators-legacy', 6 | [ 7 | 'module-resolver', 8 | { 9 | alias: { 10 | webview: './src/webview', 11 | components: './src/webview/js/components', 12 | data: './src/webview/js/data', 13 | utils: './src/webview/js/utils', 14 | assets: './src/webview/assets', 15 | styles: './src/webview/scss' 16 | } 17 | } 18 | ] 19 | ], 20 | cacheDirectory: true 21 | }; 22 | -------------------------------------------------------------------------------- /config/webview/env.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra'); 2 | const path = require('path'); 3 | const paths = require('./paths'); 4 | 5 | // Make sure that including paths.js after env.js will read .env variables. 6 | delete require.cache[require.resolve('./paths')]; 7 | 8 | const NODE_ENV = process.env.NODE_ENV; 9 | if (!NODE_ENV) { 10 | throw new Error( 11 | 'The NODE_ENV environment variable is required but was not specified.' 12 | ); 13 | } 14 | 15 | // https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use 16 | var dotenvFiles = [ 17 | `${paths.dotenv}.${NODE_ENV}.local`, 18 | `${paths.dotenv}.${NODE_ENV}`, 19 | // Don't include `.env.local` for `test` environment 20 | // since normally you expect tests to produce the same 21 | // results for everyone 22 | NODE_ENV !== 'test' && `${paths.dotenv}.local`, 23 | paths.dotenv, 24 | ].filter(Boolean); 25 | 26 | // Load environment variables from .env* files. Suppress warnings using silent 27 | // if this file is missing. dotenv will never modify any environment variables 28 | // that have already been set. 29 | // https://github.com/motdotla/dotenv 30 | dotenvFiles.forEach(dotenvFile => { 31 | if (fs.existsSync(dotenvFile)) { 32 | require('dotenv').config({ 33 | path: dotenvFile, 34 | }); 35 | } 36 | }); 37 | 38 | // We support resolving modules according to `NODE_PATH`. 39 | // This lets you use absolute paths in imports inside large monorepos: 40 | // https://github.com/facebookincubator/create-react-app/issues/253. 41 | // It works similar to `NODE_PATH` in Node itself: 42 | // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders 43 | // Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored. 44 | // Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims. 45 | // https://github.com/facebookincubator/create-react-app/issues/1023#issuecomment-265344421 46 | // We also resolve them to make sure all tools using them work consistently. 47 | const appDirectory = fs.realpathSync(process.cwd()); 48 | process.env.NODE_PATH = (process.env.NODE_PATH || '') 49 | .split(path.delimiter) 50 | .filter(folder => folder && !path.isAbsolute(folder)) 51 | .map(folder => path.resolve(appDirectory, folder)) 52 | .join(path.delimiter); 53 | 54 | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be 55 | // injected into the application via DefinePlugin in Webpack configuration. 56 | const REACT_APP = /^REACT_APP_/i; 57 | 58 | function getClientEnvironment(publicUrl) { 59 | const raw = Object.keys(process.env) 60 | .filter(key => REACT_APP.test(key)) 61 | .reduce( 62 | (env, key) => { 63 | env[key] = process.env[key]; 64 | return env; 65 | }, 66 | { 67 | // Useful for determining whether we’re running in production mode. 68 | // Most importantly, it switches React into the correct mode. 69 | NODE_ENV: process.env.NODE_ENV || 'development', 70 | // Useful for resolving the correct path to static assets in `public`. 71 | // For example, . 72 | // This should only be used as an escape hatch. Normally you would put 73 | // images into the `src` and `import` them in code to get their paths. 74 | PUBLIC_URL: publicUrl, 75 | } 76 | ); 77 | // Stringify all values so we can feed into Webpack DefinePlugin 78 | const stringified = { 79 | 'process.env': Object.keys(raw).reduce((env, key) => { 80 | env[key] = JSON.stringify(raw[key]); 81 | return env; 82 | }, {}), 83 | }; 84 | 85 | return { raw, stringified }; 86 | } 87 | 88 | module.exports = getClientEnvironment; -------------------------------------------------------------------------------- /config/webview/eslint.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: ['react'], 3 | extends: ['semistandard'], 4 | env: { 5 | es6: true 6 | }, 7 | parser: 'babel-eslint', 8 | parserOptions: { 9 | sourceType: 'module', 10 | ecmaVersion: 6, 11 | ecmaFeatures: { 12 | impliedStrict: true, 13 | experimentalObjectRestSpread: true, 14 | jsx: true 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /config/webview/paths.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var fs = require('fs-extra'); 3 | 4 | var appDirectory = fs.realpathSync(process.cwd()); 5 | function resolveApp(relativePath) { 6 | return path.resolve(appDirectory, relativePath); 7 | } 8 | 9 | var nodePaths = (process.env.NODE_PATH || '') 10 | .split(process.platform === 'win32' ? ';' : ':') 11 | .filter(Boolean) 12 | .filter(folder => !path.isAbsolute(folder)) 13 | .map(resolveApp); 14 | 15 | module.exports = { 16 | src: resolveApp('src/webview/'), 17 | build: resolveApp('Contents/Resources/webview/'), 18 | buildBundleJs: 'Contents/Resources/webview/js/index.js', 19 | indexHtml: resolveApp('src/webview/index.html'), 20 | indexJs: resolveApp('src/webview/js/index.js'), 21 | packageJson: resolveApp('package.json'), 22 | yarnLockFile: resolveApp('yarn.lock'), 23 | appNodeModules: resolveApp('node_modules'), 24 | ownNodeModules: resolveApp('node_modules'), 25 | nodePaths: nodePaths, 26 | yarnLockFile: resolveApp('yarn.lock'), 27 | homepage: './' 28 | }; -------------------------------------------------------------------------------- /config/webview/polyfills.js: -------------------------------------------------------------------------------- 1 | if (typeof Promise === 'undefined') { 2 | // Rejection tracking prevents a common issue where React gets into an 3 | // inconsistent state due to an error, but it gets swallowed by a Promise, 4 | // and the user has no idea what causes React's erratic future behavior. 5 | require('promise/lib/rejection-tracking').enable(); 6 | window.Promise = require('promise/lib/es6-extensions.js'); 7 | } 8 | 9 | // fetch() polyfill for making API calls. 10 | require('whatwg-fetch'); 11 | 12 | // Object.assign() is commonly used with React. 13 | // It will use the native implementation if it's present and isn't buggy. 14 | Object.assign = require('object-assign'); 15 | -------------------------------------------------------------------------------- /config/webview/webpack-dev-server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const errorOverlayMiddleware = require('react-error-overlay/middleware'); 4 | const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware'); 5 | const config = require('./webpack-dev'); 6 | const paths = require('./paths'); 7 | 8 | const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; 9 | const host = process.env.HOST || '0.0.0.0'; 10 | 11 | module.exports = function(proxy, allowedHost) { 12 | return { 13 | // WebpackDevServer 2.4.3 introduced a security fix that prevents remote 14 | // websites from potentially accessing local content through DNS rebinding: 15 | // https://github.com/webpack/webpack-dev-server/issues/887 16 | // https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a 17 | // However, it made several existing use cases such as development in cloud 18 | // environment or subdomains in development significantly more complicated: 19 | // https://github.com/facebookincubator/create-react-app/issues/2271 20 | // https://github.com/facebookincubator/create-react-app/issues/2233 21 | // While we're investigating better solutions, for now we will take a 22 | // compromise. Since our WDS configuration only serves files in the `public` 23 | // folder we won't consider accessing them a vulnerability. However, if you 24 | // use the `proxy` feature, it gets more dangerous because it can expose 25 | // remote code execution vulnerabilities in backends like Django and Rails. 26 | // So we will disable the host check normally, but enable it if you have 27 | // specified the `proxy` setting. Finally, we let you override it if you 28 | // really know what you're doing with a special environment variable. 29 | disableHostCheck: 30 | !proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true', 31 | // Enable gzip compression of generated files. 32 | compress: true, 33 | // Silence WebpackDevServer's own logs since they're generally not useful. 34 | // It will still show compile warnings and errors with this setting. 35 | clientLogLevel: 'none', 36 | // By default WebpackDevServer serves physical files from current directory 37 | // in addition to all the virtual build products that it serves from memory. 38 | // This is confusing because those files won’t automatically be available in 39 | // production build folder unless we copy them. However, copying the whole 40 | // project directory is dangerous because we may expose sensitive files. 41 | // Instead, we establish a convention that only files in `public` directory 42 | // get served. Our build script will copy `public` into the `build` folder. 43 | // In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%: 44 | // 45 | // In JavaScript code, you can access it with `process.env.PUBLIC_URL`. 46 | // Note that we only recommend to use `public` folder as an escape hatch 47 | // for files like `favicon.ico`, `manifest.json`, and libraries that are 48 | // for some reason broken when imported through Webpack. If you just want to 49 | // use an image, put it in `src` and `import` it from JavaScript instead. 50 | contentBase: paths.src, 51 | // By default files from `contentBase` will not trigger a page reload. 52 | watchContentBase: true, 53 | // Enable hot reloading server. It will provide /sockjs-node/ endpoint 54 | // for the WebpackDevServer client so it can learn when the files were 55 | // updated. The WebpackDevServer client is included as an entry point 56 | // in the Webpack development configuration. Note that only changes 57 | // to CSS are currently hot reloaded. JS changes will refresh the browser. 58 | hot: true, 59 | // It is important to tell WebpackDevServer to use the same "root" path 60 | // as we specified in the config. In development, we always serve from /. 61 | publicPath: config.build, 62 | // WebpackDevServer is noisy by default so we emit custom message instead 63 | // by listening to the compiler events with `compiler.plugin` calls above. 64 | quiet: true, 65 | // Reportedly, this avoids CPU overload on some systems. 66 | // https://github.com/facebookincubator/create-react-app/issues/293 67 | watchOptions: { 68 | ignored: /node_modules/, 69 | }, 70 | // Enable HTTPS if the HTTPS environment variable is set to 'true' 71 | https: protocol === 'https', 72 | host: host, 73 | overlay: false, 74 | historyApiFallback: { 75 | // Paths with dots should still use the history fallback. 76 | // See https://github.com/facebookincubator/create-react-app/issues/387. 77 | disableDotRule: true, 78 | }, 79 | public: allowedHost, 80 | proxy, 81 | setup(app) { 82 | // This lets us open files from the runtime error overlay. 83 | app.use(errorOverlayMiddleware()); 84 | // This service worker file is effectively a 'no-op' that will reset any 85 | // previous service worker registered for the same host:port combination. 86 | // We do this in development to avoid hitting the production cache if 87 | // it used the same host and port. 88 | // https://github.com/facebookincubator/create-react-app/issues/2272#issuecomment-302832432 89 | app.use(noopServiceWorkerMiddleware()); 90 | }, 91 | }; 92 | }; 93 | -------------------------------------------------------------------------------- /config/webview/webpack-dev.js: -------------------------------------------------------------------------------- 1 | const autoprefixer = require('autoprefixer'); 2 | const path = require('path'); 3 | const webpack = require('webpack'); 4 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 5 | const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); 6 | 7 | const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); 8 | const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); 9 | const eslintFormatter = require('react-dev-utils/eslintFormatter'); 10 | const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); 11 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 12 | 13 | const getClientEnvironment = require('./env'); 14 | const paths = require('./paths'); 15 | 16 | // Webpack uses `publicPath` to determine where the app is being served from. 17 | // In development, we always serve from the root. This makes config easier. 18 | const publicPath = '/'; 19 | // `publicUrl` is just like `publicPath`, but we will provide it to our app 20 | // as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. 21 | // Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz. 22 | const publicUrl = ''; 23 | // Get environment variables to inject into our app. 24 | const env = getClientEnvironment(publicUrl); 25 | 26 | const cssLoader = { 27 | loader: require.resolve('css-loader'), 28 | options: { 29 | importLoaders: 1, 30 | } 31 | }; 32 | const babel = require('./babel'); 33 | 34 | const postCssLoader = { 35 | loader: require.resolve('postcss-loader'), 36 | options: { 37 | // Necessary for external CSS imports to work 38 | // https://github.com/facebookincubator/create-react-app/issues/2677 39 | ident: 'postcss', 40 | plugins: () => [ 41 | require('postcss-flexbugs-fixes'), 42 | autoprefixer({ 43 | browsers: [ 44 | '>1%', 45 | 'last 4 versions', 46 | 'Firefox ESR', 47 | 'not ie < 9', // React doesn't support IE8 anyway 48 | ], 49 | flexbox: 'no-2009', 50 | }), 51 | ], 52 | }, 53 | }; 54 | 55 | // This is the development configuration. 56 | // It is focused on developer experience and fast rebuilds. 57 | // The production configuration is different and lives in a separate file. 58 | 59 | 60 | module.exports = { 61 | // You may want 'eval' instead if you prefer to see the compiled output in DevTools. 62 | // See the discussion in https://github.com/facebookincubator/create-react-app/issues/343. 63 | devtool: 'cheap-module-source-map', 64 | // These are the "entry points" to our application. 65 | // This means they will be the "root" imports that are included in JS bundle. 66 | // The first two entry points enable "hot" CSS and auto-refreshes for JS. 67 | entry: [ 68 | // Include an alternative client for WebpackDevServer. A client's job is to 69 | // connect to WebpackDevServer by a socket and get notified about changes. 70 | // When you save a file, the client will either apply hot updates (in case 71 | // of CSS changes), or refresh the page (in case of JS changes). When you 72 | // make a syntax error, this client will display a syntax error overlay. 73 | // Note: instead of the default WebpackDevServer client, we use a custom one 74 | // to bring better experience for Create React App users. You can replace 75 | // the line below with these two lines if you prefer the stock client: 76 | // require.resolve('webpack-dev-server/client') + '?/', 77 | // require.resolve('webpack/hot/dev-server'), 78 | require.resolve('react-dev-utils/webpackHotDevClient'), 79 | // We ship a few polyfills by default: 80 | require.resolve('./polyfills'), 81 | // Errors should be considered fatal in development 82 | require.resolve('react-error-overlay'), 83 | // Finally, this is your app's code: 84 | paths.indexJs, 85 | // We include the app code last so that if there is a runtime error during 86 | // initialization, it doesn't blow up the WebpackDevServer client, and 87 | // changing JS code would still trigger a refresh. 88 | ], 89 | output: { 90 | // Next line is not used in dev but WebpackDevServer crashes without it: 91 | path: paths.build, 92 | // Add /* filename */ comments to generated require()s in the output. 93 | pathinfo: true, 94 | // This does not produce a real file. It's just the virtual path that is 95 | // served by WebpackDevServer in development. This is the JS bundle 96 | // containing code from all our entry points, and the Webpack runtime. 97 | filename: 'static/js/bundle.js', 98 | // There are also additional JS chunk files if you use code splitting. 99 | chunkFilename: 'static/js/[name].chunk.js', 100 | // This is the URL that app is served from. We use "/" in development. 101 | publicPath: publicPath, 102 | // Point sourcemap entries to original disk location (format as URL on Windows) 103 | devtoolModuleFilenameTemplate: info => 104 | path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'), 105 | }, 106 | resolve: { 107 | // This allows you to set a fallback for where Webpack should look for modules. 108 | // We placed these paths second because we want `node_modules` to "win" 109 | // if there are any conflicts. This matches Node resolution mechanism. 110 | // https://github.com/facebookincubator/create-react-app/issues/253 111 | modules: ['node_modules', paths.appNodeModules].concat( 112 | // It is guaranteed to exist because we tweak it in `env.js` 113 | process.env.NODE_PATH.split(path.delimiter).filter(Boolean) 114 | ), 115 | // These are the reasonable defaults supported by the Node ecosystem. 116 | // We also include JSX as a common component filename extension to support 117 | // some tools, although we do not recommend using it, see: 118 | // https://github.com/facebookincubator/create-react-app/issues/290 119 | // `web` extension prefixes have been added for better support 120 | // for React Native Web. 121 | extensions: ['.web.js', '.js', '.json', '.web.jsx', '.jsx'], 122 | alias: { 123 | 124 | // Support React Native Web 125 | // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ 126 | 'react-native': 'react-native-web', 127 | }, 128 | plugins: [ 129 | // Prevents users from importing files from outside of src/ (or node_modules/). 130 | // This often causes confusion because we only process files within src/ with babel. 131 | // To fix this, we prevent you from importing files out of src/ -- if you'd like to, 132 | // please link the files into your node_modules/ and let module-resolution kick in. 133 | // Make sure your source files are compiled, as they will not be processed in any way. 134 | new ModuleScopePlugin(paths.src), 135 | ], 136 | }, 137 | module: { 138 | strictExportPresence: true, 139 | rules: [ 140 | // ** ADDING/UPDATING LOADERS ** 141 | // The "file" loader handles all assets unless explicitly excluded. 142 | // The `exclude` list *must* be updated with every change to loader extensions. 143 | // When adding a new loader, you must add its `test` 144 | // as a new entry in the `exclude` list for "file" loader. 145 | 146 | // "file" loader makes sure those assets get served by WebpackDevServer. 147 | // When you `import` an asset, you get its (virtual) filename. 148 | // In production, they would get copied to the `build` folder. 149 | { 150 | exclude: [ 151 | /\.html$/, 152 | /\.(js|jsx)$/, 153 | /\.css$/, 154 | /\.json$/, 155 | /\.bmp$/, 156 | /\.gif$/, 157 | /\.jpe?g$/, 158 | /\.png$/, 159 | ], 160 | loader: require.resolve('file-loader'), 161 | options: { 162 | name: 'static/media/[name].[hash:8].[ext]', 163 | }, 164 | }, 165 | // "url" loader works like "file" loader except that it embeds assets 166 | // smaller than specified limit in bytes as data URLs to avoid requests. 167 | // A missing `test` is equivalent to a match. 168 | { 169 | test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], 170 | loader: require.resolve('url-loader'), 171 | options: { 172 | limit: 10000, 173 | name: 'static/media/[name].[hash:8].[ext]', 174 | }, 175 | }, 176 | // Process JS with Babel. 177 | { 178 | test: /\.(js|jsx)$/, 179 | include: paths.src, 180 | loader: require.resolve('babel-loader'), 181 | options: babel 182 | }, 183 | 184 | // "postcss" loader applies autoprefixer to our CSS. 185 | // "css" loader resolves paths in CSS and adds assets as dependencies. 186 | { 187 | test: /\.scss$/, 188 | loader: ExtractTextPlugin.extract( 189 | Object.assign( 190 | { 191 | fallback: require.resolve('style-loader'), 192 | use: [ 193 | cssLoader, 194 | { 195 | loader: require.resolve('sass-loader') 196 | }, 197 | postCssLoader 198 | ] 199 | }, 200 | {} 201 | ) 202 | ), 203 | }, 204 | 205 | // "postcss" loader applies autoprefixer to our CSS. 206 | // "css" loader resolves paths in CSS and adds assets as dependencies. 207 | { 208 | test: /\.css$/, 209 | use: [ 210 | require.resolve('style-loader'), 211 | cssLoader, 212 | postCssLoader 213 | ], 214 | }, 215 | // ** STOP ** Are you adding a new loader? 216 | // Remember to add the new extension(s) to the "file" loader exclusion list. 217 | ], 218 | }, 219 | plugins: [ 220 | // Makes some environment variables available in index.html. 221 | // The public URL is available as %PUBLIC_URL% in index.html, e.g.: 222 | // 223 | // In development, this will be an empty string. 224 | new InterpolateHtmlPlugin(env.raw), 225 | // Generates an `index.html` file with the