Skip to content

Commit 690b0a3

Browse files
committed
Merge branch 'dev' into persistence
2 parents 5ff00cf + 9f1271b commit 690b0a3

13 files changed

+148
-98
lines changed

Diff for: CONTRIBUTING.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ As of Dash 1.2, the renderer bundle and its peer dependencies can be packed and
3838
3. `renderer bundles` parses the locked version JSON, copies all the peer dependencies into dash_renderer folder, bundles the renderer assets, and generates an `__init__.py` to map all the resources. There are also a list of helpful `scripts` property defined in `package.json` you might need to do some handy tasks like linting, syntax format with prettier, etc.
3939
4. `renderer digest` computes the content hash of each asset in `dash_renderer` folder, prints out the result in logs, and dumps into a JSON file `digest.json`. Use this when you have a doubt about the current assets in `dash_renderer`, and compare it with previous result in one shot by this command.
4040
5. `renderer build` runs 1, 2, 3, 4 in sequence as a complete build process from scratch.
41-
6. `renderer watch` runs the webpack in watch mode, so any source code change triggers a rebuild. Use this if you are actively updating renderer code and you want to test your changes immediately.
41+
6. `renderer build local` runs the same order as in 5 and also generates source maps for debugging purposes. You also need to install dash-renderer with editable mode: `pip install -e .`.
4242

4343
When a change in renderer code doesn't reflect in your browser as expected, this could be: confused bundle generation, caching issue in a browser, python package not in `editable` mode, etc. The new tool reduces the risk of bundle assets by adding the digest to help compare asset changes.
4444

