Skip to content
This repository has been archived by the owner on Jul 9, 2018. It is now read-only.

Commit

Permalink
Merge pull request #93 from WordPress/add/custom-templated-path-plugin
Browse files Browse the repository at this point in the history
Package: Add `@wordpress/custom-templated-path-webpack-plugin` package
  • Loading branch information
aduth authored Mar 21, 2018
2 parents 1166624 + 712e599 commit 7025e0f
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 0 deletions.
53 changes: 53 additions & 0 deletions packages/custom-templated-path-webpack-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Custom Templated Path Webpack Plugin

Webpack plugin for creating custom path template tags. Extend the [default set of template tags](https://webpack.js.org/configuration/output/#output-filename) with your own custom behavior. Hooks into Webpack's compilation process to allow you to replace tags with a substitute value.

**Note:** This plugin targets Webpack 4.0 and newer, and is not compatible with older versions.

## Usage

Construct an instance of `CustomTemplatedPathPlugin` in your Webpack configurations `plugins` entry, passing an object where keys correspond to the template tag name. The value for each key is a function passed the original intended path and data corresponding to the asset.

The following example creates a new `basename` tag to substitute the basename of each entry file in the build output file. When compiled, the built file will be output as `build-entry.js`.

```js
const { basename } = require( 'path' );
const CustomTemplatedPathPlugin = require( '@wordpress/custom-templated-path-webpack-plugin' );

module.exports = {
// ...

entry: './entry',

output: {
filename: 'build-[basename].js',
},

plugins: [
new CustomTemplatedPathPlugin( {
basename( path, data ) {
let rawRequest;

const entryModule = get( data, [ 'chunk', 'entryModule' ], {} );
switch ( entryModule.type ) {
case 'javascript/auto':
rawRequest = entryModule.rawRequest;
break;

case 'javascript/esm':
rawRequest = entryModule.rootModule.rawRequest;
break;
}

if ( rawRequest ) {
return basename( rawRequest );
}

return path;
},
} ),
],
};
```

For more examples, refer to Webpack's own [`TemplatedPathPlugin.js`](https://github.com/webpack/webpack/blob/v4.1.1/lib/TemplatedPathPlugin.js), which implements the base set of template tags.
33 changes: 33 additions & 0 deletions packages/custom-templated-path-webpack-plugin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "@wordpress/custom-templated-path-webpack-plugin",
"version": "1.0.0",
"description": "Webpack plugin for creating custom path template tags",
"author": "WordPress",
"license": "GPL-2.0-or-later",
"keywords": [
"webpack",
"webpack-plugin"
],
"homepage": "https://github.com/WordPress/packages/tree/master/packages/custom-templated-path-webpack-plugin/",
"repository": {
"type": "git",
"url": "https://github.com/WordPress/packages.git"
},
"bugs": {
"url": "https://github.com/WordPress/packages/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",
"publishConfig": {
"access": "public"
},
"dependencies": {
"escape-string-regexp": "^1.0.5"
},
"devDependencies": {
"webpack": "^4.1.1"
},
"peerDependencies": {
"webpack": "^4.0.0"
}
}
52 changes: 52 additions & 0 deletions packages/custom-templated-path-webpack-plugin/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* External dependencies
*/
const escapeStringRegexp = require( 'escape-string-regexp' );

/**
* Webpack plugin for handling specific template tags in Webpack configuration
* values like those supported in the base Webpack functionality (e.g. `name`).
*
* @see webpack.TemplatedPathPlugin
*/
class CustomTemplatedPathPlugin {
/**
* CustomTemplatedPathPlugin constructor. Initializes handlers as a tuple
* set of RegExp, handler, where the regular expression is used in matching
* a Webpack asset path.
*
* @param {Object.<string,Function>} handlers Object keyed by tag to match,
* with function value returning
* replacement string.
*/
constructor( handlers ) {
this.handlers = [];

for ( const [ key, handler ] of Object.entries( handlers ) ) {
const regexp = new RegExp( `\\[${ escapeStringRegexp( key ) }\\]`, 'gi' );
this.handlers.push( [ regexp, handler ] );
}
}

/**
* Webpack plugin application logic.
*
* @param {Object} compiler Webpack compiler
*/
apply( compiler ) {
compiler.hooks.compilation.tap( 'CustomTemplatedPathPlugin', ( compilation ) => {
compilation.mainTemplate.hooks.assetPath.tap( 'CustomTemplatedPathPlugin', ( path, data ) => {
for ( let i = 0; i < this.handlers.length; i++ ) {
const [ regexp, handler ] = this.handlers[ i ];
if ( regexp.test( path ) ) {
return path.replace( regexp, handler( path, data ) );
}
}

return path;
} );
} );
}
}

module.exports = CustomTemplatedPathPlugin;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
entry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = null;
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* External dependencies
*/

const { basename } = require( 'path' );

/**
* Internal dependencies
*/

const CustomTemplatedPathPlugin = require( '../../' );

module.exports = {
mode: 'development',
context: __dirname,
entry: './entry',
output: {
filename: '[basename].js',
path: __dirname,
},
plugins: [
new CustomTemplatedPathPlugin( {
basename( path, data ) {
console.log(data)

let rawRequest;
if ( data && data.chunk && data.chunk.entryModule ) {
rawRequest = data.chunk.entryModule.rawRequest;
}

if ( rawRequest ) {
return basename( rawRequest );
}

return path;
},
} ),
],
};
34 changes: 34 additions & 0 deletions packages/custom-templated-path-webpack-plugin/test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* External dependencies
*/

const path = require( 'path' );
const { promisify } = require( 'util' );
const webpack = promisify( require( 'webpack' ) );
const fs = require( 'fs' );
const access = promisify( fs.access );
const unlink = promisify( fs.unlink );

/**
* Internal dependencies
*/

const config = require( './fixtures/webpack.config.js' );
const CustomTemplatedPathPlugin = require( '../' );

describe( 'CustomTemplatedPathPlugin', () => {
const outputFile = path.join( __dirname, '/fixtures/entry.js' )

beforeAll( async () => {
// Remove output file so as not to report false positive from previous
// test. Absorb error since the file may not exist (unlink will throw).
try {
await unlink( outputFile );
} catch ( error ) {}
} );

it( 'should resolve with basename output', async () => {
const stats = await webpack( config );
await access( outputFile );
} );
} );

0 comments on commit 7025e0f

Please sign in to comment.