Skip to content

Commit e512fff

Browse files
btjkeddyerburgh
authored andcommitted
feat(scss): integration (#73)
1 parent 26e6306 commit e512fff

File tree

10 files changed

+1957
-45
lines changed

10 files changed

+1957
-45
lines changed

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ Example repositories testing Vue components with jest and vue-jest:
4747

4848
## Supported langs
4949

50-
vue-jest compiles the script and template of SFCs into a JavaScript file that Jest can run. **It does not currently compile the style section**.
50+
vue-jest compiles the script and template of SFCs into a JavaScript file that Jest can run. **Currently, SCSS and Stylus are the only style languages that are compiled**.
5151

5252
### Supported script languages
5353

@@ -59,3 +59,26 @@ vue-jest compiles the script and template of SFCs into a JavaScript file that Je
5959
- **pug** (`lang="pug"`)
6060
- **jade** (`lang="jade"`)
6161
- **haml** (`lang="haml"`)
62+
63+
### Supported style languages
64+
65+
- **stylus** (`lang="stylus"`, `lang="styl"`)
66+
- **scss** (`lang="scss"`)
67+
- To import globally included files (ie. variables, mixins, etc.), include them in the Jest configuration at `jest.globals['vue-jest'].resources.scss`:
68+
```js
69+
// package.json
70+
{
71+
"jest": {
72+
"globals": {
73+
"vue-jest": {
74+
"resources": {
75+
"scss": [
76+
"./node_modules/package/_mixins.scss",
77+
"./src/assets/css/globals.scss"
78+
]
79+
}
80+
}
81+
}
82+
}
83+
}
84+
```

lib/compilers/scss-compiler.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
const path = require('path')
2+
const fs = require('fs')
3+
const ensureRequire = require('../ensure-require')
4+
const cwd = process.cwd()
5+
6+
const rewriteImports = (content, filePath) => content.replace(/@import\s+(?:'([^']+)'|"([^"]+)"|([^\s;]+))/g, (entire, single, double, unquoted) => {
7+
const oldImportPath = single || double || unquoted
8+
const absoluteImportPath = path.join(path.dirname(filePath), oldImportPath)
9+
const lastCharacter = entire[entire.length - 1]
10+
const quote = lastCharacter === "'" || lastCharacter === '"' ? lastCharacter : ''
11+
const importPath = path.relative(cwd, absoluteImportPath)
12+
return '@import ' + quote + importPath + quote
13+
})
14+
15+
module.exports = (content, filePath, config) => {
16+
ensureRequire('scss', ['node-sass'])
17+
const sass = require('node-sass')
18+
19+
let scssResources = ''
20+
if (config && config.resources && config.resources.scss) {
21+
scssResources = config.resources.scss
22+
.map(scssResource => path.resolve(process.cwd(), scssResource))
23+
.filter(scssResourcePath => fs.existsSync(scssResourcePath))
24+
.map(scssResourcePath => rewriteImports(fs.readFileSync(scssResourcePath).toString(), scssResourcePath))
25+
.join('\n')
26+
}
27+
28+
return sass.renderSync({
29+
data: scssResources + rewriteImports(content, filePath),
30+
outputStyle: 'compressed'
31+
}).css.toString()
32+
}

lib/compilers/stylus-compiler.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const stylus = require('stylus')
2+
const path = require('path')
3+
4+
module.exports = (content, filePath, config) => stylus.render(
5+
content, {
6+
paths: [path.dirname(filePath), process.cwd()]
7+
}
8+
)

lib/process-style.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const cssExtract = require('extract-from-css')
2+
3+
module.exports = function processStyle (stylePart, filePath, config) {
4+
if (!stylePart) return {}
5+
6+
const processStyleByLang = lang => require('./compilers/' + lang + '-compiler')(stylePart.content, filePath, config)
7+
8+
let cssCode = stylePart.content
9+
switch (stylePart.lang) {
10+
case 'styl':
11+
case 'stylus':
12+
cssCode = processStyleByLang('stylus')
13+
break
14+
case 'scss':
15+
cssCode = processStyleByLang('scss')
16+
break
17+
}
18+
19+
const cssNames = cssExtract.extractClasses(cssCode)
20+
const obj = {}
21+
22+
for (let i = 0, l = cssNames.length; i < l; i++) {
23+
obj[cssNames[i]] = cssNames[i]
24+
}
25+
26+
return obj
27+
}

lib/process.js

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ const compileBabel = require('./compilers/babel-compiler')
66
const compileTypescript = require('./compilers/typescript-compiler')
77
const compileCoffeeScript = require('./compilers/coffee-compiler')
88
const extractPropsFromFunctionalTemplate = require('./extract-props')
9+
const processStyle = require('./process-style')
910
const fs = require('fs')
1011
const path = require('path')
1112
const join = path.join
12-
const cssExtract = require('extract-from-css')
1313
const logger = require('./logger')
1414
const splitRE = /\r?\n/g
1515

@@ -29,26 +29,6 @@ function processScript (scriptPart) {
2929
return compileBabel(scriptPart.content)
3030
}
3131

32-
function processStyle (stylePart, filePath) {
33-
if (!stylePart) return {}
34-
35-
let cssCode = stylePart.content
36-
if (/^styl|stylus$/.test(stylePart.lang)) {
37-
const dir = path.dirname(filePath)
38-
const stylus = require('stylus')
39-
cssCode = stylus.render(stylePart.content, { paths: [dir, process.cwd()] })
40-
}
41-
42-
const cssNames = cssExtract.extractClasses(cssCode)
43-
const obj = {}
44-
45-
for (let i = 0, l = cssNames.length; i < l; i++) {
46-
obj[cssNames[i]] = cssNames[i]
47-
}
48-
49-
return obj
50-
}
51-
5232
function changePartsIfFunctional (parts) {
5333
const isFunctional = parts.template && parts.template.attrs && parts.template.attrs.functional
5434
if (isFunctional) {
@@ -59,7 +39,11 @@ function changePartsIfFunctional (parts) {
5939
}
6040
}
6141

62-
module.exports = function (src, filePath) {
42+
module.exports = function (src, filePath, jestConfig) {
43+
const config = jestConfig && jestConfig.globals
44+
? jestConfig.globals['vue-jest']
45+
: {}
46+
6347
var parts = vueCompiler.parseComponent(src, { pad: true })
6448

6549
changePartsIfFunctional(parts)
@@ -102,15 +86,17 @@ module.exports = function (src, filePath) {
10286

10387
if (Array.isArray(parts.styles) && parts.styles.length > 0) {
10488
if ((parts.styles.some(ast => /^scss|sass|less|pcss|postcss/.test(ast.lang))) && logger.shouldLogStyleWarn) {
105-
logger.warn('Sass/SCSS, Less and PostCSS are not currently compiled by vue-jest')
89+
logger.warn('Sass, Less and PostCSS are not currently compiled by vue-jest')
10690
logger.shouldLogStyleWarn = false
10791
}
10892

10993
const styleStr = parts.styles.map(ast => {
11094
if (!module) return
111-
const styleObj = (/^scss|sass|less|pcss|postcss/.test(ast.lang))
95+
96+
const styleObj = (/^sass|less|pcss|postcss/.test(ast.lang))
11297
? {}
113-
: processStyle(ast, filePath)
98+
: processStyle(ast, filePath, config)
99+
114100
const moduleName = ast.module === true ? '$style' : ast.module
115101

116102
return '\n this[\'' + moduleName + '\'] = ' + JSON.stringify(styleObj)

0 commit comments

Comments
 (0)