Diff for: dash-renderer/CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## Unreleased
6+
7+
### Fixed
8+
- Reduced about 55% of the dash-renderer packages size on **PyPI** by removing the source maps. To do more advanced debugging, the source maps needs to be generated from source code with `npm run build:local` and pip install in editable mode, i.e. `pip install -e .` [#910](https://github.com/plotly/dash/pull/910)
9+
510
## [1.0.1] - 2019-08-27
611
- Clean all the binary assets in dash-renderer repo, add tool to build all the required bundles from fresh source code to avoid confusion of the assets and improve the release process. [#874](https://github.com/plotly/dash/pull/874)
712

Diff for: dash-renderer/init.template

-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ _js_dist = [
4545
{
4646
"relative_package_path": "{}.min.js.map".format(__name__),
4747
"dev_package_path": "{}.dev.js.map".format(__name__),
48-
"external_url": "https://unpkg.com/dash-renderer@$version"
49-
"/dash_renderer/dash_renderer.min.js.map",
5048
"namespace": "dash_renderer",
5149
"dynamic": True,
5250
},

Diff for: dash-renderer/package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
"scripts": {
77
"lint": "./node_modules/.bin/eslint --quiet --fix .",
88
"lint:test": "./node_modules/.bin/eslint .",
9-
"build:js": "webpack --mode development && webpack --mode production",
10-
"build:dev": "webpack --mode development --watch",
9+
"build:js": "webpack --build release",
10+
"build:dev": "webpack --build local",
11+
"build:local": "renderer build local",
1112
"build": "renderer build",
1213
"start": "webpack-serve ./webpack.serve.config.js",
1314
"format": "prettier --config .prettierrc --write \"src/**/*.js\"",

Diff for: dash-renderer/webpack.config.js

+75-78
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,84 @@
11
const webpack = require('webpack');
2+
const R = require('ramda');
23
const path = require('path');
34
const packagejson = require('./package.json');
4-
55
const dashLibraryName = packagejson.name.replace(/-/g, '_');
66

7-
module.exports = (env, argv) => {
8-
let mode;
9-
10-
// if user specified mode flag take that value
11-
if (argv && argv.mode) {
12-
mode = argv.mode;
13-
}
14-
15-
// else if configuration object is already set (module.exports) use that value
16-
else if (module.exports && module.exports.mode) {
17-
mode = module.exports = mode;
18-
}
19-
20-
// else take webpack default
21-
else {
22-
mode = 'production';
23-
}
24-
return {
25-
entry: {main: ['@babel/polyfill', 'whatwg-fetch', './src/index.js']},
26-
output: {
27-
path: path.resolve(__dirname, dashLibraryName),
28-
filename:
29-
mode === 'development'
30-
? `${dashLibraryName}.dev.js`
31-
: `${dashLibraryName}.min.js`,
32-
library: dashLibraryName,
33-
libraryTarget: 'window',
34-
},
35-
devtool: 'source-map',
36-
externals: {
37-
react: 'React',
38-
'react-dom': 'ReactDOM',
39-
'plotly.js': 'Plotly',
40-
'prop-types': 'PropTypes'
41-
},
42-
module: {
43-
rules: [
44-
{
45-
test: /\.js$/,
46-
exclude: /node_modules/,
47-
use: {
48-
loader: 'babel-loader',
49-
},
50-
},
51-
{
52-
test: /\.css$/,
53-
use: [
54-
{
55-
loader: 'style-loader',
56-
},
57-
{
58-
loader: 'css-loader',
59-
},
60-
],
7+
const defaultOptions = {
8+
mode: 'development',
9+
devtool: 'none',
10+
entry: {
11+
main: ['@babel/polyfill', 'whatwg-fetch', './src/index.js'],
12+
},
13+
output: {
14+
path: path.resolve(__dirname, dashLibraryName),
15+
filename: `${dashLibraryName}.dev.js`,
16+
library: dashLibraryName,
17+
libraryTarget: 'window',
18+
},
19+
externals: {
20+
react: 'React',
21+
'react-dom': 'ReactDOM',
22+
'plotly.js': 'Plotly',
23+
'prop-types': 'PropTypes',
24+
},
25+
plugins: [],
26+
module: {
27+
rules: [
28+
{
29+
test: /\.js$/,
30+
exclude: /node_modules/,
31+
use: {
32+
loader: 'babel-loader',
6133
},
62-
{
63-
test: /\.svg$/,
64-
use: ['@svgr/webpack']
65-
},
66-
{
67-
test: /\.txt$/i,
68-
use: 'raw-loader',
34+
},
35+
{
36+
test: /\.css$/,
37+
use: [
38+
{
39+
loader: 'style-loader',
40+
},
41+
{
42+
loader: 'css-loader',
43+
},
44+
],
45+
},
46+
{
47+
test: /\.svg$/,
48+
use: ['@svgr/webpack'],
49+
},
50+
{
51+
test: /\.txt$/i,
52+
use: 'raw-loader',
53+
},
54+
],
55+
},
56+
};
6957

58+
module.exports = (_, argv) => {
59+
const devtool = argv.build === 'local' ? 'source-map' : 'none';
60+
return [
61+
R.mergeDeepLeft({devtool}, defaultOptions),
62+
R.mergeDeepLeft(
63+
{
64+
devtool: devtool,
65+
mode: 'production',
66+
output: {
67+
filename: `${dashLibraryName}.min.js`,
7068
},
71-
],
72-
},
73-
plugins: [
74-
new webpack.NormalModuleReplacementPlugin(
75-
/(.*)GlobalErrorContainer.react(\.*)/,
76-
function(resource) {
77-
if (mode === 'production') {
78-
resource.request = resource.request.replace(
79-
/GlobalErrorContainer.react/,
80-
'GlobalErrorContainerPassthrough.react'
81-
);
82-
}
83-
}
84-
),
85-
],
86-
};
69+
plugins: [
70+
new webpack.NormalModuleReplacementPlugin(
71+
/(.*)GlobalErrorContainer.react(\.*)/,
72+
function(resource) {
73+
resource.request = resource.request.replace(
74+
/GlobalErrorContainer.react/,
75+
'GlobalErrorContainerPassthrough.react'
76+
);
77+
}
78+
),
79+
],
80+
},
81+
defaultOptions
82+
),
83+
];
8784
};

Diff for: dash/CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
## Unreleased
22

3+
### Added
4+
5+
- [#918](https://github.com/plotly/dash/pull/918) Adds `wait_for_element_by_id` and `visit_and_snapshot` APIs in browser, adds `raw_command` option (it also has higher priority than
6+
the default waitress one) and optional `start_timeout` argument to handle large application within process runner
7+
38
### Fixed
49

10+
- [#915](https://github.com/plotly/dash/issues/915) Fixes `dash-generate-components` on Windows
511
- [#829](https://github.com/plotly/dash/issues/829) Fixes the `--remote` pytest argument which was not effective in the code, adding a new argument `--remote-url` to support the selenium grid usage in the cloud.
612

713
## [1.2.0] - 2019-08-27

Diff for: dash/dash.py

+1
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ def layout(self, value):
441441
'or a function that returns '
442442
'a dash component.')
443443

444+
self._cached_layout = None
444445
self._layout = value
445446

446447
@property

Diff for: dash/development/build_process.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@ def watch(self):
7777
os.system("npm run build:dev")
7878

7979
@job("run the whole building process in sequence")
80-
def build(self):
80+
def build(self, build=None):
8181
self.clean()
8282
self.npm()
83-
self.bundles()
83+
self.bundles(build)
8484
self.digest()
8585

8686
@job("compute the hash digest for assets")
@@ -108,7 +108,7 @@ def digest(self):
108108
)
109109

110110
@job("copy and generate the bundles")
111-
def bundles(self):
111+
def bundles(self, build=None):
112112
if not os.path.exists(self.build_folder):
113113
try:
114114
os.makedirs(self.build_folder)
@@ -142,9 +142,10 @@ def bundles(self):
142142
self._concat(self.build_folder, target),
143143
)
144144

145-
logger.info("run `npm run build:js`")
145+
_script = 'build:dev' if build == 'local' else 'build:js'
146+
logger.info("run `npm run %s`", _script)
146147
os.chdir(self.main)
147-
run_command_with_process("npm run build:js")
148+
run_command_with_process("npm run {}".format(_script))
148149

149150
logger.info("generate the `__init__.py` from template and verisons")
150151
with open(self._concat(self.main, "init.template")) as fp:

Diff for: dash/development/component_generator.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,9 @@ def generate_components(
5858
reserved_patterns = "|".join("^{}$".format(p) for p in reserved_words)
5959

6060
os.environ["NODE_PATH"] = "node_modules"
61+
6162
cmd = shlex.split(
62-
"node {} {} {} {}".format(
63+
'node {} "{}" "{}" {}'.format(
6364
extract_path, ignore, reserved_patterns, components_source
6465
),
6566
posix=not is_windows,

Diff for: dash/extract-meta.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const path = require('path');
55
const reactDocs = require('react-docgen');
66

77
const componentPaths = process.argv.slice(4);
8-
const ignorePattern = new RegExp(process.argv[2]);
8+
const ignorePattern = new RegExp(process.argv[2].split('"').join(''));
99
const reservedPatterns = process.argv[3].split('|').map(part => new RegExp(part));
1010

1111
let failed = false;

Diff for: dash/testing/application_runners.py

+23-7
Original file line numberDiff line numberDiff line change
@@ -179,23 +179,39 @@ def __init__(self, keep_open=False, stop_timeout=3):
179179
self.proc = None
180180

181181
# pylint: disable=arguments-differ
182-
def start(self, app_module, application_name="app", port=8050):
182+
def start(
183+
self,
184+
app_module=None,
185+
application_name="app",
186+
raw_command=None,
187+
port=8050,
188+
start_timeout=3,
189+
):
183190
"""Start the server with waitress-serve in process flavor """
184-
entrypoint = "{}:{}.server".format(app_module, application_name)
191+
if not (app_module or raw_command): # need to set a least one
192+
logging.error(
193+
"the process runner needs to start with"
194+
" at least one valid command"
195+
)
196+
return
185197
self.port = port
186-
187198
args = shlex.split(
188-
"waitress-serve --listen=0.0.0.0:{} {}".format(port, entrypoint),
199+
raw_command
200+
if raw_command
201+
else "waitress-serve --listen=0.0.0.0:{} {}:{}.server".format(
202+
port, app_module, application_name
203+
),
189204
posix=not self.is_windows,
190205
)
206+
191207
logger.debug("start dash process with %s", args)
192208

193209
try:
194210
self.proc = subprocess.Popen(
195211
args, stdout=subprocess.PIPE, stderr=subprocess.PIPE
196212
)
197213
# wait until server is able to answer http request
198-
wait.until(lambda: self.accessible(self.url), timeout=3)
214+
wait.until(lambda: self.accessible(self.url), timeout=start_timeout)
199215

200216
except (OSError, ValueError):
201217
logger.exception("process server has encountered an error")
@@ -233,7 +249,7 @@ def __init__(self, keep_open=False, stop_timeout=3):
233249
self.proc = None
234250

235251
# pylint: disable=arguments-differ
236-
def start(self, app):
252+
def start(self, app, start_timeout=2):
237253
"""Start the server with waitress-serve in process flavor """
238254

239255
# app is a R string chunk
@@ -267,7 +283,7 @@ def start(self, app):
267283
args, stdout=subprocess.PIPE, stderr=subprocess.PIPE
268284
)
269285
# wait until server is able to answer http request
270-
wait.until(lambda: self.accessible(self.url), timeout=2)
286+
wait.until(lambda: self.accessible(self.url), timeout=start_timeout)
271287

272288
except (OSError, ValueError):
273289
logger.exception("process server has encountered an error")

Diff for: dash/testing/browser.py

+24
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,20 @@ def wait_for_element_by_css_selector(self, selector, timeout=None):
173173
),
174174
)
175175

176+
def wait_for_element_by_id(self, element_id, timeout=None):
177+
"""explicit wait until the element is present,
178+
timeout if not set, equals to the fixture's `wait_timeout`
179+
shortcut to `WebDriverWait` with `EC.presence_of_element_located`
180+
"""
181+
return self._wait_for(
182+
EC.presence_of_element_located,
183+
((By.ID, element_id),),
184+
timeout,
185+
"timeout {}s => waiting for element id {}".format(
186+
timeout if timeout else self._wait_timeout, element_id
187+
),
188+
)
189+
176190
def wait_for_style_to_equal(self, selector, style, val, timeout=None):
177191
"""explicit wait until the element's style has expected `value`
178192
timeout if not set, equals to the fixture's `wait_timeout`
@@ -433,6 +447,16 @@ def reset_log_timestamp(self):
433447
if entries:
434448
self._last_ts = entries[-1]["timestamp"]
435449

450+
def visit_and_snapshot(self, resource_path, hook_id):
451+
try:
452+
self.driver.get(self.server_url + resource_path)
453+
self.wait_for_element_by_id(hook_id)
454+
self.percy_snapshot(resource_path)
455+
self.driver.back()
456+
except WebDriverException as e:
457+
logger.exception("snapshot at resource %s error", resource_path)
458+
raise e
459+
436460
@property
437461
def driver(self):
438462
"""expose the selenium webdriver as fixture property"""

Diff for: tests/unit/test_app_runners.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def test_threaded_server_smoke(dash_thread_server):
2525
sys.version_info < (3,), reason="requires python3 for process testing"
2626
)
2727
def test_process_server_smoke(dash_process_server):
28-
dash_process_server("simple_app")
28+
dash_process_server('simple_app')
2929
r = requests.get(dash_process_server.url)
3030
assert r.status_code == 200, "the server is reachable"
3131
assert 'id="react-entry-point"' in r.text, "the entrypoint is present"

0 commit comments

Comments
 (0)