This repository has been archived by the owner on Oct 30, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit c1e68ac
Showing
17 changed files
with
373 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"presets": ["es2015", "stage-3"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# http://editorconfig.org | ||
|
||
# A special property that should be specified at the top of the file outside of | ||
# any sections. Set to true to stop .editor config file search on current file | ||
root = true | ||
|
||
[*] | ||
# Indentation style | ||
# Possible values - tab, space | ||
indent_style = space | ||
|
||
# Indentation size in single-spaced characters | ||
# Possible values - an integer, tab | ||
indent_size = 2 | ||
|
||
# Line ending file format | ||
# Possible values - lf, crlf, cr | ||
end_of_line = lf | ||
|
||
# File character encoding | ||
# Possible values - latin1, utf-8, utf-16be, utf-16le | ||
charset = utf-8 | ||
|
||
# Denotes whether to trim whitespace at the end of lines | ||
# Possible values - true, false | ||
trim_trailing_whitespace = true | ||
|
||
# Denotes whether file should end with a newline | ||
# Possible values - true, false | ||
insert_final_newline = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
{ | ||
"env": { | ||
"es6": true, | ||
"node": true | ||
}, | ||
"extends": "eslint:recommended", | ||
"parser": "babel-eslint", | ||
"plugins": [ | ||
"babel" | ||
], | ||
"parserOptions": { | ||
"sourceType": "module" | ||
}, | ||
"rules": { | ||
"indent": [ | ||
"error", | ||
2 | ||
], | ||
"linebreak-style": [ | ||
"error", | ||
"unix" | ||
], | ||
"quotes": [ | ||
"error", | ||
"single" | ||
], | ||
"semi": [ | ||
"error", | ||
"always" | ||
], | ||
"no-console": [ | ||
0 | ||
], | ||
"no-var": [ | ||
"error" | ||
], | ||
"comma-dangle": [ | ||
"error", | ||
"always" | ||
], | ||
"no-unused-vars": [ | ||
2, {"vars": "all", "args": "after-used"} | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
lib | ||
bundle.js | ||
example.css.d.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.babelrc | ||
.eslintrc | ||
.editorconfig | ||
jsconfig.json | ||
src | ||
test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# typings-for-css-modules-loaderg | ||
|
||
Webpack loader that works as a css-loader drop-in replacement to generate TypeScript typings for CSS modules on the fly | ||
|
||
## Installation | ||
|
||
Install via npm `npm install --save-dev typings-for-css-modules-loader` | ||
|
||
## Usage | ||
|
||
Keep your `webpack.config` as is just instead of using `css-loader` use `typings-for-css-modules-loader` | ||
*its important you keep all the params that you used for the css-loader before, as they will be passed along in the process* | ||
|
||
before: | ||
```js | ||
webpackConfig.module.loaders: [ | ||
{ test: /\.css$/, loader: 'css?modules' } | ||
{ test: /\.scss$/, loader: 'css?modules&sass' } | ||
]; | ||
``` | ||
|
||
after: | ||
```js | ||
webpackConfig.module.loaders: [ | ||
{ test: /\.css$/, loader: 'typings-for-css-modules?modules' } | ||
{ test: /\.scss$/, loader: 'typings-for-css-modules?modules&sass' } | ||
]; | ||
``` | ||
|
||
## Example | ||
|
||
Imagine you have a file `~/my-project/src/component/MyComponent/component.scss` in your project with the following content: | ||
``` | ||
.some-class { | ||
// some styles | ||
&.someOtherClass { | ||
// some other styles | ||
} | ||
&-sayWhat { | ||
// more styles | ||
} | ||
} | ||
``` | ||
|
||
Adding the `typings-for-css-modules-loader` will generate a file `~/my-project/src/component/MyComponent/mycomponent.scss.d.ts` that has the following content: | ||
``` | ||
export interface IMyComponentScss { | ||
'some-class': string; | ||
'someOtherClass': string; | ||
'some-class-sayWhat': string; | ||
} | ||
declare const styles: IMyComponentScss; | ||
export default styles; | ||
``` | ||
|
||
### Example in Visual Studio Code | ||
 | ||
|
||
## Support | ||
|
||
As the loader just acts as an intermediary it can handle all kind of css preprocessors (`sass`, `scss`, `stylus`, `less`, ...). | ||
The only requirement is that those preprocessors have proper webpack loaders defined - meaning they can already be loaded by webpack anyways. | ||
|
||
## Requirements | ||
|
||
The loader uses `css-loader`(https://github.com/webpack/css-loader) under the hood. Thus it is a peer-dependency and the expected loader to create CSS Modules. | ||
|
||
## Known issues | ||
|
||
- There may be a lag or a reload necessary when adding a new style-file to your project as the typescript loader may take a while to "find" the new typings file. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"compilerOptions": { | ||
"target": "ES6" | ||
}, | ||
"exclude": [ | ||
"node_modules" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
{ | ||
"name": "typings-for-css-modules-loader", | ||
"version": "0.0.1", | ||
"description": "Drop-in replacement for css-loader to generate typings for your CSS-Modules on the fly in webpack", | ||
"main": "lib/index.js", | ||
"scripts": { | ||
"build": "babel src -d lib", | ||
"prepublish": "npm run build", | ||
"pretest": "rm -f ./test/example.css.d.ts && touch ./test/example.css.d.ts", | ||
"test:run": "babel-node ./node_modules/webpack/bin/webpack --config ./test/webpack.config.babel.js && diff ./test/example.css.d.ts ./test/expected-example.css.d.ts", | ||
"test": "npm run test:run > /dev/null 2>&1 && npm run test:run" | ||
}, | ||
"author": "Tim Sebastian <[email protected]>", | ||
"license": "MIT", | ||
"keywords": [ | ||
"Typescript", | ||
"TypeScript", | ||
"CSS Modules", | ||
"CSSModules", | ||
"CSS Modules typings", | ||
"Webpack", | ||
"Webpack loader", | ||
"Webpack css module typings loader", | ||
"typescript webpack typings", | ||
"css modules webpack typings" | ||
], | ||
"dependencies": { | ||
"graceful-fs": "4.1.4" | ||
}, | ||
"devDependencies": { | ||
"babel-cli": "6.10.1", | ||
"babel-eslint": "6.1.0", | ||
"babel-loader": "^6.2.5", | ||
"babel-polyfill": "^6.13.0", | ||
"babel-preset-es2015": "6.9.0", | ||
"babel-preset-stage-0": "6.5.0", | ||
"eslint": "2.13.1", | ||
"eslint-plugin-babel": "3.3.0", | ||
"ts-loader": "^0.8.2", | ||
"typescript": "^1.8.10", | ||
"webpack": "^1.13.2" | ||
}, | ||
"peerDependencies": { | ||
"css-loader": "^0.23.1" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/Jimdo/typings-for-css-modules-loader.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/Jimdo/typings-for-css-modules-loader/issues" | ||
}, | ||
"homepage": "https://github.com/Jimdo/typings-for-css-modules-loader#readme" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import path from 'path'; | ||
import vm from 'vm'; | ||
|
||
const isCssModule = (module) => { | ||
if (!module || typeof module.request !== 'string') { | ||
return false; | ||
} | ||
|
||
const extname = path.extname(module.request); | ||
return /\/css-loader\//.test(module.request) && extname !== '.js'; | ||
}; | ||
|
||
export const filterCssModules = (modules) => { | ||
return modules.filter(isCssModule); | ||
}; | ||
|
||
export const removeLoadersBeforeCssLoader = (loaders) => { | ||
let sawCssLoader = false; | ||
// remove all loaders before the css-loader | ||
return loaders.filter((loader)=> { | ||
if (loader.indexOf('/css-loader/') > -1) { | ||
sawCssLoader = true; | ||
} | ||
|
||
return sawCssLoader; | ||
}); | ||
}; | ||
|
||
export const extractCssModuleFromSource = (source) => { | ||
const sandbox = { | ||
exports: null, | ||
module: {}, | ||
require: () => () => [], | ||
}; | ||
const script = new vm.Script(source); | ||
const context = new vm.createContext(sandbox); | ||
script.runInContext(context); | ||
return sandbox.exports.locals; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import path from 'path'; | ||
|
||
const filenameToInterfaceName = (filename) => { | ||
return path.basename(filename) | ||
.replace(/^(\w)/, (_, c) => 'I' + c.toUpperCase()) | ||
.replace(/\W+(\w)/g, (_, c) => c.toUpperCase()); | ||
}; | ||
|
||
const cssModuleToTypescriptInterfaceProperties = (cssModuleObject, indent = ' ') => { | ||
return Object.keys(cssModuleObject) | ||
.map((key) => `${indent}'${key}': string;`) | ||
.join('\n'); | ||
}; | ||
|
||
export const filenameToTypingsFilename = (filename) => { | ||
const dirName = path.dirname(filename); | ||
const baseName = path.basename(filename); | ||
return path.join(dirName, `${baseName}.d.ts`); | ||
}; | ||
|
||
export const generateInterface = (cssModuleObject, filename, indent) => { | ||
const interfaceName = filenameToInterfaceName(filename); | ||
const interfaceProperties = cssModuleToTypescriptInterfaceProperties(cssModuleObject, indent); | ||
return ( | ||
`export interface ${interfaceName} { | ||
${interfaceProperties} | ||
} | ||
declare const styles: ${interfaceName}; | ||
export default styles; | ||
`); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import cssLoader from 'css-loader'; | ||
import cssLocalsLoader from 'css-loader/locals'; | ||
import { | ||
generateInterface, | ||
filenameToTypingsFilename, | ||
} from './cssModuleToInterface'; | ||
import * as persist from './persist'; | ||
|
||
module.exports = function(input) { | ||
if(this.cacheable) this.cacheable(); | ||
|
||
// mock async step 1 - css loader is async, we need to intercept this so we get async ourselves | ||
const callback = this.async(); | ||
// mock async step 2 - offer css loader a "fake" callback | ||
this.async = () => (err, content) => { | ||
const cssmodules = this.exec(content); | ||
const requestedResource = this.resourcePath; | ||
|
||
const cssModuleInterfaceFilename = filenameToTypingsFilename(requestedResource); | ||
const cssModuleInterface = generateInterface(cssmodules, requestedResource); | ||
persist.writeToFileIfChanged(cssModuleInterfaceFilename, cssModuleInterface); | ||
// mock async step 3 - make `async` return the actual callback again before calling the 'real' css-loader | ||
this.async = () => callback; | ||
cssLoader.call(this, input); | ||
}; | ||
cssLocalsLoader.call(this, input); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import fs from 'graceful-fs'; | ||
import crypto from 'crypto'; | ||
|
||
export const writeToFileIfChanged = (filename, content) => { | ||
try { | ||
const currentInput = fs.readFileSync(filename, 'utf-8'); | ||
const oldHash = crypto.createHash('md5').update(currentInput).digest("hex"); | ||
const newHash = crypto.createHash('md5').update(content).digest("hex"); | ||
// the definitions haven't changed - ignore this | ||
if (oldHash === newHash) { | ||
return false; | ||
} | ||
} catch(e) { | ||
} finally { | ||
fs.writeFileSync(filename, content); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import styles from './example.css'; | ||
|
||
const foo = styles.foo; | ||
const barBaz = styles['bar-baz']; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.foo { | ||
color: white; | ||
} | ||
|
||
.bar-baz { | ||
color: green; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export interface IExampleCss { | ||
'foo': string; | ||
'bar-baz': string; | ||
} | ||
declare const styles: IExampleCss; | ||
|
||
export default styles; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"compilerOptions": { | ||
"target": "es6", | ||
"noImplicitAny": true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
module.exports = { | ||
entry: './test/entry.ts', | ||
output: { | ||
path: __dirname, | ||
filename: 'bundle.js' | ||
}, | ||
module: { | ||
loaders: [ | ||
{ test: /\.ts$/, loaders: ['babel', 'ts'] }, | ||
{ test: /\.css$/, loader: '../src/index.js?modules' } | ||
] | ||
} | ||
}; |