1 | 'use strict'
|
2 |
|
3 | const path = require('path')
|
4 | const rollup = require('rollup')
|
5 | const chokidar = require('chokidar')
|
6 | const debounce = require('debounce')
|
7 |
|
8 | const hasNullByte = string => string.includes('\u0000')
|
9 |
|
10 | function createWatcher(emitter) {
|
11 | let files = new Map()
|
12 | let watch = chokidar.watch()
|
13 |
|
14 | const refreshFile = filePath => {
|
15 | |
16 |
|
17 |
|
18 |
|
19 |
|
20 | let isPOSIX = path.sep === '/'
|
21 | filePath = isPOSIX ? filePath : filePath.replace(/\\/g, '/')
|
22 | emitter._fileList.changeFile(filePath, true)
|
23 | }
|
24 |
|
25 | const handleChange = path => {
|
26 | for (const [entry, dependencies] of files.entries()) {
|
27 | if (entry === path || dependencies.includes(path)) {
|
28 | return refreshFile(entry)
|
29 | }
|
30 | }
|
31 | }
|
32 |
|
33 | watch.on('change', debounce(handleChange, 150))
|
34 |
|
35 | return {
|
36 | add(entry, dependencies) {
|
37 | if (!hasNullByte(entry)) {
|
38 | let filteredDependencies = dependencies.filter(path => !hasNullByte(path))
|
39 | files.set(entry, filteredDependencies)
|
40 | watch.add([entry, ...filteredDependencies])
|
41 | }
|
42 | },
|
43 | }
|
44 | }
|
45 |
|
46 | function createPreprocessor(preconfig, config, emitter, logger) {
|
47 | let cache = new Map()
|
48 | let log = logger.create('preprocessor.rollup')
|
49 |
|
50 | let watcher
|
51 | if (!config.singleRun && config.autoWatch) {
|
52 | watcher = createWatcher(emitter)
|
53 | }
|
54 |
|
55 | return async function preprocess(original, file, done) {
|
56 | let originalPath = file.originalPath
|
57 | let location = path.relative(config.basePath, originalPath)
|
58 | try {
|
59 | let options = Object.assign({}, config.rollupPreprocessor, preconfig.options, {
|
60 | input: originalPath,
|
61 | cache: cache.get(originalPath),
|
62 | })
|
63 |
|
64 | options.output = Object.assign({}, options.output, {
|
65 | dir: path.dirname(originalPath)
|
66 | })
|
67 |
|
68 | let bundle = await rollup.rollup(options)
|
69 | cache.set(originalPath, bundle.cache)
|
70 |
|
71 | if (watcher) {
|
72 | let [entry, ...dependencies] = bundle.watchFiles
|
73 | watcher.add(entry, dependencies)
|
74 | }
|
75 |
|
76 | log.info('Generating bundle for ./%s', location)
|
77 | let { output } = await bundle.generate(options.output)
|
78 |
|
79 | for (let result of output) {
|
80 | if (!result.isAsset) {
|
81 | let { code, map, facadeModuleId, fileName } = result
|
82 |
|
83 | |
84 |
|
85 |
|
86 |
|
87 | if (facadeModuleId && !hasNullByte(facadeModuleId)) {
|
88 | let { dir } = path.parse(originalPath)
|
89 | file.path = path.posix.join(dir, fileName)
|
90 | }
|
91 |
|
92 | file.sourceMap = map
|
93 |
|
94 | let processed =
|
95 | options.output.sourcemap === 'inline'
|
96 | ? code + `\n//# sourceMappingURL=${map.toUrl()}\n`
|
97 | : code
|
98 |
|
99 | return done(null, processed)
|
100 | }
|
101 | }
|
102 | log.warn('Nothing was processed.')
|
103 | done(null, original)
|
104 | } catch (error) {
|
105 | log.error('Failed to process ./%s\n\n%s\n', location, error.stack)
|
106 | done(error, null)
|
107 | }
|
108 | }
|
109 | }
|
110 |
|
111 | module.exports = {
|
112 | 'preprocessor:rollup': [
|
113 | 'factory',
|
114 | (factory => {
|
115 | factory.$inject = ['args', 'config', 'emitter', 'logger']
|
116 | return factory
|
117 | })(createPreprocessor),
|
118 | ],
|
119 | }
|