Skip to content

Commit

Permalink
feat: add defaultExport option
Browse files Browse the repository at this point in the history
  • Loading branch information
jantimon committed Feb 28, 2024
1 parent c7ff30d commit 1787dab
Show file tree
Hide file tree
Showing 11 changed files with 221 additions and 10 deletions.
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ module.exports = {
- **[`publicPath`](#publicPath)**
- **[`emit`](#emit)**
- **[`esModule`](#esModule)**
- **[`defaultExport`](#defaultExport)**

#### `publicPath`

Expand Down Expand Up @@ -549,6 +550,47 @@ module.exports = {
};
```

#### `defaultExport`

Type:

```ts
type defaultExport = boolean;
```

Default: `false`

By default, `mini-css-extract-plugin` generates JS modules with a default export.
However for name exports, each local is exported as a named export.

In case you need both default and named exports, you can enable this option:

**webpack.config.js**

```js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
plugins: [new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.css$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
defaultExport: true,
},
},
"css-loader",
],
},
],
},
};
```

## Examples

### Recommended
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const {
* @property {string | ((resourcePath: string, rootContext: string) => string)} [publicPath]
* @property {boolean} [emit]
* @property {boolean} [esModule]
* @property {boolean} [defaultExport]
* @property {string} [layer]
*/

Expand Down
5 changes: 5 additions & 0 deletions src/loader-options.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
"description": "Generates JS modules that use the ES modules syntax.",
"link": "https://github.com/webpack-contrib/mini-css-extract-plugin#esmodule"
},
"defaultExport": {
"type": "boolean",
"description": "Generates JS modules with the default export syntax even for named exports.",
"link": "https://github.com/webpack-contrib/mini-css-extract-plugin#defaultexports"
},
"layer": {
"type": "string"
}
Expand Down
11 changes: 9 additions & 2 deletions src/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ function pitch(request) {
const esModule =
typeof options.esModule !== "undefined" ? options.esModule : true;

const defaultExport =
typeof options.defaultExport !== "undefined"
? options.defaultExport
: false;

/**
* @param {Dependency[] | [null, object][]} dependencies
*/
Expand Down Expand Up @@ -271,8 +276,10 @@ function pitch(request) {
const exportsString = `export { ${identifiers
.map(([id, key]) => `${id} as ${JSON.stringify(key)}`)
.join(", ")} }`;

return `${localsString}\n${exportsString}\n`;
const exportDefaultString = defaultExport
? `export default ${JSON.stringify(locals)}\n`
: "";
return `${localsString}\n${exportsString}\n${exportDefaultString}`;
}

return `\n${
Expand Down
16 changes: 8 additions & 8 deletions test/__snapshots__/validate-loader-options.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -21,47 +21,47 @@ exports[`validate options should throw an error on the "publicPath" option with
exports[`validate options should throw an error on the "unknown" option with "/test/" value 1`] = `
"Invalid options object. Mini CSS Extract Plugin Loader has been initialized using an options object that does not match the API schema.
- options has an unknown property 'unknown'. These properties are valid:
object { publicPath?, emit?, esModule?, layer? }"
object { publicPath?, emit?, esModule?, defaultExport?, layer? }"
`;
exports[`validate options should throw an error on the "unknown" option with "[]" value 1`] = `
"Invalid options object. Mini CSS Extract Plugin Loader has been initialized using an options object that does not match the API schema.
- options has an unknown property 'unknown'. These properties are valid:
object { publicPath?, emit?, esModule?, layer? }"
object { publicPath?, emit?, esModule?, defaultExport?, layer? }"
`;
exports[`validate options should throw an error on the "unknown" option with "{"foo":"bar"}" value 1`] = `
"Invalid options object. Mini CSS Extract Plugin Loader has been initialized using an options object that does not match the API schema.
- options has an unknown property 'unknown'. These properties are valid:
object { publicPath?, emit?, esModule?, layer? }"
object { publicPath?, emit?, esModule?, defaultExport?, layer? }"
`;
exports[`validate options should throw an error on the "unknown" option with "{}" value 1`] = `
"Invalid options object. Mini CSS Extract Plugin Loader has been initialized using an options object that does not match the API schema.
- options has an unknown property 'unknown'. These properties are valid:
object { publicPath?, emit?, esModule?, layer? }"
object { publicPath?, emit?, esModule?, defaultExport?, layer? }"
`;
exports[`validate options should throw an error on the "unknown" option with "1" value 1`] = `
"Invalid options object. Mini CSS Extract Plugin Loader has been initialized using an options object that does not match the API schema.
- options has an unknown property 'unknown'. These properties are valid:
object { publicPath?, emit?, esModule?, layer? }"
object { publicPath?, emit?, esModule?, defaultExport?, layer? }"
`;
exports[`validate options should throw an error on the "unknown" option with "false" value 1`] = `
"Invalid options object. Mini CSS Extract Plugin Loader has been initialized using an options object that does not match the API schema.
- options has an unknown property 'unknown'. These properties are valid:
object { publicPath?, emit?, esModule?, layer? }"
object { publicPath?, emit?, esModule?, defaultExport?, layer? }"
`;
exports[`validate options should throw an error on the "unknown" option with "test" value 1`] = `
"Invalid options object. Mini CSS Extract Plugin Loader has been initialized using an options object that does not match the API schema.
- options has an unknown property 'unknown'. These properties are valid:
object { publicPath?, emit?, esModule?, layer? }"
object { publicPath?, emit?, esModule?, defaultExport?, layer? }"
`;
exports[`validate options should throw an error on the "unknown" option with "true" value 1`] = `
"Invalid options object. Mini CSS Extract Plugin Loader has been initialized using an options object that does not match the API schema.
- options has an unknown property 'unknown'. These properties are valid:
object { publicPath?, emit?, esModule?, layer? }"
object { publicPath?, emit?, esModule?, defaultExport?, layer? }"
`;
12 changes: 12 additions & 0 deletions test/cases/es-named-export-with-default/expected/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.foo__style__aClass {
background: red;
}

.foo__style__bClass {
color: green;
}

.foo__style__cClass {
color: blue;
}

91 changes: 91 additions & 0 deletions test/cases/es-named-export-with-default/expected/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ([
/* 0 */,
/* 1 */
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ aClass: () => (/* binding */ _1),
/* harmony export */ bClass: () => (/* binding */ _2),
/* harmony export */ cClass: () => (/* binding */ _3)
/* harmony export */ });
// extracted by mini-css-extract-plugin
var _1 = "foo__style__aClass";
var _2 = "foo__style__bClass";
var _3 = "foo__style__cClass";



/***/ })
/******/ ]);
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _style_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);


// eslint-disable-next-line no-console
console.log({ css: _style_css__WEBPACK_IMPORTED_MODULE_0__["default"], aClass: _style_css__WEBPACK_IMPORTED_MODULE_0__.aClass, bClass: _style_css__WEBPACK_IMPORTED_MODULE_0__.bClass, cClass: _style_css__WEBPACK_IMPORTED_MODULE_0__.cClass });

})();

/******/ })()
;
4 changes: 4 additions & 0 deletions test/cases/es-named-export-with-default/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import css, { aClass, bClass, cClass } from "./style.css";

// eslint-disable-next-line no-console
console.log({ css, aClass, bClass, cClass });
11 changes: 11 additions & 0 deletions test/cases/es-named-export-with-default/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.aClass {
background: red;
}

.bClass {
color: green;
}

.cClass {
color: blue;
}
36 changes: 36 additions & 0 deletions test/cases/es-named-export-with-default/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const Self = require("../../../");

module.exports = {
entry: "./index.js",
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: Self.loader,
options: {
defaultExport: false,
},
},
{
loader: "css-loader",
options: {
esModule: true,
modules: {
namedExport: true,
exportLocalsConvention: "asIs",
localIdentName: "foo__[name]__[local]",
},
},
},
],
},
],
},
plugins: [
new Self({
filename: "[name].css",
}),
],
};
2 changes: 2 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ type PluginOptions = {
* @property {string | ((resourcePath: string, rootContext: string) => string)} [publicPath]
* @property {boolean} [emit]
* @property {boolean} [esModule]
* @property {boolean} [defaultExport]
* @property {string} [layer]
*/
/**
Expand Down Expand Up @@ -199,6 +200,7 @@ type LoaderOptions = {
| undefined;
emit?: boolean | undefined;
esModule?: boolean | undefined;
defaultExport?: boolean | undefined;
layer?: string | undefined;
};
type NormalizedPluginOptions = {
Expand Down

0 comments on commit 1787dab

Please sign in to comment.