contributing.rst 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142
  1. Contributing to JupyterLab
  2. ==========================
  3. If you're reading this section, you're probably interested in
  4. contributing to JupyterLab. Welcome and thanks for your interest in
  5. contributing!
  6. Please take a look at the Contributor documentation, familiarize
  7. yourself with using JupyterLab, and introduce yourself to the community
  8. (on the mailing list or discourse) and share what area of the project
  9. you are interested in working on. Please also see the Jupyter `Community
  10. Guides <https://jupyter.readthedocs.io/en/latest/community/content-community.html>`__.
  11. We have labeled some issues as `good first
  12. issue <https://github.com/jupyterlab/jupyterlab/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22>`__
  13. or `help
  14. wanted <https://github.com/jupyterlab/jupyterlab/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22>`__
  15. that we believe are good examples of small, self-contained changes. We
  16. encourage those that are new to the code base to implement and/or ask
  17. questions about these issues. You are not required to ask for a permission
  18. to work on such issue, but if you do and do not get a reply within 48 hours
  19. please assume that no one else is working on it (even if someone previously
  20. volunteered) and open a pull request with proposed implementation.
  21. If you are not certain about the implementation, using draft pull requests is encouraged.
  22. If you believe you’ve found a security vulnerability in JupyterLab or
  23. any Jupyter project, please report it to security@ipython.org. If you
  24. prefer to encrypt your security reports, you can use `this PGP public
  25. key <https://raw.githubusercontent.com/jupyter/notebook/master/docs/source/ipython_security.asc>`__.
  26. .. contents:: Table of contents
  27. :local:
  28. :depth: 1
  29. General Guidelines for Contributing
  30. -----------------------------------
  31. For general documentation about contributing to Jupyter projects, see
  32. the `Project Jupyter Contributor
  33. Documentation <https://jupyter.readthedocs.io/en/latest/contributing/content-contributor.html>`__
  34. and `Code of
  35. Conduct <https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md>`__.
  36. All source code is written in
  37. `TypeScript <https://www.typescriptlang.org/Handbook>`__. See the `Style
  38. Guide <https://github.com/jupyterlab/jupyterlab/wiki/TypeScript-Style-Guide>`__.
  39. All source code is formatted using `prettier <https://prettier.io>`__.
  40. When code is modified and committed, all staged files will be
  41. automatically formatted using pre-commit git hooks (with help from the
  42. `lint-staged <https://github.com/okonet/lint-staged>`__ and
  43. `husky <https://github.com/typicode/husky>`__ libraries). The benefit of
  44. using a code formatter like prettier is that it removes the topic of
  45. code style from the conversation when reviewing pull requests, thereby
  46. speeding up the review process.
  47. You may also use the prettier npm script (e.g. ``npm run prettier`` or
  48. ``yarn prettier`` or ``jlpm prettier``) to format the entire code base.
  49. We recommend installing a prettier extension for your code editor and
  50. configuring it to format your code with a keyboard shortcut or
  51. automatically on save.
  52. Submitting a Pull Request Contribution
  53. --------------------------------------
  54. Generally, an issue should be opened describing a piece of proposed work
  55. and the issues it solves before a pull request is opened. A triager will
  56. ensure that your issue meets our definition of ready before we can merge
  57. any pull requests that relate to it.
  58. Issue Management
  59. ^^^^^^^^^^^^^^^^
  60. Opening an issue lets community members participate in the design
  61. discussion, makes others aware of work being done, and sets the stage
  62. for a fruitful community interaction. When you open a new bug or
  63. enhancement request, please provide all the requested information
  64. in the issue template
  65. so that a responder will be able to triage your bug without delay.
  66. A pull request should reference
  67. the issue it is addressing. Once the pull request is merged, the issue
  68. related to it will also be closed. If there is additional discussion
  69. around implementation the issue may be re-opened. Once 30 days have
  70. passed with no additional discussion, the `lock
  71. bot <https://github.com/apps/lock>`__ will lock the issue. If additional
  72. discussion is desired, or if the pull request doesn't fully address the
  73. locked issue, please open a new issue referencing the locked issue.
  74. New issues are subject to triage. A developer with triage permissions
  75. (a *triager*) will do the following:
  76. 1. Read the issue
  77. 2. Search the existing issues and mark it as a duplicate if necessary
  78. 3. If additional information is required, add a comment requesting it
  79. 4. If the issue is ready to be worked on, assign it to a milestone
  80. 5. Apply appropriate labels to the issue (see examples below)
  81. A developer may start to work on an issue as soon as it is filed. Please
  82. work with a triager if they have any questions about your issue so that
  83. your changes can be merged in without delay.
  84. Definition of Ready
  85. ^^^^^^^^^^^^^^^^^^^
  86. One of the main goals of triage is to get issues into a state where they
  87. are **ready** for someone to work on. Once a triager is satisfied that an
  88. issue meets the definition below, they will remove the ``status:Needs Triage``
  89. label from it. We will not merge a pull request for an issue that still
  90. needs triage.
  91. Triagers should also ensure that the issue has appropriate labels that
  92. describe it, such as labels with the ``pkg:`` prefix for issues that
  93. affect one or more packages.
  94. **All requested information, where applicable, is provided.** From the
  95. templates in JupyterLab’s issues:
  96. For a **bug**:
  97. * Description, preferably including screen shots
  98. * Steps to reproduce
  99. * Expected behavior
  100. * Context, such as OS, browser, JupyterLab version, and output or log excerpts
  101. For a **feature request**:
  102. * Description of the problem
  103. * Description of the proposed solution
  104. * Additional context
  105. **The issue should represent real, relevant, feasible work**. In short, if a
  106. knowledgeable person were to be assigned this issue, they would be able to
  107. complete it with a reasonable amount of effort and assistance, and it
  108. furthers the goals of the Jupyter project.
  109. * Issues should be unique; triage is the best time to identify duplicates.
  110. * Bugs represent valid expectations for use of Jupyter products and services.
  111. * Expectations for security, performance, accessibility, and localization match
  112. generally-accepted norms in the community that uses Jupyter products.
  113. * The issue represents work that one developer can commit to owning, even if
  114. they collaborate with other developers for feedback. Excessively large issues
  115. should be split into multiple issues, each triaged individually, or into
  116. `team-compass <https://github.com/jupyterlab/team-compass>`__ issues to discuss
  117. more substantive changes.
  118. Labels Used by Triagers
  119. ^^^^^^^^^^^^^^^^^^^^^^^
  120. All new bugs and enhancement requests have the ``status:Needs Triage`` label.
  121. On a regular basis, Jupyter contributors (triage reviewers or triagers)
  122. review JupyterLab issues tagged
  123. with ``status:Needs Triage``, starting with the oldest, and determine
  124. whether they meet the definition of ready.
  125. Once triaged, if the issue is ready, the reviewer removes the
  126. ``status:Needs Triage`` label; no additional label is required. If there
  127. is not enough information in the issue as filed, the triage reviewer applies
  128. the ``status:Needs Info`` label and leaves ``status:Needs Triage`` in place.
  129. If an issue has remained in ``status:Needs Info`` for more than 14 days
  130. without any follow-up communication, the reviewer should apply
  131. ``status:Blocked``. A blocked issue should be closed after another 14 days
  132. pass without a reply that unblocks it.
  133. Our expectation is that every new issue should be examined within a week of
  134. its creation.
  135. Tagging Issues with Labels
  136. ^^^^^^^^^^^^^^^^^^^^^^^^^^
  137. Users without the commit rights to the JupyterLab repository can tag
  138. issues with labels using the ``@meeseeksdev`` bot. For example: To apply
  139. the label ``foo`` and ``bar baz`` to an issue, comment
  140. ``@meeseeksdev tag foo "bar baz"`` on the issue.
  141. Contributing from within the browser
  142. ------------------------------------
  143. Using the https://github.com web interface - documented
  144. `here <https://docs.github.com/en/free-pro-team@latest/github>`__ - you
  145. can create and propose a change purely within your browser.
  146. Using `Binder <https://mybinder.org>`__, you can test the current master branch and your
  147. changes within the browser as well. We recommend you have at least 8 GB of RAM for this.
  148. To build and launch an instance of the latest JupyterLab master, open
  149. `this link <https://mybinder.org/v2/gh/jupyterlab/jupyterlab/master?urlpath=lab-dev/>`__
  150. in a new tab. The build takes about 7 minutes to complete.
  151. To test your own branch hosted on GitHub, enter it on https://mybinder.org.
  152. If everything goes right, filling out the form takes about 2 minutes, and the build should take
  153. about 7 minutes again.
  154. Setting up a local development environment
  155. ------------------------------------------
  156. This section explains how to set up a local development environment. We assume you use GNU/Linux,
  157. Mac OS X, or Windows Subsystem for Linux.
  158. Installing Node.js and jlpm
  159. ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  160. Building JupyterLab from its GitHub source code requires Node.js. The
  161. development version requires Node.js version 12+, as defined in the
  162. ``engines`` specification in
  163. `dev_mode/package.json <https://github.com/jupyterlab/jupyterlab/blob/3.4.x/dev_mode/package.json>`__.
  164. If you use ``conda``, you can get it with:
  165. .. code:: bash
  166. conda install -c conda-forge 'nodejs'
  167. If you use `Homebrew <https://brew.sh>`__ on Mac OS X:
  168. .. code:: bash
  169. brew install node
  170. You can also use the installer from the `Node.js <https://nodejs.org>`__
  171. website.
  172. To check which version of Node.js is installed:
  173. .. code:: bash
  174. node -v
  175. Installing JupyterLab
  176. ---------------------
  177. If you use ``conda``, you may also want to install ``nb_conda_kernels`` to have a kernel
  178. option for different `conda
  179. environments <https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html>`__
  180. .. code:: bash
  181. conda install -c conda-forge nb_conda_kernels
  182. Fork the JupyterLab
  183. `repository <https://github.com/jupyterlab/jupyterlab>`__.
  184. Then use the following steps:
  185. .. code:: bash
  186. git clone https://github.com/<your-github-username>/jupyterlab.git
  187. cd jupyterlab
  188. pip install -e .
  189. jlpm install
  190. jlpm run build # Build the dev mode assets (optional)
  191. jlpm run build:core # Build the core mode assets (optional)
  192. jupyter lab build # Build the app dir assets (optional)
  193. Notes:
  194. - A few of the scripts will run "python". If your target python is
  195. called something else (such as "python3") then parts of the build
  196. will fail. You may wish to build in a conda environment, or make an
  197. alias.
  198. - Some of the packages used in the development environment require
  199. Python 3.0 or higher. If you encounter an ImportError during the
  200. installation, make sure Python 3.0+ is installed. Also, try using the
  201. Python 3.0+ version of ``pip`` or ``pip3 install -e .`` command to
  202. install JupyterLab from the forked repository.
  203. - If you see an error that says ``Call to 'pkg-config pixman-1 --libs'
  204. returned exit status 127 while in binding.gyp`` while running the
  205. ``pip install`` command above, you may be missing packages required
  206. by ``canvas``. On macOS with Homebrew, you can add these packages by
  207. running
  208. ``brew install pkg-config cairo pango libpng jpeg giflib librsvg``.
  209. If you are using mamba or conda, you can install the necessary packages
  210. with `conda install -c conda-forge pkg-config glib pango pixman`.
  211. - The ``jlpm`` command is a JupyterLab-provided, locked version of the
  212. `yarn <https://classic.yarnpkg.com/en/>`__ package manager. If you have
  213. ``yarn`` installed already, you can use the ``yarn`` command when
  214. developing, and it will use the local version of ``yarn`` in
  215. ``jupyterlab/yarn.js`` when run in the repository or a built
  216. application directory.
  217. - If you decide to use the ``jlpm`` command and encounter the
  218. ``jlpm: command not found`` error, try adding the user-level bin
  219. directory to your ``PATH`` environment variable. You already
  220. installed ``jlpm`` along with JupyterLab in the previous command, but
  221. ``jlpm`` might not be accessible due to ``PATH`` environment variable
  222. related issues. If you are using a Unix derivative (FreeBSD, GNU /
  223. Linux, OS X), you can achieve this by using
  224. ``export PATH="$HOME/.local/bin:$PATH"`` command.
  225. - At times, it may be necessary to clean your local repo with the
  226. command ``npm run clean:slate``. This will clean the repository, and
  227. re-install and rebuild.
  228. - If ``pip`` gives a ``VersionConflict`` error, it usually means that
  229. the installed version of ``jupyterlab_server`` is out of date. Run
  230. ``pip install --upgrade jupyterlab_server`` to get the latest
  231. version.
  232. - To install JupyterLab in isolation for a single conda/virtual
  233. environment, you can add the ``--sys-prefix`` flag to the extension
  234. activation above; this will tie the installation to the
  235. ``sys.prefix`` location of your environment, without writing anything
  236. in your user-wide settings area (which are visible to all your envs):
  237. - You can run ``jlpm run build:dev:prod`` to build more accurate
  238. sourcemaps that show the original Typescript code when debugging.
  239. However, it takes a bit longer to build the sources, so is used only
  240. to build for production by default.
  241. If you are using a version of Jupyter Notebook earlier than 5.3, then
  242. you must also run the following command to enable the JupyterLab server
  243. extension:
  244. .. code:: bash
  245. jupyter serverextension enable --py --sys-prefix jupyterlab
  246. For installation instructions to write documentation, please see
  247. `Writing Documentation <#writing-documentation>`__
  248. Run JupyterLab
  249. ^^^^^^^^^^^^^^
  250. Start JupyterLab in development mode:
  251. .. code:: bash
  252. jupyter lab --dev-mode
  253. Development mode ensures that you are running the JavaScript assets that
  254. are built in the dev-installed Python package. Note that when running in
  255. dev mode, extensions will not be activated by default - refer
  256. :ref:`documentation on extension development <prebuilt_dev_workflow>` to know more.
  257. When running in dev mode, a red stripe will appear at the top of the
  258. page; this is to indicate running an unreleased version.
  259. If you want to change the TypeScript code and rebuild on the fly
  260. (needs page refresh after each rebuild):
  261. .. code:: bash
  262. jupyter lab --dev-mode --watch
  263. Build and Run the Tests
  264. ^^^^^^^^^^^^^^^^^^^^^^^
  265. .. code:: bash
  266. jlpm run build:testutils
  267. jlpm test
  268. You can run tests for an individual package by changing to the
  269. appropriate package folder:
  270. .. code:: bash
  271. cd packages/notebook
  272. jlpm run build:test
  273. jlpm test
  274. We use ``jest`` for all tests, so standard ``jest`` workflows apply.
  275. Tests can be debugged in either VSCode or Chrome. It can help to add an
  276. ``it.only`` to a specific test when debugging. All of the ``test*``
  277. scripts in each package accept ``jest`` `cli
  278. options <https://jestjs.io/docs/cli>`__.
  279. VSCode Debugging
  280. """"""""""""""""
  281. To debug in VSCode, open a package folder in VSCode. We provide a launch
  282. configuration in each package folder. In a terminal, run
  283. ``jlpm test:debug:watch``. In VSCode, select "Attach to Jest" from the
  284. "Run" sidebar to begin debugging. See `VSCode docs on
  285. debugging <https://code.visualstudio.com/docs/editor/debugging>`__ for
  286. more details.
  287. Chrome Debugging
  288. """"""""""""""""
  289. To debug in Chrome, run ``jlpm test:debug:watch`` in the terminal. Open
  290. Chrome and go to ``chrome://inspect/``. Select the remote device and
  291. begin debugging.
  292. Testing Utilities
  293. """""""""""""""""
  294. There are some helper functions in ``testutils`` (which is a public npm
  295. package called ``@jupyterlab/testutils``) that are used by many of the
  296. tests.
  297. For tests that rely on ``@jupyterlab/services`` (starting kernels,
  298. interacting with files, etc.), there are two options. If a simple
  299. interaction is needed, the ``Mock`` namespace exposed by ``testutils``
  300. has a number of mock implementations (see ``testutils/src/mock.ts``). If
  301. a full server interaction is required, use the ``JupyterServer`` class.
  302. We have a helper function called ``testEmission`` to help with writing
  303. tests that use ``Lumino`` signals, as well as a ``framePromise``
  304. function to get a ``Promise`` for a ``requestAnimationFrame``. We
  305. sometimes have to set a sentinel value inside a ``Promise`` and then
  306. check that the sentinel was set if we need a promise to run without
  307. blocking.
  308. Internationalization
  309. --------------------
  310. Translatable strings update
  311. ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  312. The translatable strings update cannot occur on patch release. They
  313. must be delayed on minor or major versions.
  314. Performance Testing
  315. -------------------
  316. If you are making a change that might affect how long it takes to load
  317. JupyterLab in the browser, we recommend doing some performance testing
  318. using `Lighthouse <https://github.com/GoogleChrome/lighthouse>`__. It
  319. let's you easily compute a number of metrics, like page load time, for
  320. the site.
  321. To use it, first build JupyterLab in dev mode:
  322. .. code:: bash
  323. jlpm run build:dev
  324. Then, start JupyterLab using the dev build:
  325. .. code:: bash
  326. jupyter lab --dev-mode --NotebookApp.token='' --no-browser
  327. Now run Lighthouse against this local server and show the results:
  328. .. code:: bash
  329. jlpm run lighthouse --view
  330. .. image:: ../images/lighthouse.png
  331. Using throttling
  332. ^^^^^^^^^^^^^^^^
  333. Lighthouse recommends using the system level
  334. `comcast <https://github.com/tylertreat/comcast>`__ tool to throttle
  335. your network connection and emulate different scenarios. To use it,
  336. first install that tool using ``go``:
  337. .. code:: bash
  338. go get github.com/tylertreat/comcast
  339. Then, before you run Lighthouse, enable the throttling (this requires
  340. sudo):
  341. .. code:: bash
  342. run lighthouse:throttling:start
  343. This enables the "WIFI (good)" preset of comcast, which should emulate
  344. loading JupyterLab over a local network.
  345. Then run the lighthouse tests:
  346. .. code:: bash
  347. jlpm run lighthouse [...]
  348. Then disable the throttling after you are done:
  349. .. code:: bash
  350. jlpm run lighthouse:throttling:stop
  351. Comparing results
  352. ^^^^^^^^^^^^^^^^^
  353. Performance results are usually only useful in comparison to other
  354. results. For that reason, we have included a comparison script that can
  355. take two lighthouse results and show the changes between them.
  356. Let's say we want to compare the results of the production build of
  357. JupyterLab with the normal build. The production build minifies all the
  358. JavaScript, so should load a bit faster.
  359. First, we build JupyterLab normally, start it up, profile it and save
  360. the results:
  361. .. code:: bash
  362. jlpm build:dev
  363. jupyter lab --dev --NotebookApp.token='' --no-browser
  364. # in new window
  365. jlpm run lighthouse --output json --output-path normal.json
  366. Then rebuild with the production build and retest:
  367. .. code:: bash
  368. jlpm run build:dev:prod
  369. jupyter lab --dev --NotebookApp.token='' --no-browser
  370. # in new window
  371. jlpm run lighthouse --output json --output-path prod.json
  372. Now we can use compare the two outputs:
  373. .. code:: bash
  374. jlpm run lighthouse:compare normal.json prod.json
  375. This gives us a report of the relative differences between the audits in
  376. the two reports:
  377. .. admonition:: Resulting Output
  378. ``normal.json`` -> ``prod.json``
  379. | **First Contentful Paint**
  380. | - -62% Δ
  381. | - 1.9 s -> 0.7 s
  382. | - First Contentful Paint marks the time at which the first text or
  383. image is painted. `Learn
  384. more <https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint>`__.
  385. | **First Meaningful Paint**
  386. | - -50% Δ
  387. | - 2.5 s -> 1.3 s
  388. | - First Meaningful Paint measures when the primary content of a
  389. page is visible. `Learn
  390. more <https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint>`__.
  391. | **Speed Index**
  392. | - -48% Δ
  393. | - 2.6 s -> 1.3 s
  394. | - Speed Index shows how quickly the contents of a page are visibly
  395. populated. `Learn
  396. more <https://developers.google.com/web/tools/lighthouse/audits/speed-index>`__.
  397. | **Estimated Input Latency**
  398. | - 0% Δ
  399. | - 20 ms -> 20 ms
  400. | - Estimated Input Latency is an estimate of how long your app takes
  401. to respond to user input, in milliseconds, during the busiest 5s
  402. window of page load. If your latency is higher than 50 ms, users
  403. may perceive your app as laggy. `Learn
  404. more <https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency>`__.
  405. | **Max Potential First Input Delay**
  406. | - 9% Δ
  407. | - 200 ms -> 210 ms
  408. | - The maximum potential First Input Delay that your users could
  409. experience is the duration, in milliseconds, of the longest task.
  410. `Learn
  411. more <https://developers.google.com/web/updates/2018/05/first-input-delay>`__.
  412. | **First CPU Idle**
  413. | - -50% Δ
  414. | - 2.5 s -> 1.3 s
  415. | - First CPU Idle marks the first time at which the page's main
  416. thread is quiet enough to handle input. `Learn
  417. more <https://developers.google.com/web/tools/lighthouse/audits/first-interactive>`__.
  418. | **Time to Interactive**
  419. | - -52% Δ
  420. | - 2.5 s -> 1.2 s
  421. | - Time to interactive is the amount of time it takes for the page
  422. to become fully interactive. `Learn
  423. more <https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive>`__.
  424. | **Avoid multiple page redirects**
  425. | - -2% Δ
  426. | - Potential savings of 10 ms -> Potential savings of 10 ms
  427. | - Redirects introduce additional delays before the page can be
  428. loaded. `Learn
  429. more <https://developers.google.com/web/tools/lighthouse/audits/redirects>`__.
  430. | **Minimize main-thread work**
  431. | - -54% Δ
  432. | - 2.1 s -> 1.0 s
  433. | - Consider reducing the time spent parsing, compiling and executing
  434. JS. You may find delivering smaller JS payloads helps with this.
  435. | **JavaScript execution time**
  436. | - -49% Δ
  437. | - 1.1 s -> 0.6 s
  438. | - Consider reducing the time spent parsing, compiling, and
  439. executing JS. You may find delivering smaller JS payloads helps
  440. with this. `Learn
  441. more <https://developers.google.com/web/tools/lighthouse/audits/bootup>`__.
  442. | **Preload key requests**
  443. | - -100% Δ
  444. | - Potential savings of 240 ms ->
  445. | - Consider using <link rel=preload> to prioritize fetching
  446. resources that are currently requested later in page load. `Learn
  447. more <https://developers.google.com/web/tools/lighthouse/audits/preload>`__.
  448. | **Uses efficient cache policy on static assets**
  449. | - 0% Δ
  450. | - 1 resource found -> 1 resource found
  451. | - A long cache lifetime can speed up repeat visits to your page.
  452. `Learn
  453. more <https://developers.google.com/web/tools/lighthouse/audits/cache-policy>`__.
  454. | **Avoid enormous network payloads**
  455. | - -86% Δ
  456. | - Total size was 30,131 KB -> Total size was 4,294 KB
  457. | - Large network payloads cost users real money and are highly
  458. correlated with long load times. `Learn
  459. more <https://developers.google.com/web/tools/lighthouse/audits/network-payloads>`__.
  460. | **Minify JavaScript**
  461. | - -100% Δ
  462. | - Potential savings of 23,041 KB ->
  463. | - Minifying JavaScript files can reduce payload sizes and script
  464. parse time. `Learn
  465. more <https://developers.google.com/speed/docs/insights/MinifyResources>`__.
  466. | **Enable text compression**
  467. | - -86% Δ
  468. | - Potential savings of 23,088 KB -> Potential savings of 3,112 KB
  469. | - Text-based resources should be served with compression (gzip,
  470. deflate or brotli) to minimize total network bytes. `Learn
  471. more <https://developers.google.com/web/tools/lighthouse/audits/text-compression>`__.
  472. | **Avoid an excessive DOM size**
  473. | - 0% Δ
  474. | - 1,268 elements -> 1,268 elements
  475. | - Browser engineers recommend pages contain fewer than ~1,500 DOM
  476. elements. The sweet spot is a tree depth < 32 elements and fewer
  477. than 60 children/parent element. A large DOM can increase memory
  478. usage, cause longer `style
  479. calculations <https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations>`__,
  480. and produce costly `layout
  481. reflows <https://developers.google.com/speed/articles/reflow>`__.
  482. `Learn
  483. more <https://developers.google.com/web/tools/lighthouse/audits/dom-size>`__.
  484. Visual Regression and UI Tests
  485. ------------------------------
  486. As part of JupyterLab CI workflows, UI tests are run with visual regression checks. `Galata <https://github.com/jupyterlab/galata>`__ is used for UI testing. Galata provides a high level API to control and inspect JupyterLab UI programmatically, testing tools and CLI to manage tests and other tasks.
  487. UI tests are run for each commit into JupyterLab project in PRs or direct commits. Code changes can sometimes cause UI tests to fail for various reasons. After each test run, Galata generates a user friendly test result report which can be used to inspect failing UI tests. Result report shows the failure reason, call-stack up to the failure and detailed information on visual regression issues. For visual regression errors, reference image and test capture image, along with diff image generated during comparison are provided in the report. You can use these information to debug failing tests. Galata test report can be downloaded from GitHub Actions page for a UI test run. Test artifact is named ``ui-test-output`` and once you extract it, you can access the report by opening ``test/report/index.html`` in a browser window.
  488. Main reasons for UI test failures are:
  489. 1. **A visual regression caused by code changes**:
  490. Sometimes unintentional UI changes are introduced by modifications to project source code. Goal of visual regression testing is to detect this kind of UI changes. If your PR / commit is causing visual regression, then debug and fix the regression caused. You can locally run and debug the UI tests to fix the visual regression. Follow the instructions in steps 5-7 of ``Adding a new UI test suite guide`` in `UI Testing documentation <https://github.com/jupyterlab/jupyterlab/blob/3.4.x/galata/README.md#adding-a-new-ui-test-suite>`__ to locally debug and fix UI tests. Once you have a fix, you can push the change to your GitHub branch and test with GitHub actions.
  491. 2. **An intended update to user interface**:
  492. If your code change is introducing an update to UI which causes existing UI Tests to
  493. fail, then you will need to update reference image(s) for the failing tests. In order
  494. to do that, you can post a comment on your PR with the following content:
  495. - ``please update galata snapshots``: A bot will push a new commit to your PR updating galata
  496. test snaphsots.
  497. - ``please update snapshots``: Combine the two previous comments effects.
  498. For more information on UI Testing, please read the `UI Testing developer documentation <https://github.com/jupyterlab/jupyterlab/blob/3.4.x/galata/README.md>`__ and `Galata documentation <https://github.com/jupyterlab/galata/blob/main/README.md>`__.
  499. Good Practices for Integration tests
  500. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  501. Here are some good practices to follow when writing integration tests:
  502. - Don't compare multiple screenshots in the same test; if the first comparison breaks, it will require running multiple times the CI workflow to fix all tests.
  503. Contributing to the debugger front-end
  504. --------------------------------------
  505. To make changes to the debugger extension, a kernel with support for debugging is required.
  506. Check out the user documentation to learn how to install such kernel: :ref:`debugger`.
  507. Then refresh the page and the debugger sidebar should appear in the right area.
  508. The Debugger Adapter Protocol
  509. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  510. The following diagram illustrates the types of messages sent between the JupyterLab extension and the kernel.
  511. .. image:: ./debugger_protocol_diagram.png
  512. Inspecting Debug Messages in VS Code
  513. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  514. Inspecting the debug messages in VS Code can be useful to understand when debug requests are made (for example triggered by a UI action), and to compare the behavior of the JupyterLab debugger with the Python debugger in VS Code.
  515. The first step is to create a test file and a debug configuration (``launch.json``):
  516. .. image:: ./debugger_launch_configuration.png
  517. .. code:: json
  518. {
  519. "version": "0.2.0",
  520. "configurations": [
  521. {
  522. "name": "Python: Current File",
  523. "type": "python",
  524. "request": "launch",
  525. "program": "${file}",
  526. "console": "integratedTerminal",
  527. "env": { "DEBUGPY_LOG_DIR": "/path/to/logs/folder" }
  528. }
  529. ]
  530. }
  531. Then start the debugger:
  532. .. image:: ./debugger_vscode_start.png
  533. The content of the log file looks like this:
  534. .. code:: bash
  535. ...
  536. D00000.032: IDE --> {
  537. "command": "initialize",
  538. "arguments": {
  539. "clientID": "vscode",
  540. "clientName": "Visual Studio Code",
  541. "adapterID": "python",
  542. "pathFormat": "path",
  543. "linesStartAt1": true,
  544. "columnsStartAt1": true,
  545. "supportsVariableType": true,
  546. "supportsVariablePaging": true,
  547. "supportsRunInTerminalRequest": true,
  548. "locale": "en-us"
  549. },
  550. "type": "request",
  551. "seq": 1
  552. }
  553. ...
  554. With:
  555. - ``IDE`` = VS Code
  556. - ``PYD`` = pydev debugger
  557. - Messages follow the `DAP <https://microsoft.github.io/debug-adapter-protocol/specification>`_
  558. References
  559. ^^^^^^^^^^
  560. - Dump cell and state restoration: https://github.com/jupyterlab/debugger/issues/52
  561. - Protocol Overview: https://microsoft.github.io/debug-adapter-protocol/overview
  562. - Specification: https://microsoft.github.io/debug-adapter-protocol/specification
  563. Build and run the stand-alone examples
  564. --------------------------------------
  565. To install and build the examples in the ``examples`` directory:
  566. .. code:: bash
  567. jlpm run build:examples
  568. To run a specific example, change to the examples directory (i.e.
  569. ``examples/filebrowser``) and enter:
  570. .. code:: bash
  571. python main.py
  572. Debugging in the Browser
  573. ------------------------
  574. All methods of building JupyterLab produce source maps. The source maps
  575. should be available in the source files view of your browser's
  576. development tools under the ``webpack://`` header.
  577. When running JupyterLab normally, expand the ``~`` header to see the
  578. source maps for individual packages.
  579. When running in ``--dev-mode``, the core packages are available under
  580. ``packages/``, while the third party libraries are available under
  581. ``~``. Note: it is recommended to use ``jupyter lab --watch --dev-mode``
  582. while debugging.
  583. When running a test, the packages will be available at the top level
  584. (e.g. ``application/src``), and the current set of test files available
  585. under ``/src``. Note: it is recommended to use ``jlpm run watch`` in the
  586. test folder while debugging test options. See
  587. `above <#build-and-run-the-tests>`__ for more info.
  588. --------------
  589. High level Architecture
  590. -----------------------
  591. The JupyterLab application is made up of two major parts:
  592. - an npm package
  593. - a Jupyter server extension (Python package)
  594. Each part is named ``jupyterlab``. The :ref:`developer tutorial
  595. documentation <developer-guide>`
  596. provides additional architecture information.
  597. The NPM Packages
  598. ----------------
  599. The repository consists of many npm packages that are managed using the
  600. lerna build tool. The npm package source files are in the ``packages/``
  601. subdirectory.
  602. Build the NPM Packages from Source
  603. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  604. .. code:: bash
  605. git clone https://github.com/jupyterlab/jupyterlab.git
  606. cd jupyterlab
  607. pip install -e .
  608. jlpm
  609. jlpm run build:packages
  610. **Rebuild**
  611. .. code:: bash
  612. jlpm run clean
  613. jlpm run build:packages
  614. Writing Documentation
  615. ---------------------
  616. Documentation is written in Markdown and reStructuredText. In
  617. particular, the documentation on our Read the Docs page is written in
  618. reStructuredText. To ensure that the Read the Docs page builds, you'll
  619. need to install the documentation dependencies with ``conda``:
  620. .. code:: bash
  621. conda env create -f docs/environment.yml
  622. .. code:: bash
  623. conda activate jupyterlab_documentation
  624. To test the docs run:
  625. .. code:: bash
  626. python -m pytest --check-links -k .md . || python -m pytest --check-links -k .md --lf .
  627. The Read the Docs pages can be built using ``make``:
  628. .. code:: bash
  629. cd docs
  630. make html
  631. Or with ``jlpm``:
  632. .. code:: bash
  633. jlpm run docs
  634. Writing Style
  635. ^^^^^^^^^^^^^
  636. - The documentation should be written in the second person, referring
  637. to the reader as "you" and not using the first person plural "we."
  638. The author of the documentation is not sitting next to the user, so
  639. using "we" can lead to frustration when things don't work as
  640. expected.
  641. - Avoid words that trivialize using JupyterLab such as "simply" or
  642. "just." Tasks that developers find simple or easy may not be for
  643. users.
  644. - Write in the active tense, so "drag the notebook cells..." rather
  645. than "notebook cells can be dragged..."
  646. - The beginning of each section should begin with a short (1-2
  647. sentence) high-level description of the topic, feature or component.
  648. - Use "enable" rather than "allow" to indicate what JupyterLab makes
  649. possible for users. Using "allow" connotes that we are giving them
  650. permission, whereas "enable" connotes empowerment.
  651. User Interface Naming Conventions
  652. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  653. Documents, Files, and Activities
  654. """"""""""""""""""""""""""""""""
  655. Files are referred to as either files or documents, depending on the
  656. context.
  657. Documents are more human centered. If human viewing, interpretation,
  658. interaction is an important part of the experience, it is a document in
  659. that context. For example, notebooks and markdown files will often be
  660. referring to as documents unless referring to the file-ness aspect of it
  661. (e.g., the notebook filename).
  662. Files are used in a less human-focused context. For example, we refer to
  663. files in relation to a file system or file name.
  664. Activities can be either a document or another UI panel that is not file
  665. backed, such as terminals, consoles or the inspector. An open document
  666. or file is an activity in that it is represented by a panel that you can
  667. interact with.
  668. Element Names
  669. """""""""""""
  670. - The generic content area of a tabbed UI is a panel, but prefer to
  671. refer to the more specific name, such as “File browser.” Tab bars
  672. have tabs which toggle panels.
  673. - The menu bar contains menu items, which have their own submenus.
  674. - The main work area can be referred to as the work area when the name
  675. is unambiguous.
  676. - When describing elements in the UI, colloquial names are preferred
  677. (e.g., “File browser” instead of “Files panel”).
  678. The majority of names are written in lower case. These names include:
  679. - tab
  680. - panel
  681. - menu bar
  682. - sidebar
  683. - file
  684. - document
  685. - activity
  686. - tab bar
  687. - main work area
  688. - file browser
  689. - command palette
  690. - cell inspector
  691. - code console
  692. The following sections of the user interface should be in title case,
  693. directly quoting a word in the UI:
  694. - File menu
  695. - Files tab
  696. - Running panel
  697. - Tabs panel
  698. - Simple Interface mode
  699. The capitalized words match the label of the UI element the user is
  700. clicking on because there does not exist a good colloquial name for the
  701. tool, such as “file browser” or “command palette”.
  702. See :ref:`interface` for descriptions of elements in the UI.
  703. The Jupyter Server Extension
  704. ----------------------------
  705. The Jupyter server extension source files are in the jupyterlab/
  706. subdirectory. To use this extension, make sure the Jupyter Notebook
  707. server version 4.3 or later is installed.
  708. Build the JupyterLab server extension
  709. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  710. When you make a change to JupyterLab npm package source files, run:
  711. .. code:: bash
  712. jlpm run build
  713. to build the changes, and then refresh your browser to see the changes.
  714. To have the system build after each source file change, run:
  715. .. code:: bash
  716. jupyter lab --dev-mode --watch
  717. Build Utilities
  718. ---------------
  719. There is a range of build utilities for maintaining the repository. To
  720. get a suggested version for a library use
  721. ``jlpm run get:dependency foo``. To update the version of a library
  722. across the repo use ``jlpm run update:dependency foo ^latest``. To
  723. remove an unwanted dependency use ``jlpm run remove:dependency foo``.
  724. The key utility is ``jlpm run integrity``, which ensures the integrity
  725. of the packages in the repo. It will:
  726. - Ensure the core package version dependencies match everywhere.
  727. - Ensure imported packages match dependencies.
  728. - Ensure a consistent version of all packages.
  729. - Manage the meta package.
  730. The ``packages/metapackage`` package is used to build all of the
  731. TypeScript in the repository at once, instead of 50+ individual builds.
  732. The integrity script also allows you to automatically add a dependency
  733. for a package by importing from it in the TypeScript file, and then
  734. running: ``jlpm run integrity`` from the repo root.
  735. We also have scripts for creating and removing packages in
  736. ``packages/``, ``jlpm run create:package`` and
  737. ``jlpm run remove:package``. When creating a package, if it is meant to
  738. be included in the core bundle, add the
  739. ``jupyterlab: { coreDependency: true }`` metadata to the
  740. ``package.json``. Packages with ``extension`` or ``mimeExtension``
  741. metadata are considered to be a core dependency unless they are
  742. explicitly marked otherwise.
  743. Testing Changes to External Packages
  744. ------------------------------------
  745. Linking/Unlinking Packages to JupyterLab
  746. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  747. If you want to make changes to one of JupyterLab's external packages
  748. (for example, `Lumino <https://github.com/jupyterlab/lumino>`__) and test
  749. them out against your copy of JupyterLab, you can easily do so using the
  750. ``link`` command:
  751. 1. Make your changes and then build the external package
  752. 2. Register a link to the modified external package
  753. - navigate to the external package dir and run ``jlpm link``
  754. 3. Link JupyterLab to modded package
  755. - navigate to top level of your JupyterLab repo, then run
  756. ``jlpm link "<package-of-interest>"``
  757. You can then (re)build JupyterLab (eg ``jlpm run build``) and your
  758. changes should be picked up by the build.
  759. To restore JupyterLab to its original state, you use the ``unlink``
  760. command:
  761. 1. Unlink JupyterLab and modded package
  762. - navigate to top level of your JupyterLab repo, then run
  763. ``jlpm unlink "<package-of-interest>"``
  764. 2. Reinstall original version of the external package in JupyterLab
  765. - run ``jlpm install --check-files``
  766. You can then (re)build JupyterLab and everything should be back to
  767. default.
  768. Possible Linking Pitfalls
  769. ^^^^^^^^^^^^^^^^^^^^^^^^^
  770. If you're working on an external project with more than one package,
  771. you'll probably have to link in your copies of every package in the
  772. project, including those you made no changes to. Failing to do so may
  773. cause issues relating to duplication of shared state.
  774. Specifically, when working with Lumino, you'll probably have to link
  775. your copy of the ``"@lumino/messaging"`` package (in addition to
  776. whatever packages you actually made changes to). This is due to
  777. potential duplication of objects contained in the ``MessageLoop``
  778. namespace provided by the ``messaging`` package.
  779. Keyboard Shortcuts
  780. ------------------
  781. Typeset keyboard shortcuts as follows:
  782. - Monospace typeface, with spaces between individual keys:
  783. ``Shift Enter``.
  784. - For modifiers, use the platform independent word describing key:
  785. ``Shift``.
  786. - For the ``Accel`` key use the phrase: ``Command/Ctrl``.
  787. - Don’t use platform specific icons for modifier keys, as they are
  788. difficult to display in a platform specific way on Sphinx/RTD.
  789. Screenshots and Animations
  790. --------------------------
  791. Our documentation should contain screenshots and animations that
  792. illustrate and demonstrate the software. Here are some guidelines for
  793. preparing them:
  794. - Make sure the screenshot does not contain copyrighted material
  795. (preferable), or the license is allowed in our documentation and
  796. clearly stated.
  797. - If taking a png screenshot, use the Firefox or Chrome developer tools
  798. to do the following:
  799. - set the browser viewport to 1280x720 pixels
  800. - set the device pixel ratio to 1:1 (i.e., non-hidpi, non-retina)
  801. - screenshot the entire *viewport* using the browser developer
  802. tools. Screenshots should not include any browser elements such as
  803. the browser address bar, browser title bar, etc., and should not
  804. contain any desktop background.
  805. - If creating a movie, adjust the settings as above (1280x720 viewport
  806. resolution, non-hidpi) and use a screen capture utility of your
  807. choice to capture just the browser viewport.
  808. - For PNGs, reduce their size using ``pngquant --speed 1 <filename>``.
  809. The resulting filename will have ``-fs8`` appended, so make sure to
  810. rename it and use the resulting file. Commit the optimized png file
  811. to the main repository. Each png file should be no more than a few
  812. hundred kilobytes.
  813. - For movies, upload them to the IPython/Jupyter YouTube channel and
  814. add them to the
  815. `jupyterlab-media <https://github.com/jupyterlab/jupyterlab-media>`__
  816. repository. To embed a movie in the documentation, use the
  817. ``www.youtube-nocookie.com`` website, which can be found by clicking
  818. on the 'privacy-enhanced' embedding option in the Share dialog on
  819. YouTube. Add the following parameters the end of the URL
  820. ``?rel=0&amp;showinfo=0``. This disables the video title and related
  821. video suggestions.
  822. - Screenshots or animations should be preceded by a sentence describing
  823. the content, such as "To open a file, double-click on its name in the
  824. File Browser:".
  825. - We have custom CSS that will add box shadows, and proper sizing of
  826. screenshots and embedded YouTube videos. See examples in the
  827. documentation for how to embed these assets.
  828. To help us organize screenshots and animations, please name the files
  829. with a prefix that matches the names of the source file in which they
  830. are used:
  831. ::
  832. sourcefile.rst
  833. sourcefile_filebrowser.png
  834. sourcefile_editmenu.png
  835. This will help us to keep track of the images as documentation content
  836. evolves.
  837. Notes
  838. -----
  839. - By default, the application will load from the JupyterLab staging
  840. directory (default is ``<sys-prefix>/share/jupyter/lab/build``. If
  841. you wish to run the core application in
  842. ``<git root>/jupyterlab/build``, run ``jupyter lab --core-mode``.
  843. This is the core application that will be shipped.
  844. - If working with extensions, see the :ref:`extension documentation <developer_extensions>`.
  845. - The npm modules are fully compatible with Node/Babel/ES6/ES5. Simply
  846. omit the type declarations when using a language other than
  847. TypeScript.