This commit is contained in:
darenhsu
2022-07-17 13:16:16 +08:00
parent 84759556ff
commit befd344ab0
28070 changed files with 4008428 additions and 1 deletions
+31
View File
@@ -0,0 +1,31 @@
## 1.3.3 (December 19, 2019)
* Fix resource files cache invalidation problems on Windows. [#17](https://github.com/yenshih/style-resources-loader/issues/17)
## 1.3.0 ~ 1.3.2 (November 11, 2019)
* Support for relative path in patterns.
* Ensure each resource ends with a newline.
* More detailed validation messages.
* Fix the regular expression compatibility error. [#20](https://github.com/yenshih/style-resources-loader/issues/20)
* Fix dependency issue of resource files.
## 1.2.1 (August 12, 2018)
* Fix invalid path seperator on Windows. [#8](https://github.com/yenshih/style-resources-loader/issues/8)
## 1.2.0 (August 11, 2018)
* Support for `css` resources. [#7](https://github.com/yenshih/style-resources-loader/issues/7)
* Support for asynchronous injector.
* Improve type checking for loader options.
## 1.1.0 (February 28, 2018)
* Support for `prepend`, `append` injector.
## 1.0.0 (December 5, 2017)
* Initial stable release.
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) Shi Yan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+208
View File
@@ -0,0 +1,208 @@
[![npm][npm]][npm-url]
[![node][node]][node-url]
[![downloads][downloads]][downloads-url]
[![build][build]][build-url]
[![coverage][coverage]][coverage-url]
[![996.icu][996.icu]][996.icu-url]
<div align="center">
<a href="https://github.com/webpack/webpack">
<img
width="200"
height="200"
src="https://webpack.js.org/assets/icon-square-big.svg"
>
</a>
<h1>Style Resources Loader</h1>
<p>CSS processor resources loader for webpack.</p>
</div>
<h2 align="center">Install</h2>
```bash
npm i style-resources-loader -D
```
<h2 align="center">Usage</h2>
This loader is a CSS processor resources loader for webpack, which injects your style resources (e.g. `variables, mixins`) into multiple imported `css, sass, scss, less, stylus` modules.
It's mainly used to
- share your `variables, mixins, functions` across all style files, so you don't need to `@import` them manually.
- override `variables` in style files provided by other libraries (e.g. [ant-design](https://github.com/ant-design/ant-design)) and customize your own theme.
### Usage with Vue CLI
See [automatic imports](https://cli.vuejs.org/guide/css.html#automatic-imports) for more details.
<h2 align="center">Examples</h2>
Prepends `variables` and `mixins` to all `scss` files with default resources injector.
**webpack.config.js**
``` js
module.exports = {
// ...
module: {
rules: [{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader', {
loader: 'style-resources-loader',
options: {
patterns: [
'./path/from/context/to/scss/variables/*.scss',
'./path/from/context/to/scss/mixins/*.scss',
]
}
}]
}]
},
// ...
}
```
Appends `variables` to all `less` files and overrides original `less variables`.
**webpack.config.js**
```js
module.exports = {
// ...
module: {
rules: [{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader', {
loader: 'style-resources-loader',
options: {
patterns: path.resolve(__dirname, 'path/to/less/variables/*.less'),
injector: 'append'
}
}]
}]
},
// ...
}
```
Prepends `variables` and `mixins` to all `stylus` files with customized resources injector.
**webpack.config.js**
``` js
module.exports = {
// ...
module: {
rules: [{
test: /\.styl$/,
use: ['style-loader', 'css-loader', 'stylus-loader', {
loader: 'style-resources-loader',
options: {
patterns: [
path.resolve(__dirname, 'path/to/stylus/variables/*.styl'),
path.resolve(__dirname, 'path/to/stylus/mixins/*.styl')
],
injector: (source, resources) => {
const combineAll = type => resources
.filter(({ file }) => file.includes(type))
.map(({ content }) => content)
.join('');
return combineAll('variables') + combineAll('mixins') + source;
}
}
}]
}]
},
// ...
}
```
<h2 align="center">Options</h2>
|Name|Type|Default|Description|
|:--:|:--:|:-----:|:----------|
|**[`patterns`](#patterns)**|`{string \| string[]}`|`/`|Path to the resources you would like to inject|
|**[`injector`](#injector)**|`{Function \| 'prepend' \| 'append'}`|`'prepend'`|Controls the resources injection precisely|
|**[`globOptions`](#globoptions)**|`{Object}`|`{}`|An options that can be passed to `glob(...)`|
|**[`resolveUrl`](#resolveurl)**|`{boolean}`|`true`|Enable/Disable `@import` url to be resolved|
See [the type definition file](https://github.com/yenshih/style-resources-loader/blob/master/src/types.ts) for more details.
### `patterns`
A string or an array of string, which represents the path to the resources you would like to inject. If the path is relative, it would relative to [webpack context](https://webpack.js.org/configuration/entry-context/).
It supports [globbing](https://github.com/isaacs/node-glob). You could include many files using a file mask.
For example, `'./styles/*/*.less'` would include all `less` files from `variables` and `mixins` directories and ignore `reset.less` in such following structure.
```
./src <-- webpack context
/styles
/variables
|-- fonts.less
|-- colors.less
/mixins
|-- size.less
|-- reset.less
```
Only supports `.css` `.sass` `.scss` `.less` `.styl` as resources file extensions.
### `injector`
An optional function which controls the resources injection precisely. It also supports `'prepend'` and `'append'` for convenience, which means the loader will prepend or append all resources to source files, respectively.
It defaults to `'prepend'`, which implements as an injector function internally.
Furthermore, an injector function should match the following type signature:
```ts
(source: string, resources: StyleResource[]) => string | Promise<string>
```
It receives two parameters:
|Name|Type|Default|Description|
|:--:|:--:|:-----:|:----------|
|**`source`**|`{string}`|`/`|Content of the source file|
|**[`resources`](#resources)**|`{StyleResource[]}`|`/`|Resource descriptors|
#### `resources`
An array of resource descriptor, each contains `file` and `content` properties:
|Name|Type|Default|Description|
|:--:|:--:|:-----:|:----------|
|**`file`**|`{string}`|`/`|Absolute path to the resource|
|**`content`**|`{string}`|`/`|Content of the resource file|
It can be asynchronous. You could use `async / await` syntax in your own injector function or just return a promise.
### `globOptions`
Options that can be passed to `glob(...)`. See [node-glob options](https://github.com/isaacs/node-glob#options) for more details.
### `resolveUrl`
A boolean which defaults to `true`. It represents whether the relative path in `@import` or `@require` statements should be resolved.
If you were to use `@import` or `@require` statements in style resource files, you should make sure that the URL is relative to that resource file, rather than the source file.
You could disable this feature by setting `resolveUrl` to `false`.
<h2 align="center">License</h2>
[MIT](http://www.opensource.org/licenses/mit-license.php)
[npm]: https://img.shields.io/npm/v/style-resources-loader.svg?style=flat-square
[npm-url]: https://www.npmjs.com/package/style-resources-loader
[node]: https://img.shields.io/node/v/style-resources-loader.svg
[node-url]: https://nodejs.org
[downloads]: https://img.shields.io/npm/dm/style-resources-loader.svg?style=flat-square
[downloads-url]: https://www.npmjs.com/package/style-resources-loader
[build]: https://img.shields.io/travis/yenshih/style-resources-loader/master.svg?style=flat-square
[build-url]: https://travis-ci.org/yenshih/style-resources-loader
[coverage]: https://img.shields.io/coveralls/yenshih/style-resources-loader/master.svg?style=flat
[coverage-url]: https://coveralls.io/github/yenshih/style-resources-loader?branch=master
[996.icu]: https://img.shields.io/badge/link-996.icu-%23FF4D5B.svg?style=flat-square
[996.icu-url]: https://996.icu/#/en_US
+1
View File
@@ -0,0 +1 @@
export * from './lib';
+4
View File
@@ -0,0 +1,4 @@
import loader from './loader';
export * from './schema';
export * from './types';
export default loader;
+12
View File
@@ -0,0 +1,12 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const loader_1 = __importDefault(require("./loader"));
__export(require("./schema"));
exports.default = loader_1.default;
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;AAAA,sDAA8B;AAE9B,8BAAyB;AAGzB,kBAAe,gBAAM,CAAC"}
+3
View File
@@ -0,0 +1,3 @@
import { Loader } from '.';
declare const loader: Loader;
export default loader;
+16
View File
@@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("./utils");
const loader = function (source) {
this.cacheable && this.cacheable();
const callback = this.async();
if (!utils_1.isFunction(callback)) {
throw new Error(utils_1.errorMessage.syncCompilation);
}
if (typeof source !== 'string') {
throw new Error(utils_1.errorMessage.impossible);
}
utils_1.loadResources(this, source, callback);
};
exports.default = loader;
//# sourceMappingURL=loader.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":";;AAAA,mCAAgE;AAKhE,MAAM,MAAM,GAAW,UAAS,MAAM;IAClC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;IAEnC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAE9B,IAAI,CAAC,kBAAU,CAAiB,QAAQ,CAAC,EAAE;QACvC,MAAM,IAAI,KAAK,CAAC,oBAAY,CAAC,eAAe,CAAC,CAAC;KACjD;IAGD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QAC5B,MAAM,IAAI,KAAK,CAAC,oBAAY,CAAC,UAAU,CAAC,CAAC;KAC5C;IAGD,qBAAa,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC,CAAC;AAGF,kBAAe,MAAM,CAAC"}
+4
View File
@@ -0,0 +1,4 @@
import validate from 'schema-utils';
declare type Schema = Parameters<typeof validate>[0];
export declare const schema: Schema;
export {};
+39
View File
@@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.schema = {
type: 'object',
properties: {
patterns: {
anyOf: [
{ type: 'string' },
{
type: 'array',
uniqueItems: true,
items: {
type: 'string',
},
},
],
},
injector: {
anyOf: [
{
type: 'string',
enum: ['prepend', 'append'],
},
{
instanceof: 'Function',
},
],
},
globOptions: {
type: 'object',
},
resolveUrl: {
type: 'boolean',
},
},
required: ['patterns'],
additionalProperties: false,
};
//# sourceMappingURL=schema.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":";;AAIa,QAAA,MAAM,GAAW;IAC1B,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACR,QAAQ,EAAE;YACN,KAAK,EAAE;gBACH,EAAC,IAAI,EAAE,QAAQ,EAAC;gBAChB;oBACI,IAAI,EAAE,OAAO;oBACb,WAAW,EAAE,IAAI;oBACjB,KAAK,EAAE;wBACH,IAAI,EAAE,QAAQ;qBACjB;iBACJ;aACJ;SACJ;QACD,QAAQ,EAAE;YACN,KAAK,EAAE;gBACH;oBACI,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC;iBAC9B;gBACD;oBACI,UAAU,EAAE,UAAU;iBACzB;aACJ;SACJ;QACD,WAAW,EAAE;YACT,IAAI,EAAE,QAAQ;SACjB;QACD,UAAU,EAAE;YACR,IAAI,EAAE,SAAS;SAClB;KACJ;IACD,QAAQ,EAAE,CAAC,UAAU,CAAC;IACtB,oBAAoB,EAAE,KAAK;CAC9B,CAAC"}
+24
View File
@@ -0,0 +1,24 @@
import { loader } from 'webpack';
import glob from 'glob';
export declare type Loader = loader.Loader;
export declare type LoaderContext = loader.LoaderContext;
export declare type LoaderCallback = loader.loaderCallback;
export declare type StyleResourcesFileFormat = 'css' | 'sass' | 'scss' | 'less' | 'styl';
export interface StyleResource {
file: string;
content: string;
}
export declare type StyleResources = StyleResource[];
export declare type StyleResourcesFunctionalInjector = (source: string, resources: StyleResources) => string | Promise<string>;
export declare type StyleResourcesInjector = 'prepend' | 'append' | StyleResourcesFunctionalInjector;
export declare type StyleResourcesNormalizedInjector = StyleResourcesFunctionalInjector;
export interface StyleResourcesLoaderOptions {
patterns: string | string[];
injector?: StyleResourcesInjector;
globOptions?: glob.IOptions;
resolveUrl?: boolean;
}
export interface StyleResourcesLoaderNormalizedOptions extends NonNullable<StyleResourcesLoaderOptions> {
patterns: string[];
injector: StyleResourcesNormalizedInjector;
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
+7
View File
@@ -0,0 +1,7 @@
import { StyleResourcesFileFormat } from '..';
export declare const PACKAGE_NAME = "style-resources-loader";
export declare const ISSUES_URL: string;
export declare const LOADER_NAME: string;
export declare const VALIDATION_BASE_DATA_PATH = "options";
export declare const SUPPORTED_FILE_FORMATS: StyleResourcesFileFormat[];
export declare const SUPPORTED_FILE_EXTS: string[];
+11
View File
@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PACKAGE_NAME = 'style-resources-loader';
exports.ISSUES_URL = `https://github.com/yenshih/${exports.PACKAGE_NAME}/issues`;
exports.LOADER_NAME = exports.PACKAGE_NAME.split('-')
.map(word => `${word[0].toUpperCase()}${word.slice(1)}`)
.join(' ');
exports.VALIDATION_BASE_DATA_PATH = 'options';
exports.SUPPORTED_FILE_FORMATS = ['css', 'sass', 'scss', 'less', 'styl'];
exports.SUPPORTED_FILE_EXTS = exports.SUPPORTED_FILE_FORMATS.map(type => `.${type}`);
//# sourceMappingURL=constants.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":";;AAEa,QAAA,YAAY,GAAG,wBAAwB,CAAC;AAExC,QAAA,UAAU,GAAG,8BAA8B,oBAAY,SAAS,CAAC;AAEjE,QAAA,WAAW,GAAG,oBAAY,CAAC,KAAK,CAAC,GAAG,CAAC;KAC7C,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;KACvD,IAAI,CAAC,GAAG,CAAC,CAAC;AAEF,QAAA,yBAAyB,GAAG,SAAS,CAAC;AAEtC,QAAA,sBAAsB,GAA+B,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAE7F,QAAA,mBAAmB,GAAG,8BAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC"}
+5
View File
@@ -0,0 +1,5 @@
export declare const errorMessage: {
impossible: string;
syncCompilation: string;
invalidInjectorReturn: string;
};
+14
View File
@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const _1 = require(".");
const formatErrorMessage = (message) => `[${_1.PACKAGE_NAME}] ${message}`;
const messageByType = {
impossible: `This error is caused by a bug. Please file an issue: ${_1.ISSUES_URL}.`,
syncCompilation: 'Synchronous compilation is not supported.',
invalidInjectorReturn: 'Expected options.injector(...) returns a string. Instead received number.',
};
exports.errorMessage = Object.entries(messageByType).reduce((errorMessage, [type, message]) => ({
...errorMessage,
[type]: formatErrorMessage(message),
}), messageByType);
//# sourceMappingURL=error-message.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"error-message.js","sourceRoot":"","sources":["../../src/utils/error-message.ts"],"names":[],"mappings":";;AAAA,wBAA2C;AAE3C,MAAM,kBAAkB,GAAG,CAAC,OAAe,EAAE,EAAE,CAAC,IAAI,eAAY,KAAK,OAAO,EAAE,CAAC;AAE/E,MAAM,aAAa,GAAG;IAClB,UAAU,EAAE,wDAAwD,aAAU,GAAG;IACjF,eAAe,EAAE,2CAA2C;IAC5D,qBAAqB,EAAE,2EAA2E;CACrG,CAAC;AAEW,QAAA,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,MAAM,CAC5D,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;IAChC,GAAG,YAAY;IACf,CAAC,IAAI,CAAC,EAAE,kBAAkB,CAAC,OAAO,CAAC;CACtC,CAAC,EACF,aAAa,CAChB,CAAC"}
+3
View File
@@ -0,0 +1,3 @@
/// <reference types="webpack" />
import { StyleResource, StyleResourcesLoaderNormalizedOptions } from '..';
export declare const getResources: (ctx: import("webpack").loader.LoaderContext, options: StyleResourcesLoaderNormalizedOptions) => Promise<StyleResource[]>;
+20
View File
@@ -0,0 +1,20 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
const util_1 = __importDefault(require("util"));
const _1 = require(".");
exports.getResources = async (ctx, options) => {
const { resolveUrl } = options;
const files = await _1.matchFiles(ctx, options);
files.forEach(file => ctx.dependency(file));
const resources = await Promise.all(files.map(async (file) => {
const content = await util_1.default.promisify(fs_1.default.readFile)(file, 'utf8');
const resource = { file, content };
return resolveUrl ? _1.resolveImportUrl(ctx, resource) : resource;
}));
return resources;
};
//# sourceMappingURL=get-resources.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"get-resources.js","sourceRoot":"","sources":["../../src/utils/get-resources.ts"],"names":[],"mappings":";;;;;AAAA,4CAAoB;AACpB,gDAAwB;AAIxB,wBAA+C;AAElC,QAAA,YAAY,GAAG,KAAK,EAAE,GAAkB,EAAE,OAA8C,EAAE,EAAE;IACrG,MAAM,EAAC,UAAU,EAAC,GAAG,OAAO,CAAC;IAE7B,MAAM,KAAK,GAAG,MAAM,aAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAE7C,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;IAE5C,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAC,IAAI,EAAC,EAAE;QACnB,MAAM,OAAO,GAAG,MAAM,cAAI,CAAC,SAAS,CAAC,YAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAChE,MAAM,QAAQ,GAAkB,EAAC,IAAI,EAAE,OAAO,EAAC,CAAC;QAEhD,OAAO,UAAU,CAAC,CAAC,CAAC,mBAAgB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IACnE,CAAC,CAAC,CACL,CAAC;IAEF,OAAO,SAAS,CAAC;AACrB,CAAC,CAAC"}
+10
View File
@@ -0,0 +1,10 @@
export * from './constants';
export * from './error-message';
export * from './get-resources';
export * from './inject-resources';
export * from './load-resources';
export * from './match-files';
export * from './normalize-options';
export * from './resolve-import-url';
export * from './type-guards';
export * from './validate-options';
+16
View File
@@ -0,0 +1,16 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("./constants"));
__export(require("./error-message"));
__export(require("./get-resources"));
__export(require("./inject-resources"));
__export(require("./load-resources"));
__export(require("./match-files"));
__export(require("./normalize-options"));
__export(require("./resolve-import-url"));
__export(require("./type-guards"));
__export(require("./validate-options"));
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;AAAA,iCAA4B;AAC5B,qCAAgC;AAChC,qCAAgC;AAChC,wCAAmC;AACnC,sCAAiC;AACjC,mCAA8B;AAC9B,yCAAoC;AACpC,0CAAqC;AACrC,mCAA8B;AAC9B,wCAAmC"}
+2
View File
@@ -0,0 +1,2 @@
import { StyleResources, StyleResourcesLoaderNormalizedOptions } from '..';
export declare const injectResources: (options: StyleResourcesLoaderNormalizedOptions, source: string, resources: StyleResources) => Promise<string>;
+13
View File
@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const _1 = require(".");
exports.injectResources = async (options, source, resources) => {
const { injector } = options;
const dist = injector(source, resources);
const content = _1.isPromise(dist) ? await dist : dist;
if (typeof content !== 'string') {
throw new Error(_1.errorMessage.invalidInjectorReturn);
}
return content;
};
//# sourceMappingURL=inject-resources.js.map
@@ -0,0 +1 @@
{"version":3,"file":"inject-resources.js","sourceRoot":"","sources":["../../src/utils/inject-resources.ts"],"names":[],"mappings":";;AAEA,wBAA0C;AAE7B,QAAA,eAAe,GAAG,KAAK,EAChC,OAA8C,EAC9C,MAAc,EACd,SAAyB,EAC3B,EAAE;IACA,MAAM,EAAC,QAAQ,EAAC,GAAG,OAAO,CAAC;IAE3B,MAAM,IAAI,GAAQ,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAE9C,MAAM,OAAO,GAAG,YAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAEpD,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE;QAC7B,MAAM,IAAI,KAAK,CAAC,eAAY,CAAC,qBAAqB,CAAC,CAAC;KACvD;IAED,OAAO,OAAO,CAAC;AACnB,CAAC,CAAC"}
+2
View File
@@ -0,0 +1,2 @@
/// <reference types="webpack" />
export declare const loadResources: (ctx: import("webpack").loader.LoaderContext, source: string, callback: import("webpack").loader.loaderCallback) => Promise<void>;
+15
View File
@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const _1 = require(".");
exports.loadResources = async (ctx, source, callback) => {
try {
const options = _1.normalizeOptions(ctx);
const resources = await _1.getResources(ctx, options);
const content = await _1.injectResources(options, source, resources);
return callback(null, content);
}
catch (err) {
return callback(err);
}
};
//# sourceMappingURL=load-resources.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"load-resources.js","sourceRoot":"","sources":["../../src/utils/load-resources.ts"],"names":[],"mappings":";;AAEA,wBAAkE;AAErD,QAAA,aAAa,GAAG,KAAK,EAAE,GAAkB,EAAE,MAAc,EAAE,QAAwB,EAAE,EAAE;IAChG,IAAI;QACA,MAAM,OAAO,GAAG,mBAAgB,CAAC,GAAG,CAAC,CAAC;QAEtC,MAAM,SAAS,GAAG,MAAM,eAAY,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAEnD,MAAM,OAAO,GAAG,MAAM,kBAAe,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;QAElE,OAAO,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;KAClC;IAAC,OAAO,GAAG,EAAE;QACV,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;KACxB;AACL,CAAC,CAAC"}
+3
View File
@@ -0,0 +1,3 @@
/// <reference types="webpack" />
import { StyleResourcesLoaderNormalizedOptions } from '..';
export declare const matchFiles: (ctx: import("webpack").loader.LoaderContext, options: StyleResourcesLoaderNormalizedOptions) => Promise<string[]>;
+31
View File
@@ -0,0 +1,31 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = __importDefault(require("path"));
const util_1 = __importDefault(require("util"));
const glob_1 = __importDefault(require("glob"));
const _1 = require(".");
const isLegacyWebpack = (ctx) => !!ctx.options;
const getRootContext = (ctx) => {
if (isLegacyWebpack(ctx)) {
return ctx.options.context;
}
return ctx.rootContext;
};
const flatten = (items) => {
const emptyItems = [];
return emptyItems.concat(...items);
};
exports.matchFiles = async (ctx, options) => {
const { patterns, globOptions } = options;
const files = await Promise.all(patterns.map(async (pattern) => {
const rootContext = getRootContext(ctx);
const absolutePattern = path_1.default.isAbsolute(pattern) ? pattern : path_1.default.resolve(rootContext, pattern);
const partialFiles = await util_1.default.promisify(glob_1.default)(absolutePattern, globOptions);
return partialFiles.filter(_1.isStyleFile);
}));
return [...new Set(flatten(files))].map(file => path_1.default.resolve(file));
};
//# sourceMappingURL=match-files.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"match-files.js","sourceRoot":"","sources":["../../src/utils/match-files.ts"],"names":[],"mappings":";;;;;AAAA,gDAAwB;AACxB,gDAAwB;AAExB,gDAAwB;AAIxB,wBAA8B;AAE9B,MAAM,eAAe,GAAG,CAAC,GAAQ,EAAuC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AAEzF,MAAM,cAAc,GAAG,CAAC,GAAkB,EAAE,EAAE;IAE1C,IAAI,eAAe,CAAC,GAAG,CAAC,EAAE;QACtB,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;KAC9B;IAED,OAAO,GAAG,CAAC,WAAW,CAAC;AAC3B,CAAC,CAAC;AAEF,MAAM,OAAO,GAAG,CAAI,KAAY,EAAE,EAAE;IAChC,MAAM,UAAU,GAAQ,EAAE,CAAC;IAE3B,OAAO,UAAU,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC;AACvC,CAAC,CAAC;AAEW,QAAA,UAAU,GAAG,KAAK,EAAE,GAAkB,EAAE,OAA8C,EAAE,EAAE;IACnG,MAAM,EAAC,QAAQ,EAAE,WAAW,EAAC,GAAG,OAAO,CAAC;IAExC,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAC3B,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAC,OAAO,EAAC,EAAE;QACzB,MAAM,WAAW,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACxC,MAAM,eAAe,GAAG,cAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,cAAI,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAChG,MAAM,YAAY,GAAG,MAAM,cAAI,CAAC,SAAS,CAAC,cAAI,CAAC,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;QAE9E,OAAO,YAAY,CAAC,MAAM,CAAC,cAAW,CAAC,CAAC;IAC5C,CAAC,CAAC,CACL,CAAC;IAQF,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AACxE,CAAC,CAAC"}
+3
View File
@@ -0,0 +1,3 @@
/// <reference types="webpack" />
import { StyleResourcesLoaderNormalizedOptions } from '..';
export declare const normalizeOptions: (ctx: import("webpack").loader.LoaderContext) => StyleResourcesLoaderNormalizedOptions;
+29
View File
@@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const os_1 = require("os");
const loader_utils_1 = require("loader-utils");
const _1 = require(".");
const normalizePatterns = (patterns) => Array.isArray(patterns) ? patterns : [patterns];
const coerceContentEOL = (content) => (content.endsWith(os_1.EOL) ? content : `${content}${os_1.EOL}`);
const getResourceContent = ({ content }) => coerceContentEOL(content);
const normalizeInjector = (injector) => {
if (typeof injector === 'undefined' || injector === 'prepend') {
return (source, resources) => resources.map(getResourceContent).join('') + source;
}
if (injector === 'append') {
return (source, resources) => source + resources.map(getResourceContent).join('');
}
return injector;
};
exports.normalizeOptions = (ctx) => {
const options = loader_utils_1.getOptions(ctx) || {};
_1.validateOptions(options);
const { patterns, injector, globOptions = {}, resolveUrl = true } = options;
return {
patterns: normalizePatterns(patterns),
injector: normalizeInjector(injector),
globOptions,
resolveUrl,
};
};
//# sourceMappingURL=normalize-options.js.map
@@ -0,0 +1 @@
{"version":3,"file":"normalize-options.js","sourceRoot":"","sources":["../../src/utils/normalize-options.ts"],"names":[],"mappings":";;AAAA,2BAAuB;AAEvB,+CAAwC;AAUxC,wBAAkC;AAElC,MAAM,iBAAiB,GAAG,CAAC,QAAiD,EAAE,EAAE,CAC5E,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;AAEpD,MAAM,gBAAgB,GAAG,CAAC,OAAe,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,QAAG,EAAE,CAAC,CAAC;AACrG,MAAM,kBAAkB,GAAG,CAAC,EAAC,OAAO,EAAgB,EAAE,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAEnF,MAAM,iBAAiB,GAAG,CAAC,QAAiD,EAAoC,EAAE;IAC9G,IAAI,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,KAAK,SAAS,EAAE;QAC3D,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC;KACrF;IAED,IAAI,QAAQ,KAAK,QAAQ,EAAE;QACvB,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;KACrF;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC,CAAC;AAEW,QAAA,gBAAgB,GAAG,CAAC,GAAkB,EAAyC,EAAE;IAC1F,MAAM,OAAO,GAAG,yBAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IAEtC,kBAAe,CAA8B,OAAO,CAAC,CAAC;IAEtD,MAAM,EAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,GAAG,EAAE,EAAE,UAAU,GAAG,IAAI,EAAC,GAAG,OAAO,CAAC;IAE1E,OAAO;QACH,QAAQ,EAAE,iBAAiB,CAAC,QAAQ,CAAC;QACrC,QAAQ,EAAE,iBAAiB,CAAC,QAAQ,CAAC;QACrC,WAAW;QACX,UAAU;KACb,CAAC;AACN,CAAC,CAAC"}
@@ -0,0 +1,3 @@
/// <reference types="webpack" />
import { StyleResource } from '..';
export declare const resolveImportUrl: (ctx: import("webpack").loader.LoaderContext, { file, content }: StyleResource) => StyleResource;
+22
View File
@@ -0,0 +1,22 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = __importDefault(require("path"));
const regex = /@(?:import|require)\s+(?:\([a-z,\s]+\)\s*)?['"]?([^'"\s;]+)['"]?;?/gu;
exports.resolveImportUrl = (ctx, { file, content }) => ({
file,
content: content.replace(regex, (match, pathToResource) => {
if (!pathToResource || /^[~/]/u.test(pathToResource)) {
return match;
}
const absolutePathToResource = path_1.default.resolve(path_1.default.dirname(file), pathToResource);
const relativePathFromContextToResource = path_1.default
.relative(ctx.context, absolutePathToResource)
.split(path_1.default.sep)
.join('/');
return match.replace(pathToResource, relativePathFromContextToResource);
}),
});
//# sourceMappingURL=resolve-import-url.js.map
@@ -0,0 +1 @@
{"version":3,"file":"resolve-import-url.js","sourceRoot":"","sources":["../../src/utils/resolve-import-url.ts"],"names":[],"mappings":";;;;;AAAA,gDAAwB;AAKxB,MAAM,KAAK,GAAG,sEAAsE,CAAC;AAExE,QAAA,gBAAgB,GAAG,CAAC,GAAkB,EAAE,EAAC,IAAI,EAAE,OAAO,EAAgB,EAAiB,EAAE,CAAC,CAAC;IACpG,IAAI;IACJ,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,KAAa,EAAE,cAAuB,EAAE,EAAE;QACvE,IAAI,CAAC,cAAc,IAAI,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE;YAClD,OAAO,KAAK,CAAC;SAChB;QAED,MAAM,sBAAsB,GAAG,cAAI,CAAC,OAAO,CAAC,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,cAAc,CAAC,CAAC;QAChF,MAAM,iCAAiC,GAAG,cAAI;aACzC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,sBAAsB,CAAC;aAC7C,KAAK,CAAC,cAAI,CAAC,GAAG,CAAC;aACf,IAAI,CAAC,GAAG,CAAC,CAAC;QAEf,OAAO,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,iCAAiC,CAAC,CAAC;IAC5E,CAAC,CAAC;CACL,CAAC,CAAC"}
+4
View File
@@ -0,0 +1,4 @@
import isPromise from 'is-promise';
export declare const isFunction: <T extends (...args: any[]) => any>(arg: any) => arg is T;
export declare const isStyleFile: (file: string) => boolean;
export { isPromise };
+12
View File
@@ -0,0 +1,12 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = __importDefault(require("path"));
const is_promise_1 = __importDefault(require("is-promise"));
exports.isPromise = is_promise_1.default;
const _1 = require(".");
exports.isFunction = (arg) => typeof arg === 'function';
exports.isStyleFile = (file) => _1.SUPPORTED_FILE_EXTS.includes(path_1.default.extname(file));
//# sourceMappingURL=type-guards.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"type-guards.js","sourceRoot":"","sources":["../../src/utils/type-guards.ts"],"names":[],"mappings":";;;;;AAAA,gDAAwB;AAExB,4DAAmC;AAQ3B,oBARD,oBAAS,CAQC;AANjB,wBAAsC;AAEzB,QAAA,UAAU,GAAG,CAAoC,GAAQ,EAAY,EAAE,CAAC,OAAO,GAAG,KAAK,UAAU,CAAC;AAElG,QAAA,WAAW,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,sBAAmB,CAAC,QAAQ,CAAC,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC"}
+1
View File
@@ -0,0 +1 @@
export declare const validateOptions: <T extends {}>(options: any) => asserts options is T;
+13
View File
@@ -0,0 +1,13 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const schema_utils_1 = __importDefault(require("schema-utils"));
const __1 = require("..");
const _1 = require(".");
exports.validateOptions = options => schema_utils_1.default(__1.schema, options, {
name: _1.LOADER_NAME,
baseDataPath: _1.VALIDATION_BASE_DATA_PATH,
});
//# sourceMappingURL=validate-options.js.map
@@ -0,0 +1 @@
{"version":3,"file":"validate-options.js","sourceRoot":"","sources":["../../src/utils/validate-options.ts"],"names":[],"mappings":";;;;;AAAA,gEAAoC;AAEpC,0BAA0B;AAE1B,wBAAyD;AAE5C,QAAA,eAAe,GAAyD,OAAO,CAAC,EAAE,CAC3F,sBAAQ,CAAC,UAAM,EAAE,OAAO,EAAE;IACtB,IAAI,EAAE,cAAW;IACjB,YAAY,EAAE,4BAAyB;CAC1C,CAAC,CAAC"}
+119
View File
@@ -0,0 +1,119 @@
{
"_args": [
[
"style-resources-loader@1.3.3",
"/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series"
]
],
"_from": "style-resources-loader@1.3.3",
"_id": "style-resources-loader@1.3.3",
"_inBundle": false,
"_integrity": "sha512-vDD2HyG6On8H9gWUN9O9q1eXR/JnXpCkNvpusvgFsRQ9JZGF9drzvwKEigR9vqlmUbXO2t/vIIabpYMmis0eAQ==",
"_location": "/style-resources-loader",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "style-resources-loader@1.3.3",
"name": "style-resources-loader",
"escapedName": "style-resources-loader",
"rawSpec": "1.3.3",
"saveSpec": null,
"fetchSpec": "1.3.3"
},
"_requiredBy": [
"/@nuxt/webpack"
],
"_resolved": "https://registry.npmjs.org/style-resources-loader/-/style-resources-loader-1.3.3.tgz",
"_spec": "1.3.3",
"_where": "/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series",
"author": {
"name": "Shi Yan",
"email": "yenshih95@gmail.com",
"url": "https://github.com/yenshih"
},
"bugs": {
"url": "https://github.com/yenshih/style-resources-loader/issues"
},
"dependencies": {
"glob": "^7.1.6",
"is-promise": "^2.1.0",
"loader-utils": "^1.2.3",
"schema-utils": "^2.6.1"
},
"description": "CSS processor resources loader for webpack",
"devDependencies": {
"@commitlint/cli": "^8.2.0",
"@commitlint/config-conventional": "^8.2.0",
"@types/glob": "^7.1.1",
"@types/is-promise": "^2.1.0",
"@types/jest": "^24.0.24",
"@types/loader-utils": "^1.1.3",
"@types/node": "^12.12.21",
"@types/webpack": "^4.41.0",
"@types/webpack-merge": "^4.1.5",
"@typescript-eslint/eslint-plugin": "^2.12.0",
"@typescript-eslint/parser": "^2.12.0",
"coveralls": "^3.0.9",
"cross-env": "^6.0.3",
"eslint": "^6.7.2",
"eslint-config-prettier": "^6.7.0",
"eslint-plugin-import": "^2.19.1",
"eslint-plugin-prettier": "^3.1.2",
"husky": "^3.1.0",
"jest": "^24.9.0",
"lint-staged": "^9.5.0",
"prettier": "^1.19.1",
"raw-loader": "^4.0.0",
"ts-jest": "^24.2.0",
"typescript": "^3.7.3",
"webpack": "^4.41.3",
"webpack-merge": "^4.2.2"
},
"engines": {
"node": ">=7.6"
},
"files": [
"lib",
"src",
"index.d.ts"
],
"homepage": "https://github.com/yenshih/style-resources-loader",
"keywords": [
"webpack",
"loader",
"style",
"css",
"sass",
"scss",
"less",
"stylus",
"inject",
"resource",
"variable",
"mixin"
],
"license": "MIT",
"main": "lib/index.js",
"name": "style-resources-loader",
"peerDependencies": {
"webpack": "^3.0.0 || ^4.0.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/yenshih/style-resources-loader.git"
},
"scripts": {
"build": "tsc -d",
"clean": "rimraf lib coverage test/**/outputs",
"coverage": "npm test -- --coverage",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"posttest": "rimraf test/**/outputs",
"prepare": "npm run clean && npm run lint && npm run build && npm run coverage",
"prettier": "prettier {src,test}/**/*.{js,jsx,ts,tsx} --write",
"start": "tsc -w",
"test": "jest --detectOpenHandles"
},
"sideEffects": false,
"version": "1.3.3"
}
+6
View File
@@ -0,0 +1,6 @@
import loader from './loader';
export * from './schema';
export * from './types';
export default loader;
+25
View File
@@ -0,0 +1,25 @@
import {errorMessage, isFunction, loadResources} from './utils';
import {Loader, LoaderCallback} from '.';
/* eslint-disable no-invalid-this */
const loader: Loader = function(source) {
this.cacheable && this.cacheable();
const callback = this.async();
if (!isFunction<LoaderCallback>(callback)) {
throw new Error(errorMessage.syncCompilation);
}
/* istanbul ignore if: not possible to test */
if (typeof source !== 'string') {
throw new Error(errorMessage.impossible);
}
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
loadResources(this, source, callback);
};
/* eslint-enable no-invalid-this */
export default loader;
+40
View File
@@ -0,0 +1,40 @@
import validate from 'schema-utils';
type Schema = Parameters<typeof validate>[0];
export const schema: Schema = {
type: 'object',
properties: {
patterns: {
anyOf: [
{type: 'string'},
{
type: 'array',
uniqueItems: true,
items: {
type: 'string',
},
},
],
},
injector: {
anyOf: [
{
type: 'string',
enum: ['prepend', 'append'],
},
{
instanceof: 'Function',
},
],
},
globOptions: {
type: 'object',
},
resolveUrl: {
type: 'boolean',
},
},
required: ['patterns'],
additionalProperties: false,
};
+35
View File
@@ -0,0 +1,35 @@
import {loader} from 'webpack';
import glob from 'glob';
export type Loader = loader.Loader;
export type LoaderContext = loader.LoaderContext;
export type LoaderCallback = loader.loaderCallback;
export type StyleResourcesFileFormat = 'css' | 'sass' | 'scss' | 'less' | 'styl';
export interface StyleResource {
file: string;
content: string;
}
export type StyleResources = StyleResource[];
export type StyleResourcesFunctionalInjector = (source: string, resources: StyleResources) => string | Promise<string>;
export type StyleResourcesInjector = 'prepend' | 'append' | StyleResourcesFunctionalInjector;
export type StyleResourcesNormalizedInjector = StyleResourcesFunctionalInjector;
export interface StyleResourcesLoaderOptions {
patterns: string | string[];
injector?: StyleResourcesInjector;
globOptions?: glob.IOptions;
resolveUrl?: boolean;
}
export interface StyleResourcesLoaderNormalizedOptions extends NonNullable<StyleResourcesLoaderOptions> {
patterns: string[];
injector: StyleResourcesNormalizedInjector;
}
+15
View File
@@ -0,0 +1,15 @@
import {StyleResourcesFileFormat} from '..';
export const PACKAGE_NAME = 'style-resources-loader';
export const ISSUES_URL = `https://github.com/yenshih/${PACKAGE_NAME}/issues`;
export const LOADER_NAME = PACKAGE_NAME.split('-')
.map(word => `${word[0].toUpperCase()}${word.slice(1)}`)
.join(' ');
export const VALIDATION_BASE_DATA_PATH = 'options';
export const SUPPORTED_FILE_FORMATS: StyleResourcesFileFormat[] = ['css', 'sass', 'scss', 'less', 'styl'];
export const SUPPORTED_FILE_EXTS = SUPPORTED_FILE_FORMATS.map(type => `.${type}`);
+17
View File
@@ -0,0 +1,17 @@
import {PACKAGE_NAME, ISSUES_URL} from '.';
const formatErrorMessage = (message: string) => `[${PACKAGE_NAME}] ${message}`;
const messageByType = {
impossible: `This error is caused by a bug. Please file an issue: ${ISSUES_URL}.`,
syncCompilation: 'Synchronous compilation is not supported.',
invalidInjectorReturn: 'Expected options.injector(...) returns a string. Instead received number.',
};
export const errorMessage = Object.entries(messageByType).reduce(
(errorMessage, [type, message]) => ({
...errorMessage,
[type]: formatErrorMessage(message),
}),
messageByType,
);
+25
View File
@@ -0,0 +1,25 @@
import fs from 'fs';
import util from 'util';
import {LoaderContext, StyleResource, StyleResourcesLoaderNormalizedOptions} from '..';
import {matchFiles, resolveImportUrl} from '.';
export const getResources = async (ctx: LoaderContext, options: StyleResourcesLoaderNormalizedOptions) => {
const {resolveUrl} = options;
const files = await matchFiles(ctx, options);
files.forEach(file => ctx.dependency(file));
const resources = await Promise.all(
files.map(async file => {
const content = await util.promisify(fs.readFile)(file, 'utf8');
const resource: StyleResource = {file, content};
return resolveUrl ? resolveImportUrl(ctx, resource) : resource;
}),
);
return resources;
};
+10
View File
@@ -0,0 +1,10 @@
export * from './constants';
export * from './error-message';
export * from './get-resources';
export * from './inject-resources';
export * from './load-resources';
export * from './match-files';
export * from './normalize-options';
export * from './resolve-import-url';
export * from './type-guards';
export * from './validate-options';
+21
View File
@@ -0,0 +1,21 @@
import {StyleResources, StyleResourcesLoaderNormalizedOptions} from '..';
import {isPromise, errorMessage} from '.';
export const injectResources = async (
options: StyleResourcesLoaderNormalizedOptions,
source: string,
resources: StyleResources,
) => {
const {injector} = options;
const dist: any = injector(source, resources);
const content = isPromise(dist) ? await dist : dist;
if (typeof content !== 'string') {
throw new Error(errorMessage.invalidInjectorReturn);
}
return content;
};
+17
View File
@@ -0,0 +1,17 @@
import {LoaderContext, LoaderCallback} from '..';
import {normalizeOptions, getResources, injectResources} from '.';
export const loadResources = async (ctx: LoaderContext, source: string, callback: LoaderCallback) => {
try {
const options = normalizeOptions(ctx);
const resources = await getResources(ctx, options);
const content = await injectResources(options, source, resources);
return callback(null, content);
} catch (err) {
return callback(err);
}
};
+47
View File
@@ -0,0 +1,47 @@
import path from 'path';
import util from 'util';
import glob from 'glob';
import {LoaderContext, StyleResourcesLoaderNormalizedOptions} from '..';
import {isStyleFile} from '.';
const isLegacyWebpack = (ctx: any): ctx is {options: {context: string}} => !!ctx.options;
const getRootContext = (ctx: LoaderContext) => {
/* istanbul ignore if: will be deprecated soon */
if (isLegacyWebpack(ctx)) {
return ctx.options.context;
}
return ctx.rootContext;
};
const flatten = <T>(items: T[][]) => {
const emptyItems: T[] = [];
return emptyItems.concat(...items);
};
export const matchFiles = async (ctx: LoaderContext, options: StyleResourcesLoaderNormalizedOptions) => {
const {patterns, globOptions} = options;
const files = await Promise.all(
patterns.map(async pattern => {
const rootContext = getRootContext(ctx);
const absolutePattern = path.isAbsolute(pattern) ? pattern : path.resolve(rootContext, pattern);
const partialFiles = await util.promisify(glob)(absolutePattern, globOptions);
return partialFiles.filter(isStyleFile);
}),
);
/**
* Glob always returns Unix-style file paths which would have cache invalidation problems on Windows.
* Use `path.resolve()` to convert Unix-style file paths to system-compatible ones.
*
* @see {@link https://github.com/yenshih/style-resources-loader/issues/17}
*/
return [...new Set(flatten(files))].map(file => path.resolve(file));
};
+46
View File
@@ -0,0 +1,46 @@
import {EOL} from 'os';
import {getOptions} from 'loader-utils';
import {
LoaderContext,
StyleResource,
StyleResourcesNormalizedInjector,
StyleResourcesLoaderOptions,
StyleResourcesLoaderNormalizedOptions,
} from '..';
import {validateOptions} from '.';
const normalizePatterns = (patterns: StyleResourcesLoaderOptions['patterns']) =>
Array.isArray(patterns) ? patterns : [patterns];
const coerceContentEOL = (content: string) => (content.endsWith(EOL) ? content : `${content}${EOL}`);
const getResourceContent = ({content}: StyleResource) => coerceContentEOL(content);
const normalizeInjector = (injector: StyleResourcesLoaderOptions['injector']): StyleResourcesNormalizedInjector => {
if (typeof injector === 'undefined' || injector === 'prepend') {
return (source, resources) => resources.map(getResourceContent).join('') + source;
}
if (injector === 'append') {
return (source, resources) => source + resources.map(getResourceContent).join('');
}
return injector;
};
export const normalizeOptions = (ctx: LoaderContext): StyleResourcesLoaderNormalizedOptions => {
const options = getOptions(ctx) || {};
validateOptions<StyleResourcesLoaderOptions>(options);
const {patterns, injector, globOptions = {}, resolveUrl = true} = options;
return {
patterns: normalizePatterns(patterns),
injector: normalizeInjector(injector),
globOptions,
resolveUrl,
};
};
+23
View File
@@ -0,0 +1,23 @@
import path from 'path';
import {LoaderContext, StyleResource} from '..';
/* eslint-disable-next-line prefer-named-capture-group */
const regex = /@(?:import|require)\s+(?:\([a-z,\s]+\)\s*)?['"]?([^'"\s;]+)['"]?;?/gu;
export const resolveImportUrl = (ctx: LoaderContext, {file, content}: StyleResource): StyleResource => ({
file,
content: content.replace(regex, (match: string, pathToResource?: string) => {
if (!pathToResource || /^[~/]/u.test(pathToResource)) {
return match;
}
const absolutePathToResource = path.resolve(path.dirname(file), pathToResource);
const relativePathFromContextToResource = path
.relative(ctx.context, absolutePathToResource)
.split(path.sep)
.join('/');
return match.replace(pathToResource, relativePathFromContextToResource);
}),
});
+11
View File
@@ -0,0 +1,11 @@
import path from 'path';
import isPromise from 'is-promise';
import {SUPPORTED_FILE_EXTS} from '.';
export const isFunction = <T extends (...args: any[]) => any>(arg: any): arg is T => typeof arg === 'function';
export const isStyleFile = (file: string) => SUPPORTED_FILE_EXTS.includes(path.extname(file));
export {isPromise};
+11
View File
@@ -0,0 +1,11 @@
import validate from 'schema-utils';
import {schema} from '..';
import {LOADER_NAME, VALIDATION_BASE_DATA_PATH} from '.';
export const validateOptions: <T extends {}>(options: any) => asserts options is T = options =>
validate(schema, options, {
name: LOADER_NAME,
baseDataPath: VALIDATION_BASE_DATA_PATH,
});