Skip to content

Commit

Permalink
refactor!: the insert option can only be a selector or the path t…
Browse files Browse the repository at this point in the history
…o the module
  • Loading branch information
alexander-akait committed Apr 8, 2024
1 parent 17b2295 commit faacaad
Show file tree
Hide file tree
Showing 12 changed files with 180 additions and 185 deletions.
181 changes: 102 additions & 79 deletions README.md
Expand Up @@ -450,9 +450,7 @@ module.exports = {
Type:

```ts
type insert =
| string
| ((htmlElement: HTMLElement, options: Record<string, any>) => void);
type insert = string;
```

Default: `head`
Expand All @@ -462,9 +460,7 @@ This will cause CSS created by the loader to take priority over CSS already pres
You can use other values if the standard behavior is not suitable for you, but we do not recommend doing this.
If you target an [iframe](https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement) make sure you have sufficient access rights, the styles will be injected into the content document head.

#### `string`

##### `Selector`
#### `Selector`

Allows to setup custom [query selector](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector) where styles inject into the DOM.

Expand All @@ -491,7 +487,7 @@ module.exports = {
};
```

##### `Absolute path to function`
#### `Absolute path to function`

Allows to setup absolute path to custom function that allows to override default behavior and insert styles at any position.

Expand All @@ -515,7 +511,7 @@ module.exports = {
{
loader: "style-loader",
options: {
insert: require.resolve("modulePath"),
insert: require.resolve("./path-to-insert-module"),
},
},
"css-loader",
Expand All @@ -528,17 +524,32 @@ module.exports = {

A new `<style>`/`<link>` elements will be inserted into at bottom of `body` tag.

#### `function`
Examples:

Allows to override default behavior and insert styles at any position.
Insert styles at top of `head` tag:

> **Warning**
>
> Do not forget that this code will be used in the browser and not all browsers support latest ECMA features like `let`, `const`, `arrow function expression` and etc, we recommend use only ECMA 5 features, but it is depends what browsers you want to support
**insert-function.js**

> **Warning**
>
> Do not forget that some DOM methods may not be available in older browsers, we recommended use only [DOM core level 2 properties](https://caniuse.com/#search=DOM%20Core), but it is depends what browsers you want to support
```js
function insertAtTop(element) {
var parent = document.querySelector("head");
// eslint-disable-next-line no-underscore-dangle
var lastInsertedElement = window._lastElementInsertedByStyleLoader;

if (!lastInsertedElement) {
parent.insertBefore(element, parent.firstChild);
} else if (lastInsertedElement.nextSibling) {
parent.insertBefore(element, lastInsertedElement.nextSibling);
} else {
parent.appendChild(element);
}

// eslint-disable-next-line no-underscore-dangle
window._lastElementInsertedByStyleLoader = element;
}

module.exports = insertAtTop;
```

**webpack.config.js**

Expand All @@ -552,23 +563,7 @@ module.exports = {
{
loader: "style-loader",
options: {
insert: function insertAtTop(element) {
var parent = document.querySelector("head");
// eslint-disable-next-line no-underscore-dangle
var lastInsertedElement =
window._lastElementInsertedByStyleLoader;

if (!lastInsertedElement) {
parent.insertBefore(element, parent.firstChild);
} else if (lastInsertedElement.nextSibling) {
parent.insertBefore(element, lastInsertedElement.nextSibling);
} else {
parent.appendChild(element);
}

// eslint-disable-next-line no-underscore-dangle
window._lastElementInsertedByStyleLoader = element;
},
insert: require.resolve("./insert-function"),
},
},
"css-loader",
Expand All @@ -579,10 +574,20 @@ module.exports = {
};
```

Insert styles at top of `head` tag.

You can pass any parameters to `style.use(options)` and this value will be passed to `insert` and `styleTagTransform` functions.

**insert-function.js**

```js
function insertIntoTarget(element, options) {
var parent = options.target || document.head;

parent.appendChild(element);
}

module.exports = insertIntoTarget;
```

**webpack.config.js**

```js
Expand All @@ -599,12 +604,8 @@ module.exports = {
// Do not forget that this code will be used in the browser and
// not all browsers support latest ECMA features like `let`, `const`, `arrow function expression` and etc,
// we recommend use only ECMA 5 features,
// but it is depends what browsers you want to support
insert: function insertIntoTarget(element, options) {
var parent = options.target || document.head;

parent.appendChild(element);
},
// but it depends what browsers you want to support
insert: require.resolve("./insert-function.js"),
},
},
"css-loader",
Expand Down Expand Up @@ -1031,7 +1032,28 @@ The loader generate:

#### Insert styles at top

Inserts styles at top of `head` tag.
Insert styles at top of `head` tag.

**insert-function.js**

```js
function insertAtTop(element) {
var parent = document.querySelector("head");
var lastInsertedElement = window._lastElementInsertedByStyleLoader;

if (!lastInsertedElement) {
parent.insertBefore(element, parent.firstChild);
} else if (lastInsertedElement.nextSibling) {
parent.insertBefore(element, lastInsertedElement.nextSibling);
} else {
parent.appendChild(element);
}

window._lastElementInsertedByStyleLoader = element;
}

module.exports = insertAtTop;
```

**webpack.config.js**

Expand All @@ -1045,21 +1067,7 @@ module.exports = {
{
loader: "style-loader",
options: {
insert: function insertAtTop(element) {
var parent = document.querySelector("head");
var lastInsertedElement =
window._lastElementInsertedByStyleLoader;

if (!lastInsertedElement) {
parent.insertBefore(element, parent.firstChild);
} else if (lastInsertedElement.nextSibling) {
parent.insertBefore(element, lastInsertedElement.nextSibling);
} else {
parent.appendChild(element);
}

window._lastElementInsertedByStyleLoader = element;
},
insert: require.resolve("./insert-function.js"),
},
},
"css-loader",
Expand All @@ -1074,6 +1082,29 @@ module.exports = {

Inserts styles before `#id` element.

**insert-function.js**

```js
function insertBeforeAt(element) {
const parent = document.querySelector("head");
const target = document.querySelector("#id");

const lastInsertedElement = window._lastElementInsertedByStyleLoader;

if (!lastInsertedElement) {
parent.insertBefore(element, target);
} else if (lastInsertedElement.nextSibling) {
parent.insertBefore(element, lastInsertedElement.nextSibling);
} else {
parent.appendChild(element);
}

window._lastElementInsertedByStyleLoader = element;
}

module.exports = insertBeforeAt;
```

**webpack.config.js**

```js
Expand All @@ -1086,23 +1117,7 @@ module.exports = {
{
loader: "style-loader",
options: {
insert: function insertBeforeAt(element) {
const parent = document.querySelector("head");
const target = document.querySelector("#id");

const lastInsertedElement =
window._lastElementInsertedByStyleLoader;

if (!lastInsertedElement) {
parent.insertBefore(element, target);
} else if (lastInsertedElement.nextSibling) {
parent.insertBefore(element, lastInsertedElement.nextSibling);
} else {
parent.appendChild(element);
}

window._lastElementInsertedByStyleLoader = element;
},
insert: require.resolve("./insert-function.js"),
},
},
"css-loader",
Expand All @@ -1117,6 +1132,18 @@ module.exports = {

You can define custom target for your styles for the `lazyStyleTag` type.

**insert-function.js**

```js
function insertIntoTarget(element, options) {
var parent = options.target || document.head;

parent.appendChild(element);
}

module.exports = insertIntoTarget;
```

**webpack.config.js**

```js
Expand All @@ -1134,11 +1161,7 @@ module.exports = {
// not all browsers support latest ECMA features like `let`, `const`, `arrow function expression` and etc,
// we recommend use only ECMA 5 features,
// but it is depends what browsers you want to support
insert: function insertIntoTarget(element, options) {
var parent = options.target || document.head;

parent.appendChild(element);
},
insert: require.resolve("./insert-function.js"),
},
},
"css-loader",
Expand Down
8 changes: 3 additions & 5 deletions src/index.js
Expand Up @@ -74,11 +74,9 @@ loader.pitch = function pitch(request) {
}

