diff --git a/README.md b/README.md
index 976fc4c..177f81a 100644
--- a/README.md
+++ b/README.md
@@ -1,158 +1,161 @@
-[![npm][npm]][npm-url]
-[![build][build]][build-url]
-
-
-
-# One Loader
-
-A webpack loader to enable single-file React components.
-Inspired by `vue-loader`.
-
-## Features
-
-* CSS and JavaScript code co-located in a single `.one` file (extension is configurable)
-* Configurable loaders for JavaScript and CSS
-* Support for scoped styles through CSS Modules (using `css-loader`)
-
-## Installation
-
-```bash
-$ npm i --save-dev one-loader
-```
-
-## Example
-
-In `webpack.config.js`:
-
-```javascript
-{
- module: {
- loaders: [
- {
- test: /\.one$/,
- loader: 'one-loader',
- options: {
- map: {
- 'text/css': ['style-loader', 'css-loader'],
- 'javascript': 'babel-loader'
- }
- }
- }
- ]
- }
-}
-```
-
-In `ExampleComponent.one`:
-
-```html
-
-
-
-```
-
-More examples are available in [examples](examples) directory:
-
-* [Simple Counter](examples/01_counter)
-* [Redux Todo List with extracted CSS file](examples/02_redux-todos)
-* [Redux Todo List with scoped CSS](examples/03_redux-todos-scoped)
-
-## Configuration
-
-The `map` object in `one-loader` options is responsible for assigning loaders to code types in your single-file components.
-
-If no mapping is provided `
-
-```
-
-There are no restrictions on type naming, so any string will work, however descriptive values are recommended.
-
-## Known issues
-
-The internal architecture of the loader requires passing the options object to sub-loaders through a `require` string.
-This is currently causing issues when defining `map` object loaders in strings with a `!` separator.
-Thus array syntax is recommended for defining mapped loaders.
-
-This will **NOT** work:
-
-```javascript
-{
- module: {
- loaders: [
- {
- test: /\.one$/,
- loader: 'one-loader',
- options: {
- map: {
- 'text/css': 'style-loader!css-loader',
- 'javascript': 'babel-loader'
- }
- }
- }
- ]
- }
-}
-```
-
-This will work:
-
-```javascript
-{
- module: {
- loaders: [
- {
- test: /\.one$/,
- loader: 'one-loader',
- options: {
- map: {
- 'text/css': ['style-loader', 'css-loader'],
- 'javascript': 'babel-loader'
- }
- }
- }
- ]
- }
-}
-```
-
-
-## License
-
-MIT
-
-[npm]: https://img.shields.io/npm/v/one-loader.svg
-[npm-url]: https://npmjs.com/package/one-loader
-
-[build]: https://travis-ci.org/digitalie/one-loader.svg?branch=master
-[build-url]: https://travis-ci.org/digitalie/one-loader
+[![npm][npm]][npm-url]
+[![build][build]][build-url]
+
+
+
+# One Loader
+
+A webpack loader to enable single-file components, inspired by `vue-loader`.
+
+Originally it was built for react, but will work for almost any type of content.
+In fact, if you wanted to, you could even use it for php, html and css using file-loaders without any javascript part.
+
+
+## Features
+
+* CSS, JavaScript code and other parts co-located in a single `.one` file (extension is configurable)
+* Configurable loaders for JavaScript and CSS
+* Support for scoped styles through CSS Modules (using `css-loader`)
+
+## Installation
+
+```bash
+$ npm i --save-dev one-loader
+```
+
+## Example
+
+In `webpack.config.js`:
+
+```javascript
+{
+ module: {
+ loaders: [
+ {
+ test: /\.one$/,
+ loader: 'one-loader',
+ options: {
+ map: {
+ 'text/css': ['style-loader', 'css-loader'],
+ 'javascript': 'babel-loader'
+ }
+ }
+ }
+ ]
+ }
+}
+```
+
+In `ExampleComponent.one`:
+
+```html
+
+
+
+```
+
+More examples are available in [examples](examples) directory:
+
+* [Simple Counter](examples/01_counter)
+* [Redux Todo List with extracted CSS file](examples/02_redux-todos)
+* [Redux Todo List with scoped CSS](examples/03_redux-todos-scoped)
+
+## Configuration
+
+The `map` object in `one-loader` options is responsible for assigning loaders to code types in your single-file components.
+
+If no mapping is provided `
+
+```
+
+There are no restrictions on type naming, so any string will work, however descriptive values are recommended.
+
+## Known issues
+
+The internal architecture of the loader requires passing the options object to sub-loaders through a `require` string.
+This is currently causing issues when defining `map` object loaders in strings with a `!` separator.
+Thus array syntax is recommended for defining mapped loaders.
+
+This will **NOT** work:
+
+```javascript
+{
+ module: {
+ loaders: [
+ {
+ test: /\.one$/,
+ loader: 'one-loader',
+ options: {
+ map: {
+ 'text/css': 'style-loader!css-loader',
+ 'javascript': 'babel-loader'
+ }
+ }
+ }
+ ]
+ }
+}
+```
+
+This will work:
+
+```javascript
+{
+ module: {
+ loaders: [
+ {
+ test: /\.one$/,
+ loader: 'one-loader',
+ options: {
+ map: {
+ 'text/css': ['style-loader', 'css-loader'],
+ 'javascript': 'babel-loader'
+ }
+ }
+ }
+ ]
+ }
+}
+```
+
+
+## License
+
+MIT
+
+[npm]: https://img.shields.io/npm/v/one-loader.svg
+[npm-url]: https://npmjs.com/package/one-loader
+
+[build]: https://travis-ci.org/digitalie/one-loader.svg?branch=master
+[build-url]: https://travis-ci.org/digitalie/one-loader
diff --git a/package-lock.json b/package-lock.json
index f482a40..3b28625 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -715,8 +715,7 @@
"@types/node": {
"version": "14.6.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.0.tgz",
- "integrity": "sha512-mikldZQitV94akrc4sCcSjtJfsTKt4p+e/s0AGscVA6XArQ9kFclP+ZiYUMnq987rc6QlYxXv/EivqlfSLxpKA==",
- "dev": true
+ "integrity": "sha512-mikldZQitV94akrc4sCcSjtJfsTKt4p+e/s0AGscVA6XArQ9kFclP+ZiYUMnq987rc6QlYxXv/EivqlfSLxpKA=="
},
"@types/normalize-package-data": {
"version": "2.4.0",
@@ -1057,6 +1056,11 @@
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="
},
+ "boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
+ },
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -1157,6 +1161,78 @@
"integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
"dev": true
},
+ "cheerio": {
+ "version": "1.0.0-rc.3",
+ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz",
+ "integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==",
+ "requires": {
+ "css-select": "~1.2.0",
+ "dom-serializer": "~0.1.1",
+ "entities": "~1.1.1",
+ "htmlparser2": "^3.9.1",
+ "lodash": "^4.15.0",
+ "parse5": "^3.0.1"
+ },
+ "dependencies": {
+ "dom-serializer": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
+ "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==",
+ "requires": {
+ "domelementtype": "^1.3.0",
+ "entities": "^1.1.1"
+ }
+ },
+ "domelementtype": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+ "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
+ },
+ "domhandler": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
+ "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
+ "requires": {
+ "domelementtype": "1"
+ }
+ },
+ "domutils": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
+ "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
+ "requires": {
+ "dom-serializer": "0",
+ "domelementtype": "1"
+ }
+ },
+ "entities": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
+ "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
+ },
+ "htmlparser2": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
+ "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
+ "requires": {
+ "domelementtype": "^1.3.1",
+ "domhandler": "^2.3.0",
+ "domutils": "^1.5.1",
+ "entities": "^1.1.1",
+ "inherits": "^2.0.1",
+ "readable-stream": "^3.1.1"
+ }
+ },
+ "parse5": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz",
+ "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==",
+ "requires": {
+ "@types/node": "*"
+ }
+ }
+ }
+ },
"ci-info": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
@@ -1297,6 +1373,54 @@
"which": "^1.2.9"
}
},
+ "css-select": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
+ "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
+ "requires": {
+ "boolbase": "~1.0.0",
+ "css-what": "2.1",
+ "domutils": "1.5.1",
+ "nth-check": "~1.0.1"
+ },
+ "dependencies": {
+ "dom-serializer": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
+ "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
+ "requires": {
+ "domelementtype": "^2.0.1",
+ "entities": "^2.0.0"
+ },
+ "dependencies": {
+ "domelementtype": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
+ "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ=="
+ }
+ }
+ },
+ "domelementtype": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+ "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
+ },
+ "domutils": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
+ "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
+ "requires": {
+ "dom-serializer": "0",
+ "domelementtype": "1"
+ }
+ }
+ }
+ },
+ "css-what": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
+ "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg=="
+ },
"cssom": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz",
@@ -1438,32 +1562,6 @@
"integrity": "sha512-5j5vdRcw3CNctePNYN0Wy2e/JbWT6cAYnXv5OuqPhDpyCGc0uLu2TK0zOCJWNB9kOIfYMSpIulRaDgIi4HJ6Ig==",
"dev": true
},
- "dom-serializer": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
- "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
- "requires": {
- "domelementtype": "^2.0.1",
- "entities": "^2.0.0"
- },
- "dependencies": {
- "domelementtype": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
- "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ=="
- },
- "entities": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
- "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ=="
- }
- }
- },
- "domelementtype": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
- "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
- },
"domexception": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz",
@@ -1481,23 +1579,6 @@
}
}
},
- "domhandler": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
- "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
- "requires": {
- "domelementtype": "1"
- }
- },
- "domutils": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
- "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
- "requires": {
- "dom-serializer": "0",
- "domelementtype": "1"
- }
- },
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@@ -1535,9 +1616,9 @@
}
},
"entities": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
- "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
+ "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ=="
},
"error-ex": {
"version": "1.3.2",
@@ -2035,19 +2116,6 @@
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
- "htmlparser2": {
- "version": "3.10.1",
- "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
- "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
- "requires": {
- "domelementtype": "^1.3.1",
- "domhandler": "^2.3.0",
- "domutils": "^1.5.1",
- "entities": "^1.1.1",
- "inherits": "^2.0.1",
- "readable-stream": "^3.1.1"
- }
- },
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
@@ -2925,6 +2993,14 @@
"whatwg-url": "^8.0.0",
"ws": "^7.2.3",
"xml-name-validator": "^3.0.0"
+ },
+ "dependencies": {
+ "parse5": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
+ "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
+ "dev": true
+ }
}
},
"jsesc": {
@@ -3040,24 +3116,13 @@
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
- "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
- "dev": true
+ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
},
"lodash.defaultsdeep": {
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz",
"integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA=="
},
- "lodash.get": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
- "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
- },
- "lodash.set": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
- "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM="
- },
"lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
@@ -3288,6 +3353,14 @@
"path-key": "^2.0.0"
}
},
+ "nth-check": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
+ "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
+ "requires": {
+ "boolbase": "~1.0.0"
+ }
+ },
"nwsapi": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz",
@@ -3429,12 +3502,6 @@
"lines-and-columns": "^1.1.6"
}
},
- "parse5": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
- "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
- "dev": true
- },
"pascalcase": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
@@ -3501,14 +3568,6 @@
"integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
"dev": true
},
- "posthtml-parser": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.4.2.tgz",
- "integrity": "sha512-BUIorsYJTvS9UhXxPTzupIztOMVNPa/HtAm9KHni9z6qEfiJ1bpOBL5DfUOL9XAc3XkLIEzBzpph+Zbm4AdRAg==",
- "requires": {
- "htmlparser2": "^3.9.2"
- }
- },
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
diff --git a/package.json b/package.json
index 5f01d38..ce5bb47 100644
--- a/package.json
+++ b/package.json
@@ -31,10 +31,8 @@
"jest": "^26.4.1"
},
"dependencies": {
+ "cheerio": "^1.0.0-rc.3",
"loader-utils": "^2.0.0",
- "lodash.defaultsdeep": "^4.6.1",
- "lodash.get": "^4.4.2",
- "lodash.set": "^4.3.2",
- "posthtml-parser": "^0.4.2"
+ "lodash.defaultsdeep": "^4.6.1"
}
}
diff --git a/src/index.js b/src/index.js
index 28398fe..6118d86 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,7 +1,7 @@
const defaultsDeep = require('lodash.defaultsdeep');
const loaderUtils = require('loader-utils');
const parse = require('./parse').default;
-const { getRequire } = require('./require');
+const {getRequirePrimary} = require('./require');
const defaultOptions = require('./options');
/**
@@ -10,22 +10,35 @@ const defaultOptions = require('./options');
* @param {string} content
*/
module.exports = function (content) {
- let output = '';
-
- const cb = this.async();
- const parts = parse(content);
-
const options = defaultsDeep(loaderUtils.getOptions(this), defaultOptions);
const resource = loaderUtils.getRemainingRequest(this);
- const scriptKeys = Object.keys(parts['script']);
-
- if (scriptKeys.length === 1) {
- output = getRequire(this, options, 'script', scriptKeys.pop(), resource)
- } else if (scriptKeys.length > 1) {
- this.emitWarning(`Only one type script tag is allowed per component. The last one will be used.`);
- } else {
- this.emitError('At least one script tag per component is required!');
+ // parse content for validation, no transpiling or processing of parts is actually done here
+ const parts = parse(content);
+ const scriptParts = [];
+ let primaryPart;
+ parts.forEach((part) => {
+ // validate options, making sure we have loaders for each mimeType
+ if (typeof options.map[part.mimeType] === 'undefined') {
+ this.emitError(`Missing loader for tag <${part.tag} type="${part.mimeType}"> in one-loader`);
+ }
+ // look for scripts
+ if (part.tag === 'script') {
+ if (part.id === 'component') {
+ primaryPart = part;
+ } else {
+ scriptParts.push(part);
+ }
+ }
+ });
+ if (!primaryPart) {
+ if (scriptParts.length > 1) {
+ this.emitWarning(`Multiple script tags found, using the first as the component. Set id="component" on the primary tag to avoid this warning`);
+ } else if (scriptParts.length < 1) {
+ this.emitError(`A script tag is required in every .one file`);
+ }
+ primaryPart = scriptParts[0];
}
-
- cb(null, output);
+ // require just the javascript part of the .one file here.
+ // The other components will be stuffed into the content of the javascript part by the partLoaderPrimaryScript.js loader
+ return 'module.exports = ' + getRequirePrimary(this, primaryPart, options, resource);
}
diff --git a/src/loader.js b/src/loader.js
deleted file mode 100644
index a3ee5b9..0000000
--- a/src/loader.js
+++ /dev/null
@@ -1,32 +0,0 @@
-const loaderUtils = require('loader-utils');
-const parse = require('./parse').default;
-const { getRequire } = require('./require');
-
-/**
- * Helper loader that returns content based on requested tag and type
- *
- * @param {string} content
- */
-module.exports = function (content) {
- let output = '';
-
- const cb = this.async()
- const parts = parse(content);
- const query = loaderUtils.parseQuery(this.query);
- const resource = loaderUtils.getRemainingRequest(this);
- const styleKeys = Object.keys(parts['style']);
-
- if (query.tag === 'script') {
- if (styleKeys.length === 1) {
- output += getRequire(this, query.options, 'style', styleKeys.pop(), resource);
- } else if (styleKeys.length > 1) {
- this.emitWarning(`Only one type of style tag is allowed per component. The last one will be used.`);
- }
-
- output += parts['script'][query.type];
- } else if (query.tag === 'style') {
- output = parts['style'][query.type];
- }
-
- cb(null, output)
-}
diff --git a/src/parse.js b/src/parse.js
index b8579dd..9712024 100644
--- a/src/parse.js
+++ b/src/parse.js
@@ -1,6 +1,4 @@
-const get = require('lodash.get');
-const set = require('lodash.set');
-const parser = require('posthtml-parser');
+const cheerio = require('cheerio');
/**
* Parse file content (html) and categorize it by tag and type
@@ -9,72 +7,22 @@ const parser = require('posthtml-parser');
* @returns {object}
*/
module.exports.default = function (content) {
- let output = {};
-
- const nodes = parser(content);
-
- nodes.forEach((node) => {
- if (typeof node == 'object' && isCorrectTag(node)) {
- append(output, [node.tag, getType(node)], getContent(node));
- }
+ const defaultTagTypes = {
+ script: 'javascript',
+ style: 'text/css',
+ template: 'text/html',
+ }
+ const $ = cheerio.load(`${content}`, {decodeEntities: false});
+ let output = [];
+ $('body > script, body > style, body > template').each(function (i) {
+ const node = $(this);
+ output.push({
+ id: node.attr('id') || `__one_loader_internal__part-${i}`,
+ tag: this.tagName,
+ mimeType: node.attr('type') || defaultTagTypes[this.tagName],
+ content: node.html(),
+ })
});
-
return output;
}
-/**
- * Add property of given path to the object
- *
- * @param {object} object
- * @param {array} path
- * @param {string} value
- */
-function append(object, path, value) {
- set(object, path, get(object, path, '') + `\r\n${value}`);
-}
-
-/**
- * Get code content of given tag (node)
- * @param {object} node
- * @returns {string}
- */
-function getContent(node) {
- return (node.content || []).join(' ');
-}
-
-/**
- * Get tag type property
- * @param {object} node
- * @returns {string}
- */
-function getType(node) {
- const tagLoaders = {
- script: 'javascript',
- style: 'text/css'
- };
-
- if(typeof node.attrs == 'undefined' || typeof node.attrs.type == 'undefined')
- return tagLoaders[node.tag];
-
- return node.attrs.type;
-}
-
-/**
- * Verify tag is either `script` or `style`
- *
- * @param {object} node
- * @returns {boolean}
- */
-function isCorrectTag(node) {
- return node.tag === 'script' || node.tag === 'style';
-}
-
-/*
- * Export private functions for testing purposes
- */
-if (process.env.NODE_ENV === 'test') {
- module.exports.append = append;
- module.exports.getContent = getContent;
- module.exports.getType = getType;
- module.exports.isCorrectTag = isCorrectTag;
-}
diff --git a/src/partLoaderAdditional.js b/src/partLoaderAdditional.js
new file mode 100644
index 0000000..62d263f
--- /dev/null
+++ b/src/partLoaderAdditional.js
@@ -0,0 +1,20 @@
+const loaderUtils = require('loader-utils');
+const parse = require('./parse').default;
+
+/**
+ * Helper loader that returns content based on requested part id
+ *
+ * @param {string} content
+ */
+module.exports = function (content) {
+ const parts = parse(content);
+ const query = loaderUtils.parseQuery(this.query);
+ let output;
+ parts.forEach((part) => {
+ if (part.id === query.id) {
+ output = part.content;
+ return false;
+ }
+ });
+ return output;
+}
diff --git a/src/partLoaderPrimaryScript.js b/src/partLoaderPrimaryScript.js
new file mode 100644
index 0000000..cb01098
--- /dev/null
+++ b/src/partLoaderPrimaryScript.js
@@ -0,0 +1,26 @@
+const loaderUtils = require('loader-utils');
+const parse = require('./parse').default;
+const {getRequireAdditional} = require('./require');
+
+/**
+ * Helper loader that returns content based on requested part id
+ *
+ * @param {string} content
+ */
+module.exports = function (content) {
+ const parts = parse(content);
+ const query = loaderUtils.parseQuery(this.query);
+ const resource = loaderUtils.getRemainingRequest(this);
+
+ let primaryPart;
+ let output = '';
+ parts.forEach((part) => {
+ if (part.id === query.id) {
+ primaryPart = part;
+ } else {
+ // add each additional resource as a require() to the primary part
+ output += getRequireAdditional(this, part, query.options, resource);
+ }
+ });
+ return output + primaryPart.content;
+}
diff --git a/src/require.js b/src/require.js
index 8d4115e..b279cff 100644
--- a/src/require.js
+++ b/src/require.js
@@ -1,26 +1,41 @@
const loaderUtils = require('loader-utils');
/**
- * Return full require() statement for given resource and type
+ * Return full require() statement for the first script tag which is used as the component part
*
* @param {object} context
+ * @param {object} part
* @param {object} options
- * @param {string} tag
- * @param {string} type
* @param {string} resource
* @returns {string}
*/
-function getRequire(context, options, tag, type, resource) {
- const loaders = normalizeLoaders(options.map[type]);
- const selectLoader = require.resolve('./loader.js');
+function getRequirePrimary(context, part, options, resource) {
+ const fileContentPartLoader = require.resolve('./partLoaderPrimaryScript.js');
+ const loaders = normalizeLoaders(options.map[part.mimeType]);
const request = {
- tag,
- type,
+ id: part.id,
options
};
- const url = loaderUtils.stringifyRequest(context, `!${loaders}!${selectLoader}?${JSON.stringify(request)}!${resource}`)
- const prefix = tag === 'script' ? 'module.exports = ' : 'const $style = ';
- return `${prefix}require(${url});\r\n`;
+ const url = loaderUtils.stringifyRequest(context, `!${loaders}!${fileContentPartLoader}?${JSON.stringify(request)}!${resource}`);
+ return `require(${url});\r\n`;
+}
+/**
+ * Return full require() statement for given resource and type
+ *
+ * @param {object} context
+ * @param {object} part
+ * @param {object} options
+ * @param {string} resource
+ * @returns {string}
+ */
+function getRequireAdditional(context, part, options, resource) {
+ const fileContentPartLoader = require.resolve('./partLoaderAdditional.js');
+ const loaders = normalizeLoaders(options.map[part.mimeType]);
+ const request = {
+ id: part.id,
+ };
+ const url = loaderUtils.stringifyRequest(context, `!${loaders}!${fileContentPartLoader}?${JSON.stringify(request)}!${resource}`)
+ return `require(${url});\r\n`;
}
/**
@@ -47,7 +62,7 @@ function stringifyLoaders(loaders) {
}).join('!')
}
-module.exports = { getRequire };
+module.exports = { getRequirePrimary, getRequireAdditional };
/*
* Export private functions for testing purposes