Skip to content

Commit

Permalink
Merge pull request #5 from webdiscus/issue3-alias-windows
Browse files Browse the repository at this point in the history
 bugfix: path resolving on windows; issues #3, #4
  • Loading branch information
webdiscus authored Dec 10, 2021
2 parents b2ed6a3 + 63d9455 commit 5f089b1
Show file tree
Hide file tree
Showing 27 changed files with 300 additions and 145 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Change log

## 1.5.1 (2021-12-10)
- bugfix: fix path resolving on windows
- some optimisations
- code refactoring

## 1.5.0 (2021-12-07)
- 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
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ 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.

> **NEW:** The `pug-loader` is now the part of the [pug-plugin](https://github.com/webdiscus/pug-plugin).
> This plugin extract HTML and CSS from `pug` `html` `scss` files defined by webpack entry into output directory.
> This plugin extracts HTML from the `pug` files defined in the webpack entry and save them in the output directory.
> Now is possible define `pug` files directly in `webpack entry`. [See usage examples](https://github.com/webdiscus/pug-plugin#usage-examples).
## Features
Expand All @@ -33,7 +33,7 @@ The pug loader resolves paths and webpack aliases for `extends`/`include`/`requi
```
supports the `require()` for CommonJS and JSON files in pug templates **by all methods**, e.g.: \
`data.json`
```jsson
```json
[
{ "id": 1, "name": "abc" },
{ "id": 2, "name": "xyz" }
Expand Down Expand Up @@ -459,7 +459,7 @@ The result of `console.log(html)`:
</div>
```

[See the simple web app example >>](https://github.com/webdiscus/pug-loader/tree/master/examples/webpack-app-hello-pug/)
See [the simple web app example](https://github.com/webdiscus/pug-loader/tree/master/examples/webpack-app-hello-pug/).

<a id="usage-in-pug-javascript" name="usage-in-pug-javascript" href="#usage-in-pug-javascript"></a>
## Usage methods `compile`, `render` or `html` in JavaScript
Expand Down Expand Up @@ -682,7 +682,7 @@ h1 Hello Pug!
p Description: #{description}
```

[See the source files of this example >>](https://github.com/webdiscus/pug-loader/tree/master/examples/angular-component-render/)
See [the source files of this example](https://github.com/webdiscus/pug-loader/tree/master/examples/angular-component-render/).


### Alternative usage with additional `html-loader`
Expand Down Expand Up @@ -735,7 +735,7 @@ module.exports = {

```

[See the source files of this example >>](https://github.com/webdiscus/pug-loader/tree/master/examples/angular-component-html/)
See [the source files of this example](https://github.com/webdiscus/pug-loader/tree/master/examples/angular-component-html/).


<a id="passing-data-into-template" name="passing-data-into-template" href="#passing-data-into-template"></a>
Expand Down
2 changes: 1 addition & 1 deletion examples/angular-component-html/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"@angular/compiler-cli": "~13.0.0",
"@types/jasmine": "~3.10.0",
"@types/node": "^12.11.1",
"@webdiscus/pug-loader": "^1.5.0",
"@webdiscus/pug-loader": "^1.5.1",
"html-loader": "^3.0.1",
"pug-plugin-ng": "^0.0.3",
"jasmine-core": "~3.10.0",
Expand Down
2 changes: 1 addition & 1 deletion examples/angular-component-render/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"@angular/compiler-cli": "~13.0.0",
"@types/jasmine": "~3.10.0",
"@types/node": "^12.11.1",
"@webdiscus/pug-loader": "^1.5.0",
"@webdiscus/pug-loader": "^1.5.1",
"html-loader": "^3.0.1",
"pug-plugin-ng": "^0.0.3",
"jasmine-core": "~3.10.0",
Expand Down
2 changes: 1 addition & 1 deletion examples/webpack-app-hello-pug/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"author": "",
"license": "ISC",
"devDependencies": {
"@webdiscus/pug-loader": "^1.5.0",
"@webdiscus/pug-loader": "^1.5.1",
"pug-plugin": "^1.1.0",
"webpack": "^5.64.0",
"webpack-cli": "^4.9.1",
Expand Down
5 changes: 1 addition & 4 deletions examples/webpack-app-hello-pug/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,7 @@ module.exports = {
name: 'Firefox',
},
},*/
hot: false,
//hot: true,
//liveReload: true,
liveReload: false,
liveReload: true,

client: {
progress: true,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@webdiscus/pug-loader",
"version": "1.5.0",
"version": "1.5.1",
"description": "The pug loader resolves paths and webpack aliases in a pug template and compiles it to HTML or into a template function.",
"keywords": [
"pug",
Expand Down
106 changes: 67 additions & 39 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,67 +5,95 @@ const path = require('path'),
pug = require('pug'),
walk = require('pug-walk'),
{ merge } = require('webpack-merge'),
{ resolveTemplatePath, resolveResourcePath, getResourceParams, injectExternalVariables } = require('./utils'),
loaderMethods = require('./loader-methods');
{
resolveTemplatePath,
resolveRequireCode,
resolveRequireResource,
getResourceParams,
injectExternalVariables,
} = require('./utils'),
loaderMethods = require('./loader-methods'),
loader = 'pug-loader';

// the variables with global scope for the resolvePlugin
let webpackResolveAlias = {},
loaderMethod = null,
codeDependencies = [];

const isRendering = (loaderMethod) => ['html', 'render'].indexOf(loaderMethod.method) > -1;

/**
* Resolve the code file path in require ().
* The pug plugin to resolve path for include, extends, 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.
* @return {string}
*/
const resolveCodePath = (templateFile, value, aliases) =>
value.replaceAll(/(require\(.+?\))/g, (value) => {
const [, sourcePath] = /(?<=require\("|'|`)(.+)(?="|'|`\))/.exec(value) || [];
let resolvedPath = resolveTemplatePath(sourcePath, aliases);
if (sourcePath === resolvedPath) resolvedPath = path.join(path.dirname(templateFile), resolvedPath);

// Important: delete the file from require.cache to allow reload cached files after changes by watch.
delete require.cache[resolvedPath];
codeDependencies.push(resolvedPath);

return `require('${resolvedPath}')`;
});

/**
* The pug plugin to resolve path for include, extend, require.
*
* @type {{preLoad: (function(*): *)}}
* @type {{resolve: (function(string, string, {}): string), preCodeGen: (function({}): *)}}
*/
const resolvePlugin = {
preLoad: (ast) =>
/**
* Resolve the filename for extends / include / raw include.
*
* @param {string} filename The extends/include filename in template.
* @param {string} source The absolute path to template.
* @param {{}} options The options of pug compiler.
* @return {string}
*/
resolve: (filename, source, options) => {
let resolvedFile = filename.trim();

if (resolvedFile[0] === '/') {
if (!options.basedir) optionBasedirException();
resolvedFile = path.join(options.basedir, resolvedFile);
} else {
if (!source) noSourceException();
resolvedFile = resolveTemplatePath(resolvedFile, webpackResolveAlias);
// note: on windows an absolute path begin not with `/` otherwise as like `C:\`
if (!path.isAbsolute(resolvedFile)) {
resolvedFile = path.join(path.dirname(source.trim()), resolvedFile);
}
}

return resolvedFile;
},

/**
* Resolve the filename for require().
*
* @param {{}} ast The parsed tree of pug template.
* @return {{}}
*/
preCodeGen: (ast) =>
walk(ast, (node) => {
if (node.type === 'FileReference') {
// resolving for extends/include
let result = resolveTemplatePath(node.path, webpackResolveAlias);
if (result && result !== node.path) node.path = result;
} else if (node.type === 'Code' && isRendering(loaderMethod)) {
// resolving for require of a code, e.g.: `- var data = require('./data.js')` (its need only by rendering)
if (node.val && node.val.indexOf('require(') > 0) {
let result = resolveCodePath(node.filename, node.val, webpackResolveAlias);
if (node.type === 'Code') {
// resolving for require of a code, e.g.: `- var data = require('./data.js')`
if (containRequire(node)) {
let result = resolveRequireCode(node.filename, node.val, webpackResolveAlias, codeDependencies);
if (result && result !== node.val) node.val = result;
}
} else if (node.attrs) {
// resolving for tag attributes, e.g.: img(src=require('./image.jpeg'))
node.attrs.forEach((attr) => {
if (attr.val && typeof attr.val === 'string' && attr.val.indexOf('require(') === 0) {
let result = resolveResourcePath(attr.filename, attr.val, webpackResolveAlias, loaderMethod);
if (containRequire(attr)) {
let result = resolveRequireResource(attr.filename, attr.val, webpackResolveAlias, loaderMethod);
if (result && result !== attr.val) attr.val = result;
}
});
}
}),
};

/**
* Whether the node value contains the require().
*
* @param {{val: *}} obj
* @return {boolean}
*/
const containRequire = (obj) => obj.val && typeof obj.val === 'string' && obj.val.indexOf('require(') >= 0;

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.`);
};

/**
* @param {string} content The pug template.
* @param {function(error: string|null, result: string?)?} callback The asynchronous callback function.
Expand Down Expand Up @@ -119,7 +147,7 @@ const compilePugContent = function (content, callback) {
} catch (exception) {
// watch files in which an error occurred
if (exception.filename) loaderContext.addDependency(path.normalize(exception.filename));
callback('\n[pug-loader] Pug compilation failed.\n' + exception.toString());
callback(`\n[${loader}] Pug compilation failed.\n` + exception.toString());
return;
}

Expand Down
2 changes: 1 addition & 1 deletion src/loader-methods.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const loaderMethods = [
method: 'render',
queryParam: 'pug-render',
// the result of compiled string must be exact as this:
//requireResource: (file) => "((file) => `' + require('${file}') + '`)(" + file + ')',
// requireResource: (file) => "((file) => `' + require('${file}') + '`)(" + file + ')',
// to prevent escaping the 'single quotes' they must be as HTML char '&quot;' encoded and at end decoded:
requireResource: (file) => '((file) => `&quot; + require(&quot;${file}&quot;) + &quot;`)(' + file + ')',
output: (funcBody, locals, esModule) =>
Expand Down
Loading

0 comments on commit 5f089b1

Please sign in to comment.