Skip to content

Scss integration #73

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Example repositories testing Vue components with jest and vue-jest:

## Supported langs

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**.
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**.

### Supported script languages

Expand All @@ -59,3 +59,26 @@ vue-jest compiles the script and template of SFCs into a JavaScript file that Je
- **pug** (`lang="pug"`)
- **jade** (`lang="jade"`)
- **haml** (`lang="haml"`)

### Supported style languages

- **stylus** (`lang="stylus"`, `lang="styl"`)
- **scss** (`lang="scss"`)
- To import globally included files (ie. variables, mixins, etc.), include them in the Jest configuration at `jest.globals['vue-jest'].resources.scss`:
```js
// package.json
{
"jest": {
"globals": {
"vue-jest": {
"resources": {
"scss": [
"./node_modules/package/_mixins.scss",
"./src/assets/css/globals.scss"
]
}
}
}
}
}
```
32 changes: 32 additions & 0 deletions lib/compilers/scss-compiler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const path = require('path')
const fs = require('fs')
const ensureRequire = require('../ensure-require')
const cwd = process.cwd()

const rewriteImports = (content, filePath) => content.replace(/@import\s+(?:'([^']+)'|"([^"]+)"|([^\s;]+))/g, (entire, single, double, unquoted) => {
const oldImportPath = single || double || unquoted
const absoluteImportPath = path.join(path.dirname(filePath), oldImportPath)
const lastCharacter = entire[entire.length - 1]
const quote = lastCharacter === "'" || lastCharacter === '"' ? lastCharacter : ''
const importPath = path.relative(cwd, absoluteImportPath)
return '@import ' + quote + importPath + quote
})

module.exports = (content, filePath, config) => {
ensureRequire('scss', ['node-sass'])
const sass = require('node-sass')

let scssResources = ''
if (config && config.resources && config.resources.scss) {
scssResources = config.resources.scss
.map(scssResource => path.resolve(process.cwd(), scssResource))
.filter(scssResourcePath => fs.existsSync(scssResourcePath))
.map(scssResourcePath => rewriteImports(fs.readFileSync(scssResourcePath).toString(), scssResourcePath))
.join('\n')
}

return sass.renderSync({
data: scssResources + rewriteImports(content, filePath),
outputStyle: 'compressed'
}).css.toString()
}
8 changes: 8 additions & 0 deletions lib/compilers/stylus-compiler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const stylus = require('stylus')
const path = require('path')

module.exports = (content, filePath, config) => stylus.render(
content, {
paths: [path.dirname(filePath), process.cwd()]
}
)
27 changes: 27 additions & 0 deletions lib/process-style.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const cssExtract = require('extract-from-css')

module.exports = function processStyle (stylePart, filePath, config) {
if (!stylePart) return {}

const processStyleByLang = lang => require('./compilers/' + lang + '-compiler')(stylePart.content, filePath, config)

let cssCode = stylePart.content
switch (stylePart.lang) {
case 'styl':
case 'stylus':
cssCode = processStyleByLang('stylus')
break
case 'scss':
cssCode = processStyleByLang('scss')
break
}

const cssNames = cssExtract.extractClasses(cssCode)
const obj = {}

for (let i = 0, l = cssNames.length; i < l; i++) {
obj[cssNames[i]] = cssNames[i]
}

return obj
}
36 changes: 11 additions & 25 deletions lib/process.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ const compileBabel = require('./compilers/babel-compiler')
const compileTypescript = require('./compilers/typescript-compiler')
const compileCoffeeScript = require('./compilers/coffee-compiler')
const extractPropsFromFunctionalTemplate = require('./extract-props')
const processStyle = require('./process-style')
const fs = require('fs')
const path = require('path')
const join = path.join
const cssExtract = require('extract-from-css')
const logger = require('./logger')
const splitRE = /\r?\n/g

Expand All @@ -29,26 +29,6 @@ function processScript (scriptPart) {
return compileBabel(scriptPart.content)
}

function processStyle (stylePart, filePath) {
if (!stylePart) return {}

let cssCode = stylePart.content
if (/^styl|stylus$/.test(stylePart.lang)) {
const dir = path.dirname(filePath)
const stylus = require('stylus')
cssCode = stylus.render(stylePart.content, { paths: [dir, process.cwd()] })
}

const cssNames = cssExtract.extractClasses(cssCode)
const obj = {}

for (let i = 0, l = cssNames.length; i < l; i++) {
obj[cssNames[i]] = cssNames[i]
}

return obj
}

function changePartsIfFunctional (parts) {
const isFunctional = parts.template && parts.template.attrs && parts.template.attrs.functional
if (isFunctional) {
Expand All @@ -59,7 +39,11 @@ function changePartsIfFunctional (parts) {
}
}

module.exports = function (src, filePath) {
module.exports = function (src, filePath, jestConfig) {
const config = jestConfig && jestConfig.globals
? jestConfig.globals['vue-jest']
: {}

var parts = vueCompiler.parseComponent(src, { pad: true })

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

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

const styleStr = parts.styles.map(ast => {
if (!module) return
const styleObj = (/^scss|sass|less|pcss|postcss/.test(ast.lang))

const styleObj = (/^sass|less|pcss|postcss/.test(ast.lang))
? {}
: processStyle(ast, filePath)
: processStyle(ast, filePath, config)

const moduleName = ast.module === true ? '$style' : ast.module

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