const insertType =
typeof options.insert === "function"
? "function"
: options.insert && path.isAbsolute(options.insert)
? "module-path"
: "selector";
options.insert && path.isAbsolute(options.insert)
? "module-path"
: "selector";

switch (injectType) {
case "linkTag": {
Expand Down
18 changes: 2 additions & 16 deletions src/options.json
Expand Up @@ -23,14 +23,7 @@
"insert": {
"description": "Inserts `<style>`/`<link>` at the given position.",
"link": "https://github.com/webpack-contrib/style-loader#insert",
"anyOf": [
{
"type": "string"
},
{
"instanceof": "Function"
}
]
"type": "string"
},
"base": {
"description": "Sets module ID base for DLLPlugin.",
Expand All @@ -45,14 +38,7 @@
"styleTagTransform": {
"description": "Transform tag and css when insert 'style' tag into the DOM",
"link": "https://github.com/webpack-contrib/style-loader#styleTagTransform",
"anyOf": [
{
"type": "string"
},
{
"instanceof": "Function"
}
]
"type": "string"
}
},
"additionalProperties": false
Expand Down
33 changes: 11 additions & 22 deletions src/utils.js
Expand Up @@ -80,17 +80,6 @@ function getImportInsertBySelectorCode(
insertType,
options,
) {
if (insertType === "selector") {
const modulePath = stringifyRequest(
loaderContext,
`!${path.join(__dirname, "runtime/insertBySelector.js")}`,
);

return esModule
? `import insertFn from ${modulePath};`
: `var insertFn = require(${modulePath});`;
}

if (insertType === "module-path") {
const modulePath = stringifyRequest(loaderContext, `${options.insert}`);

Expand All @@ -101,24 +90,24 @@ function getImportInsertBySelectorCode(
: `var insertFn = require(${modulePath});`;
}

return "";
const modulePath = stringifyRequest(
loaderContext,
`!${path.join(__dirname, "runtime/insertBySelector.js")}`,
);

return esModule
? `import insertFn from ${modulePath};`
: `var insertFn = require(${modulePath});`;
}

function getInsertOptionCode(insertType, options) {
if (insertType === "selector") {
const insert = options.insert ? JSON.stringify(options.insert) : '"head"';

return `
options.insert = insertFn.bind(null, ${insert});
`;
}

if (insertType === "module-path") {
return `options.insert = insertFn;`;
}

// Todo remove "function" type for insert option in next major release, because code duplication occurs. Leave require.resolve()
return `options.insert = ${options.insert.toString()};`;
const insert = options.insert ? JSON.stringify(options.insert) : '"head"';

return `options.insert = insertFn.bind(null, ${insert});`;
}

function getImportInsertStyleElementCode(esModule, loaderContext) {
Expand Down

0 comments on commit faacaad

Please sign in to comment.