-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(build)!: Introduce exports
section in package.json
#7822
Conversation
Note to reviewer: the diffs, especially of |
exports
section in package.json
exports
section in package.json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved.
Two requests (made in offline conversation):
- Add links to an overview of the resolution strategies used by node and by webpack.
- Test with one or more of the plugins.
OK, this has tested correctly with
I also want to make two additional tweaks to the |
c8a7829
to
7f764dd
Compare
PR #226 addedd a resolve.alias for blockly to webpack.config.js. It is not entirely clear what the purpose of this was at the time, but it has the effect of treating imports of submodules (e.g. 'blockly/core') as if they were direct imports (e.g. of './node_modules/blockly/core.js'), causing webpack to ignore the blockly package's package.json file. This causes plugins to fail to build due to the introduction of an exports stanza in that file (and other related changes) in google/blockly#7822.
The latter has never been an advertised entrypoint, and will cease to be a valid entrypoint in v11 (see google/blockly#7822). Fortunately the 'blockly' entrypoint behaves the same as the 'blockly/node' entrypoint does in a node.js environment.
PR google#226 addedd a resolve.alias for blockly to webpack.config.js. It is not entirely clear what the purpose of this was at the time, but it has the effect of treating imports of submodules (e.g. 'blockly/core') as if they were direct imports (e.g. of './node_modules/blockly/core.js'), causing webpack to ignore the blockly package's package.json file. This causes plugins to fail to build due to the introduction of an exports stanza in that file (and other related changes) in google/blockly#7822.
The latter has never been an advertised entrypoint, and will cease to be a valid entrypoint in v11 (see google/blockly#7822). Fortunately the 'blockly' entrypoint behaves the same as the 'blockly/node' entrypoint does in a node.js environment.
PR google#3821 added .d.ts files for every file in msg/json/, but several of these are internal utility files rather than translations, and do not result in a langfile being output by create_messages.py when building langfiles. In the meantime we have added a few new languages that are being published but which have (until now) not had the corresponding type declarations.
Add an exports stanza to package.json, enumerating existing entrypoints in a new format. - The original main entrypoint, index.js, is removed since the exports section can point directly at node.js or browser.js. - No change made (yet) to other entrypoints (core, blocks, generators); these will be dealt with in a subsequent PR. - The msg/en entrypoint is included in the top-level package.json as an example; entries for all other languages created as part of the packageJSON package task. BREAKING CHANGE: The introduction of an exports stanza means that correctly-behaved tools (node.js, bundlers like webpack, etc.) will only allow importing of the specified entrypoints. Here is the full list of permitted entrypoints that can be imported or required: - blockly - blockly/core - blockly/blocks - blockly/dart - blockly/lua - blockly/javascript - blockly/php - blockly/python - blockly/msg/<lang>, for all supported language codes <lang> (e.g blockly/msg/en, blockly/msg/fr, blockly/msg/de, etc.) If you previously impored any other paths from the blockly package you will need to update your imports. Here are the most common paths that may have been used, and their correct replacements: | If you previously imported: | Import instead: | | -------------------------------- | -------------------------- | | blockly/index.js | blockly | | blockly/node.js | blockly | | blockly/browser.js | blockly | | blockly/blockly.min | This file should only be loaded as a <script>. | | blockly/core.js | blockly/core | | blockly/core-browser.js | blockly/core | | blockly/blockly_compressed.js | blockly/core | | blockly/blocks.js | blockly/blocks | | blockly/blocks_compressed.js | blockly/blocks | | blockly/dart.js | blockly/dart | | blockly/dart_compressed.js | blockly/dart | | blockly/lua.js | blockly/lua | | blockly/lua_compressed.js | blockly/lua | | blockly/javascript.js | blockly/javascript | | blockly/javascript_compressed.js | blockly/javascript | | blockly/php.js | blockly/php | | blockly/php_compressed.js | blockly/php | | blockly/python.js | blockly/python | | blockly/python_compressed.js | blockly/python | | blockly/msg/en.js | blockly/msg/en |
Use 'blockly/core' instead of './core' when importing core into other wrappers (and similarly for other entries in package.json exports stanza), so that (e.g.) dist/javascript.js won't import dist/core.js (the node.js version that loads jsdom) when being loaded in a browser environment. This fixes an issue where blockly attempts to load jsdom even in browser environments because the browser stanza in package.json, which caused attempts to load core.js to load core-browser.js instead in browser environments, was removed in a previous commit.
Remove pointless wrapper modules that no longer server any purpose; use exports stanza in package.json to point directly to compiled chunks where possible.
Combine scripts/package/browser/index.js (becomes dist/browser.js) and scripts/package/node/index.js (becomes dist/node.js) into a single environment-agnostic index.js. BREAKING CHANGE: Historically, importing the main 'blockly' package would import 'blockly/core', 'blockly/blocks', 'blockly/en' and 'blockly/javascript' - and additionally, in node.js, also import 'blockly/dart', 'blockly/lua', 'blockly/php' and 'blockly/python'. Now the main 'blockly' package entrypoint never loads any of the generator modules. This change has been made because of changes to generator exports made in blockly v9.0.0 that make necessary to always separately import generator modules. Note that this change does not affect loading the blockly package via <script src="https://unpkg.com/blockly"; that continues to load to blockly.min.js, which includes javascript_compressed.js and (due to being loaded as a script) makes it available via Blockly.JavaScript.
Move scripts/package/node/core.js to scripts/package/core-node.js, and have it packaged as dist/core-node.js rather than dist/core.js - without a UMD wrapper, since it will always be loaded as a CJS module.
Use a subpath pattern (wildcard) for the msg/* entrypoints, obviating the need for special handling in packageJSON.
run_node_test.js previously directly require()d the dist/blockly.js and dist/javascript.js wrapper module, which no longer exist. Change it to require('blockly-test') (and …blockly-test/javascript) and create a symlink ./node_modules/blocky-test -> dist/ to satisfy this.
In the 'blockly/core' export: - Replace the browser: entrypoint with a default: one. - Add a types: entrypoint for core.
OK, previous commits rebased onto current |
…config.js` and `'blockly'` imports (#2229) * chore(dev-scripts)!: Remove support acquiring Blockly through git Completes revert of PR #335. BREAKING CHANGE: This PR removes the support that was added in PR #335 for aquiring Blockly directly from a git:// URL. This feature was useful insofar as it enabled merging changes into blockly-samples that depend on changes in blockly that have not yet been published (even as a beta)—and still have tests pass. For this to work seamlessly, however, the code in webpack.config.js depended on a postinstall script that was removed in PR #1630. When testing such PRs going forward use npm link for local testing and wait for changes to blockly to be published before merging the corresponding changes to samples—or wait for blockly to become a monorepo so both changes can be made in the same PR! Note that this change is breaking only to the dev-scripts plugin itself, and will not cause other plugins that use it as a dev dependency to experience a breaking change. * fix(dev-scripts): Restore packageJson for setting PACKAGE_NAME The commit which removed support for git:// URLS by completing the revert of PR #335 removed the initialisation of packageJson (from the package.json of the plugin being built) which turns out to still be needed by a DefinePlugin call added later. * fix(dev-scripts): Don't use alias when resolving blockly PR #226 addedd a resolve.alias for blockly to webpack.config.js. It is not entirely clear what the purpose of this was at the time, but it has the effect of treating imports of submodules (e.g. 'blockly/core') as if they were direct imports (e.g. of './node_modules/blockly/core.js'), causing webpack to ignore the blockly package's package.json file. This causes plugins to fail to build due to the introduction of an exports stanza in that file (and other related changes) in google/blockly#7822. * fix(dev-scripts): Exclude blockly from plugin bundles Fix bloat caused by some plugins depending on all of blockly (instead of just blockly/core), resulting in webpack including a copy of blockly in the bundled plugin becuase only the subpackage entrypoints were listed inthe externals stanza of webpack.config.js. This will also avoid certain problems that might occur due to apps using such bundled inadvertently containing two or more different copies of Blockly. Also fix the one plugin which did still have an unnecessary dependency on blockly intead of blockly/core. * refactor(dev-scripts): Introduce exists() for readability Currently webpack.conf.js is hard to understand. Attempt to improve readability by making some parts more DRY ("don't repeat yourself") and others more DAMP ("descriptive and meaningful phrases"). * fix(dev-scripts): Ignore more jsdom subdependencies Add bufferutils and utf-8-validate to IgnorePlugin config when building tests. These are optional dependencies of wd, which is itself a dependency of jsdom. Also refactor how plugins config is generated to improve readability. * refactor(dev-scripts): Simplify resolve.extensions There doesn't appear to be any reason not to include the '.ts' in resolve.extensions even for pure-JS plugins, but it is _necessary_ to include it in TS plugins. Since the default value for resolve.extensions is ['.js', '.json', '.wasm'] set it to ['.ts', '.js', '.json', '.wasm'] which gives priority to TS, then JS, then the other default extensions. Also add a helpful comment explaining the purpose of resolve.fallback. * fix(plugins): Build tests against 'blockly', not 'blockly/node' The latter has never been an advertised entrypoint, and will cease to be a valid entrypoint in v11 (see google/blockly#7822). Fortunately the 'blockly' entrypoint behaves the same as the 'blockly/node' entrypoint does in a node.js environment. * chore(plugins): Fix lint, formatting * fix(dev-tools): Have runSerializationTestSuite accept Blockly Have runSerializationTestSuite accept a second argument which is the Blockly object to use for XML serialization/deserialization. This works around an issue in blockly-samples that (following the deletion of the alias for blockly in webpack.config.js) causes tests using this function to fail due to having two copies of jsdom loaded, where each will reject DOM objects created by the other. See #2229 (comment) for more details. * chore(typed-variable-modal): Skip failing test
Fixes google#7952. The main typings file for langfiles, typings/msg/msg.d.ts, was inadvertently deleted in PR google#7822. This was part of a well intentioned attempt to remove spurious files from typings/msg/ that do not correspond to published langfiles, but this file should have been retained because msg.d.ts is reexported by all the other *.d.ts files in this directory.
…dd TS import test (#7955) * test(typings): Add langfile (msg) import + typings test * fix(typings): Restore inadvertently-deleted typings/msg/msg.d.ts Fixes #7952. The main typings file for langfiles, typings/msg/msg.d.ts, was inadvertently deleted in PR #7822. This was part of a well intentioned attempt to remove spurious files from typings/msg/ that do not correspond to published langfiles, but this file should have been retained because msg.d.ts is reexported by all the other *.d.ts files in this directory.
This is in effect a partial rollback of PR google#7822. This should solve issues encountered by users of bunders that don't support exports at all (e.g. browserify) as well as ones that don't support it in certain circumstances (e.g., when using webpack's resolve.alias configuration option to alias 'blockly' to 'node_modules/blockly', as we formerly did in most plugins, which causes webpack to ignore blockly's package.json entirely). Assumptions: - Such bundlers will _completely_ ignore the exports declaration. - The bundles are intended to be used in a browser—or at least not in node.js—so the core entrypoint never needs to route to core-node.js. This is reasonable since there's little reason to bundle code for node.js, and node.js has supported the exports clause since at least v12, consideably older than any version of node.js we officially support. - It suffices to provide only a CJS entrypoint (because we can only provide CJS or ESM, not both. (We could in future switch to providing only an ESM entrypoint instead, though.)
This is in effect a partial rollback of PR google#7822. This should solve issues encountered by users of bunders that don't support exports at all (e.g. browserify) as well as ones that don't support it in certain circumstances (e.g., when using webpack's resolve.alias configuration option to alias 'blockly' to 'node_modules/blockly', as we formerly did in most plugins, which causes webpack to ignore blockly's package.json entirely). Assumptions: - Such bundlers will _completely_ ignore the exports declaration. - The bundles are intended to be used in a browser—or at least not in node.js—so the core entrypoint never needs to route to core-node.js. This is reasonable since there's little reason to bundle code for node.js, and node.js has supported the exports clause since at least v12, consideably older than any version of node.js we officially support. - It suffices to provide only a CJS entrypoint (because we can only provide CJS or ESM, not both. (We could in future switch to providing only an ESM entrypoint instead, though.)
This is in effect a partial rollback of PR google#7822. This should solve issues encountered by users of bunders that don't support exports at all (e.g. browserify) as well as ones that don't support it in certain circumstances (e.g., when using webpack's resolve.alias configuration option to alias 'blockly' to 'node_modules/blockly', as we formerly did in most plugins, which causes webpack to ignore blockly's package.json entirely). Assumptions: - Such bundlers will _completely_ ignore the exports declaration. - The bundles are intended to be used in a browser—or at least not in node.js—so the core entrypoint never needs to route to core-node.js. This is reasonable since there's little reason to bundle code for node.js, and node.js has supported the exports clause since at least v12, consideably older than any version of node.js we officially support. - It suffices to provide only a CJS entrypoint (because we can only provide CJS or ESM, not both. (We could in future switch to providing only an ESM entrypoint instead, though.)
This is in effect a partial rollback of PR #7822. This should solve issues encountered by users of bunders that don't support exports at all (e.g. browserify) as well as ones that don't support it in certain circumstances (e.g., when using webpack's resolve.alias configuration option to alias 'blockly' to 'node_modules/blockly', as we formerly did in most plugins, which causes webpack to ignore blockly's package.json entirely). Assumptions: - Such bundlers will _completely_ ignore the exports declaration. - The bundles are intended to be used in a browser—or at least not in node.js—so the core entrypoint never needs to route to core-node.js. This is reasonable since there's little reason to bundle code for node.js, and node.js has supported the exports clause since at least v12, considerably older than any version of node.js we officially support. - It suffices to provide only a CJS entrypoint (because we can only provide CJS or ESM, not both. (We could in future switch to providing only an ESM entrypoint instead, though.)
The basics
The details
Resolves
Preparatory work for #7449.
Proposed Changes
Add
exports
section topackage.json
Add an
exports
stanza topackage.json
, enumerating existing entrypoints in a new format. This also formally specifies the legal import paths; node.js, webpack etc. will enforce this and prevent paths other than those explicitly enumerated here from being loaded.Remove most entrypoint wrappers
Since
exports
allows us to point each entrypoint at any file, by pointing them directly at the relevant compressed chunk wherever possible we eliminate the need for most of the crufty entrypoint wrappers that we have needed up to this point.Combine browser and node entrypoint wrappers
Combine
scripts/package/browser/index.js
(was packaged asdist/browser.js
) andscripts/package/node/index.js
(was packaged asdist/node.js
) into a single, environment-agnosticindex.js
. Drop code generators from the list of things loaded by this entrypoint.Simplify
core
entrypoint wrapper for node.jsMove
scripts/package/node/core.js
toscripts/package/core-node.js
, and have it packaged asdist/core-node.js
rather thandist/core.js
—without a UMD wrapper, since it will always be loaded as a CJS module.Improve remaining wrapper imports
Use 'blockly/core' instead of './core' when importing core into
index.js
(and similarly for the other chunks it imports) so that it will either loadblockly_compressed.js
(if in a browser) ordist/core-node.js
(if in node.js) automatically.browser
stanza frompackage.json
, which would previously substitute one file for another—e.g.,require('./core')
would be treated by webpack as meaningrequire('./core-browser.js')
if running in a browser environment.Some other minor tweaks to
packageUMD
calls to produce slightly more sensible-looking UMD wrappers.Remove bogus
.d.ts
files fromtypings/msg
PR #3821 added
.d.ts
files for every file in msg/json/, but several of these are internal utility files rather than translations, and do not result in a langfile being output bycreate_messages.py
when building langfiles.Reason for Changes
Adding an
exports
section:blockly/javascript
; withoutexports
all subpath entrypoints must be either ESM or CJS and it is not possible to provide both.Test Coverage
npn test
.examples/sample-app
works fine whennpm link
ed to this version.node
loads things as expectedDocumentation
Our "getting blockly" documentation should be updated to note that loading
https://unpkg.com/blockly
(and similar) will loadblockly.min.js
, which consists ofblockly_compressed.js
,msg/en.js
,blocks_compressed.js
andjavascript_compressed.js
concatenated together. Notably, despite (or perhaps because of) each of these having their own UMD wrapper, the combination works fine as a script but will if (somehow) loaded as a CJS or AMD module only return the exports for the last of those chunks—i.e., the JavaScript generator.(We could alternatively decide to do something else with the
umd:
condition for the main (`'.'``) entrypoint.)Additional Information
Module resolution
Module resolution is ultimately at the discretion of each JS runtime or build tool. Browsers, node.js, Webpack, Closure Compiler, etc. each have their own module resolution and loading implementations. The
package.json
file was originally for the benefit ofnpm
in its role of installing packages and their dependencies, but now contains additional information (like thebrowser
,exports
,main
,umd
, andunpkg
directives) that are honoured to varying degrees by different tools. It is therefore hard to say categorically what file(s) will be loaded by which tools without consulting each tool's documentation (and/or implementation), but amongst tools that have some kind of support for NPM packages, theexports
directive appears to be widely and relatively consistently supported.Here is some of the relevant documentation for tools we expect Blockly developers are likely to use:
package.json
exports
support and module resolution and loaders.Breaking changes
BREAKING CHANGE: The introduction of an
exports
stanza means that correctly-behaved tools (node.js, bundlers like webpack, etc.) will only allow importing of the specified entrypoints. Here is the full list of permitted entrypoints that can beimport
ed orrequire
d:blockly
blockly/core
blockly/blocks
blockly/dart
blockly/lua
blockly/javascript
blockly/php
blockly/python
blockly/msg/<lang>
, for all supported language codes<lang>
(e.gblockly/msg/en
,blockly/msg/fr
,blockly/msg/de
, etc.)If you previously imported any other paths from the blockly package you will need to update your imports. Here are the most common paths that may have been used, and their correct replacements:
blockly/index.js
blockly
blockly/node.js
blockly
blockly/browser.js
blockly
blockly/blockly.min
<script>
.blockly/core.js
blockly/core
blockly/core-browser.js
blockly/core
blockly/blockly_compressed.js
blockly/core
blockly/blocks.js
blockly/blocks
blockly/blocks_compressed.js
blockly/blocks
blockly/dart.js
blockly/dart
blockly/dart_compressed.js
blockly/dart
blockly/lua.js
blockly/lua
blockly/lua_compressed.js
blockly/lua
blockly/javascript.js
blockly/javascript
blockly/javascript_compressed.js
blockly/javascript
blockly/php.js
blockly/php
blockly/php_compressed.js
blockly/php
blockly/python.js
blockly/python
blockly/python_compressed.js
blockly/python
blockly/msg/en.js
blockly/msg/en
If you are loading Blockly as a script you should continue to load the compiled chunks (
blockly_compressed.js
,blocks_compressed.js
,javascript_compressed.js
, etc.) directly, or loadblockly.min.js
which is just a concatenation ofblockly_compressed.js
,msg/en.js
,blocks_compressed.js
, andjavascript_generator.js
.(Prior to v11 there were various entrypoint wrappers provided in the form of UMD modules (e.g.
blockly.js
,javascript.js
, etc.) but loading these as as scripts never did anything useful and, as they are no longer needed, they have been deleted.)BREAKING CHANGE: Prior to v11, importing the main
blockly
package would importblockly/core
,blockly/blocks
,blockly/msg/en
andblockly/javascript
—and additionally, innode.js
, alsoblockly/dart
,blockly/lua
,blockly/php
andblockly/python
.Now the main
blockly
package entrypoint never loads any of the generators.This change has been made because of changes to generator exports made in blockly v9.0.0 that make necessary to always separately import generator modules in order to use them.
Note that this change does not affect loading the blockly package via
<script src="https://unpkg.com/blockly">
; that continues to load toblockly.min.js
, which continues to includejavascript_compressed.js
which (when loaded as a script) makes itself available viaBlockly.JavaScript
for backwards compatibility.