|
| 1 | +/* |
| 2 | + MIT License http://www.opensource.org/licenses/mit-license.php |
| 3 | + Author yibn2008<yibn2008@qq.com> |
| 4 | +*/ |
| 5 | +'use strict' |
| 6 | + |
| 7 | +// const chalk = require('chalk') |
| 8 | +const path = require('path') |
| 9 | +const { RawSource } = require('webpack-sources') |
| 10 | +const loaderUtils = require('loader-utils') |
| 11 | +const cssReplace = require('./css-replace') |
| 12 | + |
| 13 | +const isCSS = (name) => /\.css$/.test(name) |
| 14 | +// const strip = (str) => str.replace(/\/$/, '') |
| 15 | + |
| 16 | +class CssUrlRelativePlugin { |
| 17 | + |
| 18 | + constructor (options) { |
| 19 | + this.options = options || {} |
| 20 | + } |
| 21 | + |
| 22 | + fixCssUrl (compilation, chunks, done) { |
| 23 | + const root = this.options.root |
| 24 | + const assets = compilation.assets |
| 25 | + const publicPath = compilation.options.output.publicPath || '' |
| 26 | + |
| 27 | + chunks.map((chunk) => { |
| 28 | + const input = chunk.files.filter(isCSS) |
| 29 | + |
| 30 | + for (let name of input) { |
| 31 | + const asset = assets[name] |
| 32 | + const dirname = path.dirname(name) |
| 33 | + let source = asset.source() |
| 34 | + |
| 35 | + // replace url to relative |
| 36 | + source = cssReplace(source, refer => { |
| 37 | + // handle url(...) |
| 38 | + if (refer.type === 'url' && loaderUtils.isUrlRequest(refer.path, root)) { |
| 39 | + // remove publicPath parts |
| 40 | + let pathname = refer.path |
| 41 | + if (publicPath && pathname.startsWith(publicPath)) { |
| 42 | + pathname = pathname.substring(publicPath.length) |
| 43 | + } |
| 44 | + |
| 45 | + // get relative path |
| 46 | + pathname = path.relative(dirname, pathname).replace(/\\/g, '/') |
| 47 | + |
| 48 | + return `url(${pathname})` |
| 49 | + } |
| 50 | + |
| 51 | + // return original rule |
| 52 | + return refer.rule |
| 53 | + }) |
| 54 | + |
| 55 | + assets[name] = new RawSource(source) |
| 56 | + } |
| 57 | + }) |
| 58 | + |
| 59 | + done() |
| 60 | + } |
| 61 | + |
| 62 | + apply (compiler) { |
| 63 | + const plugin = { |
| 64 | + name: 'CssUrlRelativePlugin' |
| 65 | + } |
| 66 | + |
| 67 | + // use compilation instead of this-compilation, just like other plugins do |
| 68 | + compiler.hooks.compilation.tap(plugin, compilation => { |
| 69 | + compilation.hooks.optimizeChunkAssets.tapAsync(plugin, (chunks, done) => { |
| 70 | + this.fixCssUrl(compilation, chunks, done) |
| 71 | + }) |
| 72 | + }) |
| 73 | + } |
| 74 | +} |
| 75 | + |
| 76 | +module.exports = CssUrlRelativePlugin |
0 commit comments