Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@webdiscus/pug-loader

Package Overview
Dependencies
Maintainers
1
Versions
71
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@webdiscus/pug-loader - npm Package Compare versions

Comparing version 1.6.0 to 1.6.1-beta.0

src/loader.js

84

CHANGELOG.md
# Change log
## 1.6.1 (2022-01-19)
- added supports resolving for aliases from webpack `resolve.plugins` by required resources, like styles, scripts
- fix resolving issues by usage the variable filename contained parent relative path in require() function
- improve resolving the required files by all methods
- refactoring
- added more test cases
## 1.6.0 (2022-01-12)
- added supports resolving aliases from `webpack.resolve.plugins`
if a file is by `webpack.resolve.alais` not resolved, then uses the slow enhanced resolver
- added supports resolving for aliases from webpack `resolve.plugins` by include / extends
if a file is by webpack `resolve.alais` not resolved, then uses the slow enhanced resolver
- update packages
## 1.5.1 (2021-12-10)
- bugfix: fix path resolving on Windows
- fix path resolving on Windows
- some optimisations

@@ -15,16 +22,16 @@ - code refactoring

- NEW: the `pug-loader` is now the part of the [pug-plugin](https://github.com/webdiscus/pug-plugin).
- feature: added option `basedir` for all absolute inclusion
- test: add test for new option `basedir`
- test: refactoring of tests
- added the option `basedir` for all absolute inclusion
- added the test for new option `basedir`
- refactoring of tests
## 1.4.6 (2021-12-06)
- cleanup: remove needles console.log, cleanup code
- devDeps: update packages
- docs: minor update readme
- tests: add tests for an exception and an option
- tests: refactoring test utils
- remove needles console.log, cleanup code
- added tests for an exception and an option
- refactoring test utils
- update readme
- update packages
## 1.4.5 (2021-11-22)
- improvement: optimization of `render` and `html` methods
- bugfix: fix require() for CommonJS module. Now is possible use the CommonJS module directly in the pug, e.g.:
- improve the `render` and `html` methods
- fix require() for CommonJS module. Now is possible use the CommonJS module directly in the pug, e.g.:
```pug

@@ -34,14 +41,14 @@ - var someModule = require('some-module');

```
- bugfix: fix 'Unexpected token' by render method
- bugfix: fix 'Unterminated string' by render method
- fix 'Unexpected token' by render method
- fix 'Unterminated string' by render method
## 1.4.4 (2021-11-19)
- compatibility: add polyfill `replaceAll()` for node.js < 15
- bugfix: fix for the parsing multiple `require` in a single string code
- added the polyfill `replaceAll()` for node.js < 15
- fix for the parsing multiple `require` in a single string code
## 1.4.3 (2021-11-18)
- update: minor code update and cleanup
- minor code update and cleanup
## 1.4.2 (2021-11-18)
- feature: now supports require of JS and JSON data files in pug at compile time, e.g.:
- added supports for require of JS and JSON data files in pug at compile time, e.g.:
```pug

@@ -52,10 +59,10 @@ - var someData = require('some-data.json');

```
- bugfix: fix issues by samples
- fix issues by samples
## 1.4.1 (2021-11-17)
- improvement: inner optimizations for the `render` method
- update: code cleanup
- code cleanup
## 1.4.0 (2021-11-16)
- feature: added the option `esModule` to enable/disable ES modules syntax in generated JS modules
- added the option `esModule` to enable/disable ES modules syntax in generated JS modules
- improvement: some code improvements

@@ -67,17 +74,17 @@

## 1.3.0 (2021-11-15)
- feature: the `render` method has been improved. Now the method render a pug into HTML really at compile time without limitations for resolving an embedded resource.
- the `render` method has been improved. Now the method render a pug into HTML really at compile time without limitations for resolving an embedded resource.
This method do same result as any other pug-loader + html-loader, even faster, generate smaller code and with all that not need an additional loader.
- update: some code and test refactorings
- refactoring
## 1.2.0 (2021-11-12)
- feature: added for the loader option `method` new value `html` to render the template function into pure HTML string,\
- added the new loader method `html` to render the template function into pure HTML string,\
this method require additional loader, e.g. `html-loader`
- update: added directory with samples for usage this loader with Angular Component
- added directory with samples for usage this loader with Angular Component
## 1.1.1 (2021-11-10)
- bugfix: fix config for tests
- update: cleanup tests
- fix config for tests
- cleanup tests
## 1.1.0 (2021-11-10)
- feature: usage of `compile` or `render` methods in JavaScript:
- added supports for usage of `compile` or `render` methods in JavaScript:
- added loader option `method: render|compile` to render into HTML or compile into a template function all templates required in js file

@@ -88,21 +95,20 @@ - in the js require() can be used the query parameter `?pug-render` to render the pug template directly into HTML, independent of loader option `method`, \

e.g. `const tmpl = require('template.pug?pug-compile')`
- feature: pass a custom data into a template at compile time:
- added the passing a custom data into a template at compile time:
- added loader option `data: {}` to pass a data into all templates at compile time, e.g. useful for the i18n data
- in the js require () query you can use URL `key=value` or JSON `{key:value}` parameters to pass them into the template at compile time, \
e.g. `const tmpl = require('template.pug?key1=value1&{"key2":"value2","key3":"value3"}')`
- update: dependencies in package.json
- update dependencies in package.json
## 1.0.3 (2021-10-21)
- update: added missed dependency for test
- update: dependencies for test
- update: readme
- added missed dependency for test
- update dependencies for test
- update readme
## 1.0.2 (2021-10-20)
- update: added the test case to cover the `pugjs/pug-loader` [issue](https://github.com/pugjs/pug-loader/issues/123) : `Module not found: Error: Can't resolve` when use a mixin and require on same file.\
note: this pug-loader work fine und hasn't this issue. Here is just added the test case for the problem of pugjs/pug-loader to be sure that this problem doesn't occur in this pug-loader.
- added the test case to cover the `pugjs/pug-loader` [issue](https://github.com/pugjs/pug-loader/issues/123) : `Module not found: Error: Can't resolve` when use a mixin and require on same file.\
## 1.0.1 (2021-10-20)
- update: devDependencies in `package.json`
- update: readme
- update: cleanup code
- update devDependencies in `package.json`
- update readme
- cleanup code

@@ -109,0 +115,0 @@ ## 1.0.0 (2021-10-19)

{
"name": "@webdiscus/pug-loader",
"version": "1.6.0",
"version": "1.6.1-beta.0",
"description": "The pug loader resolves paths and webpack aliases in a pug template and compiles it to HTML or into a template function.",

@@ -65,2 +65,3 @@ "keywords": [

"dependencies": {
"ansis": "^1.3.2",
"pug": ">=3.0.2",

@@ -73,11 +74,13 @@ "webpack-merge": "^5.8.0"

"@types/jest": "^27.4.0",
"css-loader": "^6.5.1",
"html-loader": "^3.1.0",
"html-webpack-plugin": "^5.5.0",
"jest": "^27.4.7",
"jstransformer-markdown-it": "^2.1.0",
"prettier": "^2.5.1",
"pug-plugin": "^1.2.0",
"pug-plugin": "^1.2.1",
"rimraf": "^3.0.2",
"tsconfig-paths-webpack-plugin": "^3.5.2",
"webpack": "^5.65.0"
"webpack": "^5.66.0"
}
}

@@ -11,3 +11,3 @@ [![npm](https://img.shields.io/npm/v/@webdiscus/pug-loader?logo=npm&color=brightgreen "npm package")](https://www.npmjs.com/package/@webdiscus/pug-loader "download npm package")

Webpack loader for the [Pug](https://pugjs.org) templates.\
The pug loader resolves paths and webpack aliases for `extends`/`include`/`require()` in a pug template and compiles it to HTML or into a template function.
The pug loader resolves paths and webpack aliases for `extends`/`include`/`require()` in a pug template and compiles it to HTML or to a template function.

@@ -21,5 +21,5 @@ > **NEW:** The `pug-loader` is now the part of the [pug-plugin](https://github.com/webdiscus/pug-plugin).

- supports features and options of original [`pugjs/pug-loader`](https://github.com/pugjs/pug-loader/)
- up to 4x faster than original `pugjs/pug-loader` at webpack starting
- up to 8x faster than original `pugjs/pug-loader` at webpack watching during compile changes in dependencies
- many time faster than original `pugjs/pug-loader`
- supports Webpack `resolve.alias` and `resolve.plugins`, works with and without the prefixes `~` `@`
- supports path resolving from `tsconfig.json` using [`tsconfig-paths-webpack-plugin`](https://github.com/dividab/tsconfig-paths-webpack-plugin)
- supports integration with `Angular Component`

@@ -525,3 +525,3 @@ - supports the syntax of `CommonJS` and `ES modules` in generated templates for loading them via `require` or `import`

options: {
esModule: false, // need to allow use require() for load a tempale in JavaScript
esModule: false, // allow to use the require() for load a templqte in JavaScript
},

@@ -816,27 +816,2 @@ },

### Known issues / features by usage embedded resources
Due to the peculiarities of the pug compiler,
the interpolation of the argument to the `require()` function depends on its string and variable parts.\
Use a relative path only in the string before the variable.
The variable must contain only the filename without specifying a path.
Examples of <span style="color: red">incorrect</span> usage:
```pug
- filename = './image.jpeg'
img(src=require(filename))
```
```pug
- filename = '../relative/path/to/resource/image.jpeg'
img(src=require(filename))
```
Examples of <span style="color: green">correct</span> usage:
```pug
- filename = 'image.jpeg'
img(src=require(filename))
```
```pug
- filename = 'image.jpeg'
img(src=require('../relative/path/to/resource/' + filename))
```
The example of dynamically generating embedded resources in template:

@@ -846,5 +821,7 @@ ```pug

each file in files
img(src=require('../images/' + file))
img(src=require(file))
```
### File resolving examples
The example of webpack alias used in the table below:

@@ -854,3 +831,3 @@ ```

alias: {
SourceImages: path.join(__dirname, 'src/images/'),
Images: path.join(__dirname, 'src/images/'),
},

@@ -860,26 +837,24 @@ }

Examples for using embedded resources:
| Code | @webdiscus/pug-loader | pugjs/pug-loader |
|----------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------|-----------------------------------------|
| `img(src=require('image.jpeg'))` | <span style="color:green">**OK**</span> | <span style="color:red">fail</span> |
| `img(src=require('./image.jpeg'))` | <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span> |
| `img(src=require('./images/image.jpeg'))` | <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span> |
| `img(src=require('../images/image.jpeg'))` | <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span> |
| `img(src=require('Images/image.jpeg'))` | <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span> |
| `- var file = 'image.jpeg'`<br>`img(src=require('Images/' + file))` | <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span> |
| `- var file = 'image.jpeg'`<br>``img(src=require(`Images/${file}`))`` | <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span> |
| `- var file = 'image.jpeg'`<br>`img(src=require(file))` | <span style="color:green">**OK**</span> | <span style="color:red">fail</span> |
| `- var file = 'image.jpeg'`<br> ``img(src=require(`${file}`))`` | <span style="color:green">**OK**</span> | <span style="color:red">fail</span> |
| `- var file = 'image.jpeg'`<br>`img(src=require('./' + file))` | <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span> |
| `- var file = './image.jpeg'`<br>`img(src=require(file))` | <span style="color:green">**OK**</span> | <span style="color:red">fail</span> |
| `- var file = './image.jpeg'`<br>`img(src=require('' + file))` | <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span> |
| `- var file = 'images/image.jpeg'`<br>`img(src=require(file))` | <span style="color:green">**OK**</span> | <span style="color:red">fail</span> |
| `- var file = 'image.jpeg'`<br>`img(src=require('./images/' + file))` | <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span> |
| `- var file = 'image.jpeg'`<br>``img(src=require(`./images/${file}`))`` | <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span> |
| `- var file = '../images/image.jpeg'`<br>`img(src=require(file))` | <span style="color:green">**OK**</span> | <span style="color:red">fail</span> |
| `- var file = 'image.jpeg'`<br>`img(src=require('../images/' + file))` | <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span> |
| `- var file = 'image.jpeg'`<br>``img(src=require(`../images/${file}`))`` | <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span> |
| the `pugjs/pug-loader` can't resolve when used a mixin and require on same file: <br> `include mixins`<br>`img(src=require('./image.jpeg'))` | <span style="color:green">**OK**</span> | <span style="color:red">fail</span> |
Code | @webdiscus/pug-loader| pugjs/pug-loader | Note
---|---|---|---
`img(src=require('image.jpeg'))`| <span style="color:green">**OK**</span> | <span style="color:red">fail</span>
`img(src=require('./image.jpeg'))`| <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span>
`img(src=require('./images/image.jpeg'))`| <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span>
`img(src=require('../images/image.jpeg'))`| <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span>
`img(src=require('SourceImages/image.jpeg'))`| <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span> | Usage of the webpack alias to images directory.
`- file = 'image.jpeg'`<br>`img(src=require('SourceImages/' + file))`| <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span>
`- file = 'image.jpeg'`<br>``img(src=require(`SourceImages/${file}`))``|<span style="color:green">**OK**</span> | <span style="color:green">**OK**</span>
`- file = 'image.jpeg'`<br>`img(src=require(file))`| <span style="color:green">**OK**</span> | <span style="color:red">fail</span>
`- file = 'image.jpeg'`<br> ``img(src=require(`${file}`))``| <span style="color:green">**OK**</span> | <span style="color:red">fail</span>
`- file = 'image.jpeg'`<br>`img(src=require('./' + file))`| <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span>
`- file = './image.jpeg'`<br>`img(src=require(file))`| <span style="color:red">fail</span> | <span style="color:red">fail</span> | Don't use `./` in variable of filename.
`- file = './image.jpeg'`<br>`img(src=require('' + file))`| <span style="color:red">fail</span> | <span style="color:green">**OK**</span> | Don't use `./` in variable of filename.
`- file = 'images/image.jpeg'`<br>`img(src=require(file))`| <span style="color:green">**OK**</span> | <span style="color:red">fail</span>
`- file = 'image.jpeg'`<br>`img(src=require('./images/' + file))`| <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span>
`- file = 'image.jpeg'`<br>``img(src=require(`./images/${file}`))``| <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span>
`- file = '../images/image.jpeg'`<br>`img(src=require(file))`| <span style="color:red">fail</span> | <span style="color:red">fail</span> | Don't use a path in a variable.
`- file = 'image.jpeg'`<br>`img(src=require('../images/' + file))`| <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span> | Define a path separately as string and add to she the variable contained only a filename.
`- file = 'image.jpeg'`<br>``img(src=require(`../images/${file}`))``| <span style="color:green">**OK**</span> | <span style="color:green">**OK**</span>
Include the template from sub directory: <br> `include mixins`<br>``img(src=require('./image.jpeg'))``| <span style="color:green">**OK**</span> | <span style="color:red">fail</span> | when use a mixin and require on same file, then `pugjs/pug-loader` can't resolve the file in require().
---

@@ -913,6 +888,4 @@ > Important: in examples used name of loader as `pug-loader`, because it is defined as **alias** at resolveLoader:

<!-- prettier-ignore-start -->
[pug]: https://github.com/pugjs/pug
[pug-api]: https://pugjs.org/api/reference.html
[pug-plugin]: https://github.com/webdiscus/pug-plugin
<!-- prettier-ignore-end -->

@@ -8,20 +8,10 @@ // add polyfill for node.js >= 12.0.0 && < 15.0.0

const { merge } = require('webpack-merge');
const {
resolveTemplatePath,
resolveRequireCode,
resolveRequireResource,
getResourceParams,
injectExternalVariables,
} = require('./utils');
const { getPugResolverSync, getDirResolverSync } = require('./resolver');
const loaderMethods = require('./loader-methods');
const loader = 'pug-loader';
const { loaderName, getResourceParams, injectExternalVariables } = require('./utils');
const resolver = require('./resolver');
const loader = require('./loader');
// the variables with global scope for the resolvePlugin
let webpackResolveAlias = null,
loaderMethod = null,
let loaderMethod = null,
codeDependencies = [],
loaderContext = null,
resolvePugSync,
resolveDirSync;
loaderContext = null;

@@ -38,52 +28,8 @@ /**

* @param {string} filename The extends/include filename in template.
* @param {string} source The absolute path to template.
* @param {string} templateFile The absolute path to template.
* @param {{}} options The options of pug compiler.
* @return {string}
*/
resolve: (filename, source, options) => {
const originalFile = filename.trim();
let result = originalFile;
resolve: (filename, templateFile, options) => resolver.resolve(filename.trim(), templateFile.trim()),
// absolute path is resolved by prepending options.basedir
if (originalFile[0] === '/') {
if (!options.basedir) optionBasedirException();
return path.join(options.basedir, originalFile);
}
// relative to the current file
if (originalFile[0] === '.') {
return path.join(path.dirname(source.trim()), result);
}
if (!source) noSourceException();
// resolve by `resolve.alias`
if (webpackResolveAlias) {
result = resolveTemplatePath(originalFile, webpackResolveAlias);
}
// #Method 1
// fallback to slow resolver for `resolve.plugins`
// resolve alias or relative path to the current file
// note: relative path is allowed without `./`
// see https://pugjs.org/language/includes.html
if (result === originalFile) {
result = resolvePugSync(path.dirname(source.trim()), filename);
//console.log('### RESOLVE\nfile:', filename, '\nsource:', source, '\n==', result);
}
// #Method 2
// fallback to slow resolver for `resolve.plugins`,
// the alias must begin with any non-word char, like @ or ~
// if (result === originalFile && !/^[a-z]{1}/i.test(result)) {
// result = resolvePugSync(filename);
// console.log('### RESOLVE\nfile:', filename, '\nsource:', source, '\n==', result);
// }
// if (!path.isAbsolute(result)) {
// result = path.join(path.dirname(source.trim()), result);
// }
return result;
},
/**

@@ -100,3 +46,3 @@ * Resolve the filename for require().

if (containRequire(node)) {
let result = resolveRequireCode(node.filename, node.val, webpackResolveAlias, codeDependencies);
let result = resolver.resolveRequireCode(node.filename, node.val, codeDependencies);
if (result && result !== node.val) node.val = result;

@@ -108,3 +54,3 @@ }

if (containRequire(attr)) {
let result = resolveRequireResource(attr.filename, attr.val, webpackResolveAlias, loaderMethod);
let result = resolver.resolveRequireResource(attr.filename, attr.val, loaderMethod);
if (result && result !== attr.val) attr.val = result;

@@ -125,10 +71,2 @@ }

const optionBasedirException = () => {
throw new Error(`[${loader}] the "basedir" option is required to use includes and extends with "absolute" paths.`);
};
const noSourceException = () => {
throw new Error(`[${loader}] the "filename" option is required to use includes and extends with "relative" paths.`);
};
/**

@@ -140,2 +78,3 @@ * @param {string} content The pug template.

const compilePugContent = function (content, callback) {
const webpackOptionsResolve = this._compiler.options.resolve || {};
let res = {};

@@ -147,9 +86,9 @@

resourceParams = getResourceParams(loaderContext.resourceQuery),
// the rule: a method defined in the resource query has highest priority over a method defined in the loader options
// because a method from loader options is global but a query method override by local usage a global method
methodFromQuery = loaderMethods.find((item) => resourceParams.hasOwnProperty(item.queryParam)),
methodFromOptions = loaderMethods.find((item) => loaderOptions.method === item.method);
// the rule: a method defined in the resource query has highest priority over a method defined in the loaderName options
// because a method from loaderName options is global but a query method override by local usage a global method
methodFromQuery = loader.methods.find((item) => resourceParams.hasOwnProperty(item.queryParam)),
methodFromOptions = loader.methods.find((item) => loaderOptions.method === item.method);
// define the `loaderMethod` for global scope in this module
loaderMethod = methodFromQuery || methodFromOptions || loaderMethods[0];
loaderMethod = methodFromQuery || methodFromOptions || loader.methods[0];

@@ -181,2 +120,6 @@ const options = {

// initialize the resolver
resolver.init(options.basedir, this.rootContext, webpackOptionsResolve);
loader.setResolver(resolver);
loaderContext.cacheable && loaderContext.cacheable(true);

@@ -190,3 +133,3 @@

if (exception.filename) loaderContext.addDependency(path.normalize(exception.filename));
callback(`\n[${loader}] Pug compilation failed.\n` + exception.toString());
callback(`\n[${loaderName}] Pug compilation failed.\n` + exception.toString());
return;

@@ -210,12 +153,5 @@ }

module.exports = function (content, map, meta) {
const webpackResolve = this._compiler.options.resolve || {};
const callback = this.async();
loaderContext = this;
// save resolve.alias from webpack config for global scope in this module, defaults the `webpackResolveAlias` is null
if (webpackResolve.alias && Object.keys(webpackResolve.alias).length > 0) webpackResolveAlias = webpackResolve.alias;
resolvePugSync = getPugResolverSync(this.rootContext, webpackResolve);
//resolveDirSync = getDirResolverSync(this.rootContext, webpackResolve);
compilePugContent.call(this, content, (err, result) => {

@@ -222,0 +158,0 @@ if (err) return callback(err);

// the 'enhanced-resolve' package already used in webpack, don't need to define it in package.json
const ResolverFactory = require('enhanced-resolve');
const path = require('path');
const ansis = require('ansis');
const { loaderName, isWin, pathToPosix } = require('./utils');
// reserved for next release
const DirectoryResolvePlugin = require('./directory-resolve-plugin');
/**
* Create regexp to match alias.
*
* @param {string} match The matched alias.
* @return {string} The regexp pattern with matched aliases.
*/
const aliasRegexp = (match) => `^[~@]?(${match})(?=\\/)`;
/**
* Resolve an alias in the argument of require() function.
*
* @param {string} value The value of extends/include/require().
* @param {{}} aliases The `resolve.alias` of webpack config.
* @return {string | false} If found an alias return resolved normalized path otherwise return false.
*/
const resolveAlias = (value, aliases) => {
if (!aliases) return false;
const patternAliases = Object.keys(aliases).join('|');
// webpack.alias is empty
if (!patternAliases) return false;
const [, alias] = new RegExp(aliasRegexp(patternAliases)).exec(value) || [];
// path contains no alias
if (!alias) return false;
let resolvedFile = value.replace(new RegExp(aliasRegexp(alias)), aliases[alias]);
return path.join(resolvedFile);
};
/**
* @param {string} path The start path to resolve.

@@ -12,3 +45,3 @@ * @param {{}} options The enhanced-resolve options.

*/
const getPugResolverSync = (path, options) => {
const getFileResolverSync = (path, options) => {
const resolve = ResolverFactory.create.sync({

@@ -23,4 +56,3 @@ ...options,

mainFiles: [],
extensions: ['.pug'],
restrictions: [/\.(pug)$/i],
extensions: [],
preferRelative: true,

@@ -36,39 +68,116 @@ });

const resolveException = (file, templateFile, error) => {
throw new Error(
`\n${ansis.black.bgRedBright(`[${loaderName}]`)} the file ${ansis.yellow(
file
)} can't be resolved in the pug template:\n` +
ansis.cyan(templateFile) +
``
);
};
/**
* TODO resolve only directory, without file
*
* @param {string} path The start path to resolve.
* @param {{}} options The enhanced-resolve options.
* @returns {function(context:string, request:string): string | false}
* @typedef {Object} LoaderResolver
* @property {function(basedir:string, path:string, options:{})} init
* @property {(function(context:string, file:string): string)} resolve
* @property {function(templateFile:string, value:string, dependencies:string[]): string} resolveRequireCode
* @property {function(templateFile:string, value:string, method:LoaderMethod): string} resolveRequireResource
*/
const getDirResolverSync = (path, options) => {
const resolve = ResolverFactory.create.sync({
...options,
aliasFields: [],
conditionNames: [],
descriptionFiles: [],
mainFields: [],
mainFiles: [],
extensions: [],
exportsFields: [],
modules: [],
let pugLoaderBasedir = '/';
let aliases = null;
let resolveFile = null;
plugins: [
'...',
//new DirectoryResolvePlugin('undescribed-existing-directory', 'resolved'), // ok for resolve.alias
//new DirectoryResolvePlugin('relative', 'resolved'), // ok for resolve.alias, but not for resolve.plugins
//new DirectoryResolvePlugin('resolved', 'file'), // max
new DirectoryResolvePlugin('directory', 'relative'), //
],
/**
* @type LoaderResolver
*/
const resolver = {
/**
* @param {string} basedir The the root directory of all absolute inclusion.
* @param {string} path The root context path.
* @param {{}} options The webpack `resolve` configuration.
*/
init: (basedir, path, options) => {
pugLoaderBasedir = basedir;
aliases = options.alias;
resolveFile = getFileResolverSync(path, options);
},
preferRelative: true,
});
/**
* Resolve filename.
*
* @param {string} file The file to resolve.
* @param {string} templateFile The template file.
* @return {string}
*/
resolve: (file, templateFile) => {
const context = path.dirname(templateFile);
let resolvedPath;
return (request) => resolve(path, request);
// resolve an absolute path by prepending options.basedir
if (file[0] === '/') {
resolvedPath = path.join(pugLoaderBasedir, file);
}
// resolve a relative file
if (!resolvedPath && file[0] === '.') {
resolvedPath = path.join(context, file);
}
// resolve a file by webpack `resolve.alias`
if (!resolvedPath) {
resolvedPath = resolveAlias(file, aliases);
}
// fallback to enhanced resolver
if (!resolvedPath) {
try {
resolvedPath = resolveFile(context, file);
} catch (error) {
resolveException(file, templateFile, error);
}
}
// Windows only: fix the path format
if (isWin) resolvedPath = pathToPosix(resolvedPath);
return resolvedPath;
},
/**
* Resolve the code file path in require().
*
* @param {string} templateFile The filename of the template where resolves the resource.
* @param {string} value The resource value include require().
* @param {string[]} dependencies The list of dependencies for watching.
* @return {string}
*/
resolveRequireCode: (templateFile, value, dependencies) =>
value.replaceAll(/(require\(.+?\))/g, (value) => {
const [, file] = /(?<=require\("|'|`)(.+)(?=`|'|"\))/.exec(value) || [];
let resolvedPath = resolver.resolve(file, templateFile);
// Important: delete the file from require.cache to allow reloading cached files after changes by watch.
delete require.cache[resolvedPath];
dependencies.push(resolvedPath);
return `require('${resolvedPath}')`;
}),
/**
* Resolve a path in the argument of require() function.
*
* @param {string} templateFile The filename of the template where resolves the resource.
* @param {string} value The resource value include require().
* @param {LoaderMethod} method The object of the current method.
* @return {string}
*/
resolveRequireResource: (templateFile, value, method) => {
const [, file] = /(?<=require\()(.+)(?=\))/.exec(value) || [];
if (!file) return value;
return method.requireResource(file, templateFile);
},
};
module.exports = {
getPugResolverSync,
getDirResolverSync,
};
module.exports = resolver;
const path = require('path');
const { merge } = require('webpack-merge');
const loaderName = 'pug-loader';
const isWin = path.sep === '\\';

@@ -66,121 +68,2 @@ const isJSON = (str) => typeof str === 'string' && str.length > 1 && str[0] === '{' && str[str.length - 1] === '}';

/**
* Create regexp to match alias for extends / include / raw include.
*
* @param {string} match The matched alias.
* @return {string} The regex pattern with matched aliases.
*/
const regexpFileAlias = (match) => `^[~@]?(${match})(?=\\/)`;
/**
* Create regexp to match alias for require('').
*
* @param {string} match The matched alias.
* @return {string} The regex pattern with matched aliases.
*/
const regexpRequireAlias = (match) => `(?<=["'\`])[~@]?(${match})(?=\\/)`;
/**
* Resolve a path in pug template.
*
* @param {string} value value The value of extends/include.
* @param {{}} aliases The `resolve.alias` of webpack config.
* @return {string}
*/
const resolveTemplatePath = (value, aliases) => resolveAlias(value, aliases, regexpFileAlias);
/**
* Resolve the code file path in require().
*
* @param {string} templateFile The filename of the template where resolves the resource.
* @param {string} value The resource value include require().
* @param {{}} aliases The resolve.alias from webpack config.
* @param {string[]} dependencies The list of dependencies for watching.
* @return {string}
*/
const resolveRequireCode = (templateFile, value, aliases, dependencies) =>
value.replaceAll(/(require\(.+?\))/g, (value) => {
const [, sourcePath] = /(?<=require\("|'|`)(.+)(?=`|'|"\))/.exec(value) || [];
let resolvedPath = resolveTemplatePath(sourcePath, aliases);
if (resolvedPath === sourcePath) resolvedPath = path.join(path.dirname(templateFile), sourcePath);
// Windows only: fix the path format
if (isWin) resolvedPath = pathToPosix(resolvedPath);
// Important: delete the file from require.cache to allow reload cached files after changes by watch.
delete require.cache[resolvedPath];
dependencies.push(resolvedPath);
return `require('${resolvedPath}')`;
});
/**
* Resolve a path in the argument of require() function.
*
* @param {string} templateFile The filename of the template where resolves the resource.
* @param {string} value The resource value include require().
* @param {{}} aliases The resolve.alias from webpack config.
* @param {LoaderMethod} method The object of the current method.
* @return {string|null}
*/
const resolveRequireResource = function (templateFile, value, aliases, method) {
// match an argument of require(sourcePath)
const [, sourcePath] = /(?<=require\()(.+)(?=\))/.exec(value) || [];
if (!sourcePath) return value;
let resourcePath = sourcePath;
// replace alias with absolute path
let resolvedPath = resolveAlias(resourcePath, aliases, regexpRequireAlias);
// if the alias is not found in the path,
// then add the absolute path of the current template at the beginning of the argument,
// e.g. like this require('/path/to/template/' + 'filename.jpeg')
if (resolvedPath === resourcePath) {
// delete `./` from path, because at begin will be added full path like `/path/to/current/dir/`
resourcePath = resourcePath.replace(/(?<=[^\.])(\.\/)/, '');
// if an argument of require() begin with a relative parent path as the string template with a variable,
// like require(`../images/${file}`), then extract the relative path to the separate string
if (resourcePath.indexOf('`../') === 0) {
const relPathRegex = /(?<=`)(.+)(?=\$\{)/;
const [, relPath] = relPathRegex.exec(value);
if (relPath) {
resourcePath = `'${relPath}' + ` + resourcePath.replace(relPathRegex, '');
}
}
resolvedPath = `'${path.dirname(templateFile)}/' + ${resourcePath}`;
}
// Windows only: fix the path format
if (isWin) resolvedPath = pathToPosix(resolvedPath);
return method.requireResource(resolvedPath);
};
/**
* Replace founded alias in require argument.
*
* @param {string} value The value of extends/include/require().
* @param {{}} aliases The `resolve.alias` of webpack config.
* @param {function(string):string} regexp The function return a regex pattern string. The argument is alias name.
* @return {string} The string with replaced alias.
*/
const resolveAlias = (value, aliases, regexp) => {
if (!aliases) return value;
const patternAliases = Object.keys(aliases).join('|');
// webpack.alias is empty
if (!patternAliases) return value;
const [, alias] = new RegExp(regexp(patternAliases)).exec(value) || [];
// path contains no alias
if (!alias) return value;
return value.replace(new RegExp(regexp(alias)), aliases[alias]).replace('//', '/');
};
/**
* Inject external variables from the resource query, from the loader options

@@ -200,9 +83,7 @@ * and merge them variables with the `locals` variable.

module.exports = {
loaderName,
isWin,
pathToPosix,
getResourceParams,
resolveTemplatePath,
resolveRequireCode,
resolveRequireResource,
injectExternalVariables,
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc