Skip to content

Commit

Permalink
Dependency Extraction Webpack Plugin: Add types (#22498)
Browse files Browse the repository at this point in the history
* Type package

* Add node eslint config

* Add changelog

* Update util path in build scripts
  • Loading branch information
sirreal authored Jun 2, 2020
1 parent 2116931 commit 016a531
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 24 deletions.
76 changes: 76 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@
"@types/requestidlecallback": "0.3.1",
"@types/sprintf-js": "1.1.2",
"@types/uuid": "7.0.2",
"@types/webpack": "4.41.16",
"@types/webpack-sources": "0.1.7",
"@wordpress/babel-plugin-import-jsx-pragma": "file:packages/babel-plugin-import-jsx-pragma",
"@wordpress/babel-plugin-makepot": "file:packages/babel-plugin-makepot",
"@wordpress/babel-preset-default": "file:packages/babel-preset-default",
Expand Down
4 changes: 4 additions & 0 deletions packages/dependency-extraction-webpack-plugin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### New feature

- Include TypeScript type declarations ([#22498](https://github.com/WordPress/gutenberg/pull/22498))

## 2.5.0 (2020-04-01)

### New Features
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
// Use the default eslint parser. Prevent babel transforms.
"parser": "espree",
"env": {
"node": true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
* External dependencies
*/
const { createHash } = require( 'crypto' );
const json2php = require( 'json2php' );
const path = require( 'path' );
const { ExternalsPlugin } = require( 'webpack' );
const { RawSource } = require( 'webpack-sources' );
// Ignore reason: json2php is untyped
// @ts-ignore
const json2php = require( 'json2php' );

/**
* Internal dependencies
Expand All @@ -15,8 +17,53 @@ const {
defaultRequestToHandle,
} = require( './util' );

/**
* Map module request to an external.
*
* @callback RequestToExternal
*
* @param {string} request Module request.
*
* @return {string|string[]|void} Return `undefined` to ignore the request.
* Return `string|string[]` to map the request to an external.
*/

/**
* Map module request to a script handle.
*
* @callback RequestToHandle
*
* @param {string} request Module request.
*
* @return {string|void} Return `undefined` to use the same name as the module.
* Return `string` to map the request to a specific script handle.
*/

/**
* @typedef AssetData
*
* @property {string} version String representing a particular build
* @property {string[]} dependencies The script dependencies
*/

/**
* @typedef Options
*
* @property {boolean} injectPolyfill Force wp-polyfill to be included in each entry point's dependency list. This is like importing `@wordpress/polyfill` for each entry point.
* @property {boolean} useDefaults Set to `false` to disable the default WordPress script request handling.
* @property {'php'|'json'} outputFormat The output format for the generated asset file.
* @property {RequestToExternal|undefined} [requestToExternal] Map module requests to an external.
* @property {RequestToHandle|undefined} [requestToHandle] Map module requests to a script handle.
* @property {string|null} combinedOutputFile This option is useful only when the combineAssets option is enabled. It allows providing a custom output file for the generated single assets file. It's possible to provide a path that is relative to the output directory.
* @property {boolean|undefined} combineAssets By default, one asset file is created for each entry point. When this flag is set to true, all information about assets is combined into a single assets.(json|php) file generated in the output directory.
*/

class DependencyExtractionWebpackPlugin {
/**
* @param {Partial<Options>} options
*/
constructor( options ) {
/** @type {Options} */
this.options = Object.assign(
{
combineAssets: false,
Expand All @@ -28,11 +75,15 @@ class DependencyExtractionWebpackPlugin {
options
);

// Track requests that are externalized.
//
// Because we don't have a closed set of dependencies, we need to track what has
// been externalized so we can recognize them in a later phase when the dependency
// lists are generated.
/**
* Track requests that are externalized.
*
* Because we don't have a closed set of dependencies, we need to track what has
* been externalized so we can recognize them in a later phase when the dependency
* lists are generated.
*
* @type {Set<string>}
*/
this.externalizedDeps = new Set();

// Offload externalization work to the ExternalsPlugin.
Expand All @@ -42,7 +93,14 @@ class DependencyExtractionWebpackPlugin {
);
}

externalizeWpDeps( context, request, callback ) {
/* eslint-disable jsdoc/valid-types */
/**
* @param {Parameters<WebpackExternalsFunction>[0]} _context
* @param {Parameters<WebpackExternalsFunction>[1]} request
* @param {Parameters<WebpackExternalsFunction>[2]} callback
*/
externalizeWpDeps( _context, request, callback ) {
/* eslint-enable jsdoc/valid-types */
let externalRequest;

// Handle via options.requestToExternal first
Expand All @@ -67,6 +125,10 @@ class DependencyExtractionWebpackPlugin {
return callback();
}

/**
* @param {string} request
* @return {string} Transformed request
*/
mapRequestToDependency( request ) {
// Handle via options.requestToHandle first
if ( typeof this.options.requestToHandle === 'function' ) {
Expand All @@ -88,6 +150,10 @@ class DependencyExtractionWebpackPlugin {
return request;
}

/**
* @param {Object} asset
* @return {string} Stringified asset
*/
stringify( asset ) {
if ( this.options.outputFormat === 'php' ) {
return `<?php return ${ json2php(
Expand All @@ -98,11 +164,19 @@ class DependencyExtractionWebpackPlugin {
return JSON.stringify( asset );
}

/**
* @param {WebpackCompiler} compiler
* @return {void}
*/
apply( compiler ) {
this.externalsPlugin.apply( compiler );

const { output } = compiler.options;
const { filename: outputFilename } = output;
// Assert the `string` type for output filename.
// The type indicates the option may be `undefined`.
// However, at this point in compilation, webpack has filled the options in if
// they were not provided.
const outputFilename = /** @type {{filename:string}} */ ( compiler
.options.output ).filename;

compiler.hooks.emit.tap( this.constructor.name, ( compilation ) => {
const {
Expand All @@ -111,13 +185,16 @@ class DependencyExtractionWebpackPlugin {
injectPolyfill,
outputFormat,
} = this.options;

/** @type {Record<string, AssetData>} */
const combinedAssetsData = {};

// Process each entry point independently.
for ( const [
entrypointName,
entrypoint,
] of compilation.entrypoints.entries() ) {
/** @type {Set<string>} */
const entrypointExternalizedWpDeps = new Set();
if ( injectPolyfill ) {
entrypointExternalizedWpDeps.add( 'wp-polyfill' );
Expand All @@ -139,6 +216,7 @@ class DependencyExtractionWebpackPlugin {

const runtimeChunk = entrypoint.getRuntimeChunk();

/** @type {AssetData} */
const assetData = {
// Get a sorted array so we can produce a stable, stringified representation.
dependencies: Array.from(
Expand Down Expand Up @@ -179,7 +257,13 @@ class DependencyExtractionWebpackPlugin {
}

if ( combineAssets ) {
const outputFolder = compiler.options.output.path;
// Assert the `string` type for output path.
// The type indicates the option may be `undefined`.
// However, at this point in compilation, webpack has filled the options in if
// they were not provided.
const outputFolder = /** @type {{path:string}} */ ( compiler
.options.output ).path;

const assetsFilePath = path.resolve(
outputFolder,
combinedOutputFile ||
Expand All @@ -199,6 +283,10 @@ class DependencyExtractionWebpackPlugin {
}
}

/**
* @param {string} name
* @return {string} Basename
*/
function basename( name ) {
if ( ! name.includes( '/' ) ) {
return name;
Expand All @@ -207,3 +295,8 @@ function basename( name ) {
}

module.exports = DependencyExtractionWebpackPlugin;

/**
* @typedef {import('webpack').Compiler} WebpackCompiler
* @typedef {import('webpack').ExternalsFunctionElement} WebpackExternalsFunction
*/
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ const BUNDLED_PACKAGES = [ '@wordpress/icons', '@wordpress/interface' ];
* request `@wordpress/api-fetch` becomes `wp.apiFetch`
* request `@wordpress/i18n` becomes `wp.i18n`
*
* @param {string} request Requested module
*
* @return {(string|string[]|undefined)} Script global
* @type {import('.').RequestToExternal}
*/
function defaultRequestToExternal( request ) {
switch ( request ) {
Expand Down Expand Up @@ -55,9 +53,7 @@ function defaultRequestToExternal( request ) {
* request `@wordpress/i18n` becomes `wp-i18n`
* request `@wordpress/escape-html` becomes `wp-escape-html`
*
* @param {string} request Requested module
*
* @return {(string|undefined)} Script handle
* @type {import('.').RequestToHandle}
*/
function defaultRequestToHandle( request ) {
switch ( request ) {
Expand All @@ -84,9 +80,7 @@ function defaultRequestToHandle( request ) {
* @return {string} Camel-cased string.
*/
function camelCaseDash( string ) {
return string.replace( /-([a-z])/g, ( match, letter ) =>
letter.toUpperCase()
);
return string.replace( /-([a-z])/g, ( _, letter ) => letter.toUpperCase() );
}

module.exports = {
Expand Down
Loading

0 comments on commit 016a531

Please sign in to comment.