Skip to content

Commit ededb86

Browse files
author
Jeff Escalante
committed
Merge pull request #1 from static-dev/refactor
refactor to add filewrap, better path methods
2 parents 36ac239 + f4f9522 commit ededb86

4 files changed

Lines changed: 75 additions & 47 deletions

File tree

lib/index.js

Lines changed: 62 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const path = require('path')
77
const micromatch = require('micromatch')
88
const W = require('when')
99
const node = require('when/node')
10+
const File = require('filewrap')
1011
const SingleEntryDependency = require('webpack/lib/dependencies/SingleEntryDependency')
1112
const MultiEntryDependency = require('webpack/lib/dependencies/MultiEntryDependency')
1213

@@ -19,79 +20,83 @@ module.exports = class SpikeUtils {
1920
* Adds a number of files to webpack's pipeline as entires, so that webpack
2021
* processes them even if they are not required in the main js file.
2122
* @param {Object} compilation - object from plugin
22-
* @param {Array} files - array of absolute paths to files
23+
* @param {Array|String} files - absolute path(s) to files
2324
* @return {Promise.<Array>} compilation.addEntry return value for each file
2425
*/
2526
addFilesAsWebpackEntries (compilation, files) {
2627
return W.all(Array.prototype.concat(files).map((f) => {
27-
const name = this.getOutputPath(f)
28-
const relativePath = f.replace(this.conf.context, '.')
29-
const dep = new MultiEntryDependency([new SingleEntryDependency(relativePath)], name)
28+
const file = new File(this.conf.context, f)
29+
const dep = new MultiEntryDependency([new SingleEntryDependency(`./${file.relative}`)], file.relative)
3030
const addEntryFn = compilation.addEntry.bind(compilation)
3131

32-
return node.call(addEntryFn, this.conf.context, dep, name)
32+
return node.call(addEntryFn, this.conf.context, dep, file.relative)
3333
}))
3434
}
3535

3636
/**
37-
* Given a source file path, outputs the file's destination as spike
38-
* will write it, relative to `public`.
37+
* Given a source file path, returns the path to the final output.
3938
* @param {String} file - path to source file
40-
* @return {String} output path
39+
* @return {File} object containing relative and absolute paths
4140
*/
42-
getOutputPath (file) {
43-
let rel = file.replace(this.conf.context, '')
41+
getOutputPath (f) {
42+
let file = new File(this.conf.context, f)
4443

4544
this.conf.spike.dumpDirs.forEach((d) => {
46-
const re = new RegExp(`^${path.sep}${d}`)
47-
if (rel.match(re)) { rel = rel.replace(`${path.sep}${d}`, '') }
45+
const re = new RegExp(`^${d}\\${path.sep}`)
46+
if (file.relative.match(re)) {
47+
file = new File(this.conf.output.path, file.relative.replace(re, ''))
48+
}
4849
})
4950

50-
return rel.substring(1)
51+
return file
52+
}
53+
54+
/**
55+
* Given a file's output path, returns the path to the source file.
56+
* @param {String} f - path to an output file, relative or absolute
57+
* @return {File} object containing relative and absolute paths
58+
*/
59+
getSourcePath (f) {
60+
let file = new File(this.conf.output.path, f)
61+
62+
// check to see if the file is from a dumpDir path
63+
// https://github.com/bcoe/nyc/issues/259
64+
/* istanbul ignore next */
65+
glob.sync(`${this.conf.context}/*(${this.conf.spike.dumpDirs.join('|')})/**`).forEach((d) => {
66+
const test = new RegExp(file.relative)
67+
if (d.match(test)) file = new File(this.conf.context, d)
68+
})
69+
70+
return file
5171
}
5272

5373
/**
5474
* Removes assets from the webpack compilation, so that static files are not
5575
* written to the js file, since we already write them as static files.
76+
*
77+
* The `addFilesAsWebpackEntries` function uses the relative source path
78+
* to name files, and `this.conf.output.name` appends '.js' to the end, so
79+
* this is how the files appear in the compilation assets.
80+
*
81+
* As such, we transform the array of paths to ensure that we are getting a
82+
* relative source path, then append '.js' to the end. We then loop through
83+
* webpack's compilation assets and remove the ones we don't want to write.
84+
*
5685
* @param {Object} compilation - webpack compilation object from plugin
57-
* @param {Array} _files - array of absolute paths to processed files
86+
* @param {Array|String} _files - path(s) to source files, relative/absolute
5887
* @param {Function} done - callback
5988
*/
6089
removeAssets (compilation, _files) {
61-
// assets are set in compilation.assets as the output path, relative to
62-
// the root, with '.js' at the end, so we transform to that format for
63-
// comparison
6490
let files = Array.prototype.concat(_files).map((f) => {
65-
return this.getOutputPath(f).replace(`${this.conf.context}/`, '') + '.js'
91+
const file = new File(this.conf.context, f)
92+
return `${file.relative}.js`
6693
})
67-
// now we go through all the assets and remove the ones we have processed
68-
// with spike so that they are not written to the js file
94+
6995
for (const a in compilation.assets) {
7096
if (files.indexOf(a) > -1) { delete compilation.assets[a] }
7197
}
7298
}
7399

74-
/**
75-
* Takes a relative path like `img/foo.png` and resolves it to an absolute
76-
* path. Function respects your dumpDirs and knows how to resolve it's
77-
* absolute source path.
78-
* @param {String} file - a relative path
79-
* @return {String} absolute path to the file
80-
*/
81-
resolveRelativeSourcePath (file) {
82-
let rel = file.replace(this.conf.context, '')
83-
84-
// check to see if the file is from a dumpDir path
85-
/* istanbul ignore next */
86-
// https://github.com/bcoe/nyc/issues/259
87-
glob.sync(`${this.conf.context}/*(${this.conf.spike.dumpDirs.join('|')})/**`).forEach((d) => {
88-
const test = new RegExp(rel)
89-
if (d.match(test)) { rel = d }
90-
})
91-
92-
return path.join(rel)
93-
}
94-
95100
/**
96101
* Boolean return whether a file matches any of the configured ignores.
97102
* @param {String} file - absolute file path
@@ -101,8 +106,24 @@ module.exports = class SpikeUtils {
101106
return micromatch.any(file, this.conf.spike.ignore)
102107
}
103108

109+
/**
110+
* A shortcut to run a plugin on initialization in compile and watch mode.
111+
* @param {Compiler} compiler - webpack compiler instance from plugin
112+
* @param {Function} cb - function to be run in watch and compile mode
113+
*/
104114
runAll (compiler, cb) {
105115
compiler.plugin('run', cb)
106116
compiler.plugin('watch-run', cb)
107117
}
118+
119+
/**
120+
* Micromatch alias for simple glob matching.
121+
* @param {Array} strings - array of strings to match against
122+
* @param {Array|String} patterns - glob patterns for matching
123+
* @param {Object} [options] - micromatch options
124+
* @return {Array} array of matching strings
125+
*/
126+
matchGlobs () {
127+
return micromatch.apply(micromatch, arguments)
128+
}
108129
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
},
1313
"bugs": "https://github.com/static-dev/spike-utils/issues",
1414
"dependencies": {
15+
"filewrap": "0.1.0",
1516
"glob": "^7.0.3",
1617
"micromatch": "^2.3.8",
1718
"when": "^3.7.7"

test/index.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ test.cb('EVERYTHING WORKS', (t) => {
1212
injectFile: path.join(fixturePath, 'views/index.txt')
1313
})
1414

15-
t.plan(7)
15+
t.plan(10)
1616

1717
plugin.on('addFilesAsWebpackEntries', (comp) => {
1818
const mod = comp.modules.find((m) => m.rawRequest === './views/index.txt')
@@ -22,11 +22,16 @@ test.cb('EVERYTHING WORKS', (t) => {
2222
// TODO: this also needs to be tested with watch mode
2323
plugin.on('runAll', () => { t.truthy(true) })
2424
plugin.on('removeAssets', () => { t.truthy(true) })
25-
plugin.on('getOutputPath', (p) => { t.truthy(p, 'index.txt') })
2625
plugin.on('isFileIgnored', (r) => { t.truthy(r) })
26+
plugin.on('matchGlobs', (r) => { t.truthy(r.length === 2) })
27+
plugin.on('getOutputPath', (p) => {
28+
t.truthy(p.relative, 'index.txt')
29+
t.truthy(p.absolute.match('public'))
30+
})
2731

28-
plugin.on('resolveRelativeSourcePath', (p) => {
29-
t.truthy(p.replace(fixturePath, '') === '/views/index.txt')
32+
plugin.on('getSourcePath', (p) => {
33+
t.truthy(p.relative === 'views/index.txt')
34+
t.falsy(p.absolute.match('public'))
3035
})
3136

3237
const project = new Spike({

test/plugin.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ module.exports = class TestPlugin extends EventEmitter {
1212
this.util.runAll(compiler, this.run.bind(this))
1313

1414
this.emit('getOutputPath', this.util.getOutputPath(this.injectFile))
15-
this.emit('resolveRelativeSourcePath', this.util.resolveRelativeSourcePath('index.txt'))
15+
this.emit('getSourcePath', this.util.getSourcePath('index.txt'))
1616
this.emit('isFileIgnored', this.util.isFileIgnored('/views/ignoreme.txt'))
17+
this.emit('matchGlobs', this.util.matchGlobs(['a/foo', 'a/bar', 'b/foo'], ['a/*']))
1718

1819
compiler.plugin('make', (compilation, done) => {
1920
this.util.addFilesAsWebpackEntries(compilation, this.injectFile)
2021
.then(() => this.emit('addFilesAsWebpackEntries', compilation))
21-
.done(() => done())
22+
.done(() => done(), done)
2223
})
2324

2425
compiler.plugin('compilation', (compilation) => {

0 commit comments

Comments
 (0)