Skip to content

Commit

Permalink
support custom path for extracted css file, fixed #60
Browse files Browse the repository at this point in the history
  • Loading branch information
egoist committed Jan 16, 2018
1 parent 1a5d550 commit 6eb0cc5
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 52 deletions.
12 changes: 4 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,12 @@ You can also use it as options for [`style-inject`](https://github.com/egoist/st

### extract

Type: `boolean`<br>
Type: `boolean` `string`<br>
Default: `false`

Extract CSS into its own file.
Extract CSS to the same location where JS file is generated but with `.css` extension.

You can also set it to an absolute path.

### modules

Expand Down Expand Up @@ -238,12 +240,6 @@ Type: `id => void`
A function to be invoked when an import for CSS file is detected.
### onExtract
Type: `({ code, map, codeFilePath, mapFilePath }) => any`
A function to be invoked before extracting CSS file, you can make it return `false` to disable writing CSS and map file.
## License
MIT &copy; [EGOIST](https://github.com/egoist)
87 changes: 47 additions & 40 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createFilter } from 'rollup-pluginutils'
import styleInject from 'style-inject'
import Concat from 'concat-with-sourcemaps'
import Loaders from './loaders'
import { normalizePath } from './utils'

/**
* The options that could be `boolean` or `object`
Expand Down Expand Up @@ -101,57 +102,63 @@ export default (options = {}) => {
async onwrite(opts) {
if (extracted.length === 0) return

const basename = path.basename(opts.file, path.extname(opts.file))
const file = path.relative(
process.cwd(),
path.join(path.dirname(opts.file), basename + '.css')
)
const concat = new Concat(true, file, '\n')
for (const res of extracted) {
const relative = path.relative(process.cwd(), res.id)
const map = res.map ? JSON.parse(res.map.toString()) : null
if (map) {
map.file = file
map.sources = map.sources.map(source =>
path.relative(
process.cwd(),
path.join(path.dirname(opts.file), source)
const getExtracted = filepath => {
if (!filepath) {
if (typeof postcssLoaderOptions.extract === 'string') {
filepath = postcssLoaderOptions.extract
} else {
const basename = path.basename(opts.file, path.extname(opts.file))
filepath = normalizePath(path.join(path.dirname(opts.file), basename + '.css'))
}
}
const concat = new Concat(true, filepath, '\n')
for (const res of extracted) {
const relative = normalizePath(res.id)
const map = res.map ? JSON.parse(res.map.toString()) : null
if (map) {
map.file = filepath
map.sources = map.sources.map(source =>
normalizePath(path.join(path.dirname(opts.file), source))
)
)
}
concat.add(relative, res.code, map)
}
let code = concat.content

if (sourceMap === 'inline') {
code += `\n/*# sourceMappingURL=data:application/json;base64,${Buffer.from(
concat.sourceMap,
'utf8'
).toString('base64')}*/`
} else if (sourceMap === true) {
code += `\n/*# sourceMappingURL=${path.basename(filepath)}.map */`
}
concat.add(relative, res.code, map)
}
let code = concat.content

if (sourceMap === 'inline') {
code += `\n/*# sourceMappingURL=data:application/json;base64,${Buffer.from(
concat.sourceMap,
'utf8'
).toString('base64')}*/`
} else if (sourceMap === true) {
code += `\n/*# sourceMappingURL=${basename}.css.map */`
}

// Release for potential next build
extracted = []
// Release for potential next build
extracted = []

if (options.onExtract) {
const shouldExtract = await options.onExtract({
return {
code,
map: concat.sourceMap,
codeFilePath: file,
mapFilePath: file + '.map'
})
codeFilePath: filepath,
mapFilePath: filepath + '.map'
}
}

if (options.onExtract) {
const shouldExtract = await options.onExtract(getExtracted)
if (shouldExtract === false) {
return
}
}

await Promise.all([
fs.writeFile(file, code, 'utf8'),
sourceMap === true &&
fs.writeFile(file + '.map', concat.sourceMap, 'utf8')
])
const { code, codeFilePath, map, mapFilePath } = getExtracted()
await fs.ensureDir(path.dirname(codeFilePath))
.then(() => Promise.all([
fs.writeFile(codeFilePath, code, 'utf8'),
sourceMap === true &&
fs.writeFile(mapFilePath, map, 'utf8')
]))
}
}
}
4 changes: 2 additions & 2 deletions src/postcss-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import path from 'path'
import postcss from 'postcss'
import findPostcssConfig from 'postcss-load-config'
import reserved from 'reserved-words'
import { localRequire } from './utils'
import { localRequire, normalizePath } from './utils'

function loadConfig(id, { ctx: configOptions, path: configPath }) {
const handleError = err => {
Expand Down Expand Up @@ -107,7 +107,7 @@ export default {
for (const name in json) {
const newName = ensureClassName(name)
if (name !== newName) {
console.warn(`Exported "${name}" as "${newName}" in ${path.relative(process.cwd(), this.id)}`)
console.warn(`Exported "${name}" as "${newName}" in ${normalizePath(this.id)}`)
}
output += `export var ${newName} = ${JSON.stringify(
json[name]
Expand Down
2 changes: 2 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import path from 'path'

export const localRequire = name => require(path.resolve('node_modules', name))

export const normalizePath = filepath => path.relative(process.cwd(), filepath)
34 changes: 34 additions & 0 deletions test/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,40 @@ console.log(undefined, undefined);
"
`;

exports[`extract:path: css code 1`] = `
"body {
color: red;
}
.bar {
color: red;
}
body {
color: #f00;
background: #f00;
}
/*# sourceMappingURL=test/fixtures/simple/style.css.map */
#sidebar {
width: 30%;
background-color: #faa; }
#header {
color: #6c94be;
}
/*# sourceMappingURL=extracted.css.map */"
`;

exports[`extract:path: css map 1`] = `"{\\"version\\":3,\\"sources\\":[\\"test/fixtures/dist/extract:path/foo.css\\",\\"test/fixtures/dist/extract:path/bar.css\\",\\"test/fixtures/dist/extract:path/test/fixtures/simple/style.styl\\",\\"test/fixtures/dist/extract:path/style.styl\\",\\"test/fixtures/dist/extract:path/style.sass\\",\\"test/fixtures/dist/extract:path/input\\",\\"test/fixtures/dist/extract:path/style.less\\"],\\"names\\":[],\\"mappings\\":\\"AAAA;EACE,WAAW;CACZ;;ACFD;EACE,WAAW;CACZ;;ACFD;EACE,YAAA;EACA,iBAAA;CCCD;AACD,0DAA0D;ACJ1D;EACE,WAAW;EACX,uBAAuB,EAAE;;ACC3B;EACE,eAAA;CCFD\\",\\"file\\":\\"/Users/egoist/dev/rollup-plugin-postcss/test/fixtures/dist/extract:path/this/is/extracted.css\\",\\"sourcesContent\\":[\\"body {\\\\n color: red;\\\\n}\\\\n\\",\\".bar {\\\\n color: red;\\\\n}\\\\n\\",null,null,\\"#sidebar {\\\\n width: 30%;\\\\n background-color: #faa; }\\\\n\\",null,null]}"`;

exports[`extract:path: js code 1`] = `
"'use strict';
console.log(undefined, undefined);
"
`;

exports[`inject:false: js code 1`] = `
"'use strict';
Expand Down
13 changes: 11 additions & 2 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ async function write({
format: 'cjs',
file: path.join(dirname, 'bundle.js')
})
const cssCodePath = path.join(dirname, 'bundle.css')
const cssMapPath = path.join(dirname, 'bundle.css.map')
const cssCodePath = typeof options.extract === 'string' ? options.extract : path.join(dirname, 'bundle.css')
const cssMapPath = `${cssCodePath}.map`
const jsCodePath = path.join(dirname, 'bundle.js')
return {
jsCode() {
Expand Down Expand Up @@ -91,6 +91,15 @@ snapshot({
}
})

snapshot({
title: 'extract:path',
input: 'simple/index.js',
options: {
extract: fixture('dist/extract:path/this/is/extracted.css'),
sourceMap: true
}
})

snapshot({
title: 'minimize:inject',
input: 'simple/index.js',
Expand Down

0 comments on commit 6eb0cc5

Please sign in to comment.