├── .gitignore
├── LICENSE
├── README.md
├── __tests__
├── sketchtool.test.js
└── test.sketch
├── 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
├── 404.md
├── _config.yml
├── _includes
│ ├── docs-navigation.html
│ ├── global-vars
│ ├── head.html
│ ├── home-features.html
│ ├── home-hero.html
│ ├── navigation.html
│ ├── svgs
│ │ └── logo.svg
│ └── tutorials-navigation.html
├── _layouts
│ ├── default.html
│ ├── docs.html
│ ├── home.html
│ └── tutorials.html
├── _sass
│ ├── colors.scss
│ ├── components
│ │ ├── code.scss
│ │ └── navigation.scss
│ ├── layouts
│ │ ├── default.scss
│ │ └── home.scss
│ ├── mixins.scss
│ └── reset.scss
├── assets
│ ├── icomoon
│ │ ├── fonts
│ │ │ ├── icomoon.eot
│ │ │ ├── icomoon.svg
│ │ │ ├── icomoon.ttf
│ │ │ └── icomoon.woff
│ │ ├── selection.json
│ │ └── style.css
│ ├── images
│ │ └── favicon.png
│ └── styles
│ │ ├── index.scss
│ │ └── pygments
│ │ └── borland.css
├── docs
│ ├── build.md
│ ├── install.md
│ ├── setup
│ │ ├── eslint.md
│ │ ├── jest.md
│ │ └── webpack.md
│ ├── tests.md
│ └── utils
│ │ ├── core.md
│ │ ├── fetch.md
│ │ └── webview.md
├── index.md
└── tutorials
│ ├── advanced
│ ├── downloads.md
│ ├── guis-with-webviews.md
│ ├── network-requests.md
│ └── sketch-menu.md
│ ├── basics
│ └── plugin-entrypoints.md
│ └── index.md
├── package.json
├── scripts
├── build.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
├── docs
│ └── assets
│ │ ├── sketch-plugin-boilerplate-logo-reverse.svg
│ │ ├── sketch-plugin-boilerplate-logo.sketch
│ │ └── sketch-plugin-boilerplate-logo.svg
├── frameworks
│ └── .gitkeep
├── plugin
│ ├── index.js
│ ├── manifest.json
│ └── utils
│ │ ├── core.js
│ │ ├── formatter.js
│ │ └── webview
│ │ ├── index.js
│ │ ├── panel.js
│ │ ├── webview.js
│ │ └── window.js
└── webview
│ ├── assets
│ └── sketch-logo.svg
│ ├── index.html
│ ├── js
│ ├── actions
│ │ └── bridge.js
│ ├── app.js
│ ├── components
│ │ └── .gitkeep
│ ├── index.js
│ ├── reducers
│ │ ├── bridge.js
│ │ └── index.js
│ ├── store.js
│ └── utils
│ │ └── sketch.js
│ └── scss
│ ├── _colors.scss
│ ├── _fonts.scss
│ └── index.scss
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # Node modules
2 | node_modules/
3 |
4 | # Build folder
5 | Contents/
6 |
7 | # Ignore knowledge base for now until cleaned up :D
8 | knowledge/
9 |
10 | # Docs files
11 | docs/.sass-cache
12 | docs/_site
--------------------------------------------------------------------------------
/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 |
2 | 
3 |
4 |
5 |
6 |
7 | # Sketch Plugin Boilerplate
8 |
9 | The Sketch Plugin Boilerplate is targeted at JS Developers, who want to create awesome plugins for [Sketch](https://sketchapp.com), but don't want to have to go through all the Obj C frustrations to be able to do more complex stuff, like building GUIs, handling HTTP requests, etc.
10 |
11 | I tried to use as little Obj C as possible, again, this is supposed to be a helpful starting point for JS developers.
12 |
13 |
14 |
15 | > This is meant as a starting point, so clone the repo, modify anything and everything to your needs and build an awesome Sketch plugin
16 |
17 |
18 |
19 | ## Why
20 | Sketch is awesome. And they provided us an awesome API to develop plugins. But as a JS Developer, there are still many things that are quiet hard to achieve. The main problem I keep hearing of is the ability to build custom user interfaces (GUIs), which requires some knowledge of how web views work in Obj C, how you can communicate with them and then **a lot of** boilerplate.
21 |
22 | This repo should make it easier and faster to start new projects :)
23 |
24 |
25 | ## Getting started
26 |
27 | ```bash
28 | # Change to plugin folder
29 | cd ~/Library/Application Support/com.bohemiancoding.sketch3/Plugins/
30 |
31 | # Clone repo (as .sketchplugin!)
32 | git clone https://github.com/julianburr/sketch-plugin-boilerplate.git sketch-plugin-boilerplate.sketchplugin
33 | cd sketch-plugin-boilerplate.sketchplugin
34 |
35 | # Install dependecies
36 | yarn install
37 |
38 | # ...and create a first build
39 | yarn build
40 | ```
41 |
42 | ... and you are ready to go :)
43 |
44 |
45 | ## Commands / Scripts
46 |
47 | ```bash
48 | # Build and watch plugin (🔥, no need to run build every time to see changes in Sketch!)
49 | yarn start
50 |
51 | # Build and watch webview(s) in browser
52 | yarn start:webview
53 |
54 | # Compile everything into correct folder structure to use it in Sketch
55 | yarn build
56 |
57 | # Run eslint --fix on the source directory
58 | yarn lint-fix
59 |
60 | # Run Jest tests (needs Sketch / sketchtool installed locally)
61 | yarn test
62 | ```
63 |
64 | For the rest, see `package.json`
65 |
66 |
67 | ## Folder structure
68 |
69 | **Why is the folder structure as it is**
70 |
71 | The build structure follows [Sketch's guidelines](http://developer.sketchapp.com/introduction/plugin-bundles/) of how your plugin has to be structured. This makes development so much easier. All you have to do is to create the repo in your Sketch plugin folder (usually `~/Library/Application Support/com.bohemiancoding.sketch3/Plugins/`) and start coding. The watch and build scripts automatically put everything in the right place so you see the changes immediately in Sketch :)
72 |
73 | ```bash
74 | └─── /__tests__ # Jest tests and assets (e.g. Sketch files, etc) that are used for test scenarios
75 | └─── /config # Here you will find all necessary configurations, feel free to adjust them to your needs! :)
76 | │
77 | └─── /Contents # This is the build folder that Sketch reads
78 | │ └─── /Resources # Assets, frameworks, etc.
79 | │ └─── /Sketch # plugin.js and manifest.json have to be here
80 | │
81 | └─── /scripts # The npm scripts, also feel free to change to your needs, this is a boilerplate, not an end product!
82 | │ └─── /plugin # For `yarn *:plugin` scripts
83 | │ └─── /webview
84 | │
85 | └─── /src # Source code, split into the different parts of your plugin
86 | │ └─── /framework # Any xcode cocoa frameworks you want to load into your plugin
87 | │ └─── /plugin # The plugins JS source code
88 | │ │ └─── index.js # By default, this will be used to bundle your production plugin.js file
89 | │ └─── /webview # The source for possible web views
90 | │
91 | └─── package.json # By default, the version of your package.json will be copied into the plugins manifest.json
92 | ```
93 |
94 | ## Documentation
95 |
96 | *In progress*
97 |
98 | ## Roadmap / Todos
99 |
100 | - [ ] Create useful documentation (integrated into a simple github.io page)
101 | - [ ] Create tutorials for JS developers to get started with Sketch plugins
102 | - [x] ~~Implement testing ([Jest](https://facebook.github.io/jest/)?)~~ *- Note: using [sketchtool](https://www.sketchapp.com/tool/) for accessing Sketch files and running plugin commands, however using own util functions, since the [node package](https://github.com/marekhrabe/sketchtool) does not seem to be maintained anymore (currently at version 39.x)*
103 | - [x] ~~Migrate the webview build from webpack to rollup, so we only have one build system to care about~~
104 | - [ ] Re-Implement `fetch` polyfill (see master before merge for old solution with cocoa framework and plugin action handler)
105 | - [x] ~~Try to get rid of cocoa framework if feasable~~
106 |
107 | ## About Testing
108 |
109 | Testing is a bit of a question mark for Sketch plugins at the moment, as it's not that easy to unit test your plugin commands in the Sketch enviroment. I am currently working on a util library / plugin that lets you run and test Sketch commands with Jest or any similar JS unit testing framework. If you are interested, just hit me up, happy to share my progress on this and collaborate.
--------------------------------------------------------------------------------
/__tests__/sketchtool.test.js:
--------------------------------------------------------------------------------
1 | var sketchtool = require('../scripts/utils/sketchtool');
2 |
3 | var testFilePath = '__tests__/test.sketch';
4 |
5 | if (!sketchtool.check()) {
6 | process.exit(1);
7 | }
8 |
9 | describe('Check if sketchtool is set up correctly', () => {
10 | test('Can execute sketchtool', () => {
11 | expect(sketchtool.exec('help')).toBeTruthy();
12 | });
13 |
14 | test('Sketch version can be retrieved', () => {
15 | var version = sketchtool.getVersion();
16 | expect(version).toBeTruthy();
17 | });
18 |
19 | test('Can dump load sketch files', () => {
20 | var json = sketchtool.loadFile(testFilePath);
21 | });
22 |
23 | test('Can read dumped json', () => {
24 | var json = sketchtool.loadFile(testFilePath);
25 | expect(json.objectID).toBeTruthy();
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/__tests__/test.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/julianburr/sketch-plugin-boilerplate/070d3e0e1363f8f2fe2a6e99ca7f9eff85e085e0/__tests__/test.sketch
--------------------------------------------------------------------------------
/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 | plugins: [
38 | new webpack.IgnorePlugin(/^sketch\/[a-z]+$/),
39 | new webpack.IgnorePlugin(/^sketch$/)
40 | ]
41 | };
42 |
--------------------------------------------------------------------------------
/config/webview/babel.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['react-app'],
3 | plugins: [
4 | 'transform-object-rest-spread',
5 | 'transform-decorators-legacy',
6 | ['module-resolver', {
7 | alias: {
8 | webview: './src/webview',
9 | components: './src/webview/js/components',
10 | actions: './src/webview/js/actions',
11 | reducers: './src/webview/js/reducers',
12 | utils: './src/webview/js/utils',
13 | assets: './src/webview/assets',
14 | styles: './src/webview/scss'
15 | }
16 | }]
17 | ],
18 | cacheDirectory: true
19 | }
20 |
--------------------------------------------------------------------------------
/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