rollup-plugin-postcss 의 path alias 문제

rollup-plugin-postcss

  • 현재(210911) 메인테이너를 구하는 프로젝트이므로 이슈가 수정되지 않는다.

scss alias

1
2
3
4
5
// ~는 노드 모듈 처리된다.
@import '~@material';

// @styles 로 사용하고 싶을 경우가 있다.
@import '@styles/mystyle';
  • 두 번째의 경우는 scss 시트를 처리해주면서 (plugin postcss) Error: Can't find stylesheet to import. 와 같은 에러를 뱉는다.
  • 웹팩의 경우 resolve.alias 가 알아서 처리를 해주지만, rollup-plugin-postcss 의 sass-loader 에서 importer 를 추가해줘야할 것 같았다.

sass-loader

  • 이 플러그인의 sass-loader 는 dart-sass 의 importer 를 확장해서 쉽게 추가가 가능해보였다.
  • 그러나 아무리 확장처리를 해도 importer 에서 해당 경로가 리졸브 되지 않았고 관련 이슈가 3개, PR이 2개 등록된 것을 확인할 수 있다.
  • 이 걸 해결하려면 postcss.use.sass 사용시에 importer 를 override 해주는 custom sass-loader 를 직접 만들어야한다.

custom-sass-loader

  • https://github.com/egoist/rollup-plugin-postcss/blob/master/src/sass-loader.js
  • pity 는 promisify 로 대체 가능하여 지웠고 import-cwd 도 node 코어를 사용하게 변경했다.
  • p-queue 도 child_process 로 대체 가능해보인다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { createRequire } from 'module';
import path from 'path';
import { promisify } from 'util';

import resolve from 'resolve';
import PQueue from 'p-queue';

function loadModule(moduleId) {
try {
return require(moduleId);
} catch {
// Ignore error
}

try {
return createRequire(path.resolve(process.cwd(), 'noop.js'))(moduleId);
} catch {
// Ignore error
}
}

// This queue makes sure node-sass leaves one thread available for executing fs tasks
// See: https://github.com/sass/node-sass/issues/857
const threadPoolSize = process.env.UV_THREADPOOL_SIZE || 4;
const workQueue = new PQueue({ concurrency: threadPoolSize - 1 });

const moduleRe = /^~([a-z\d]|@).+/i;

const getUrlOfPartial = (url) => {
const parsedUrl = path.parse(url);
return `${parsedUrl.dir}${path.sep}_${parsedUrl.base}`;
};

const resolvePromise = promisify(resolve);

// List of supported SASS modules in the order of preference
const sassModuleIds = ['node-sass', 'sass'];

export default {
name: 'sass',
test: /\.(sass|scss)$/,
process({ code }) {
return new Promise((resolve, reject) => {
const sass = loadSassOrThrow();
const render = promisify(sass.render.bind(sass));
const data = this.options.data || '';
workQueue.add(() =>
render({
...this.options,
file: this.id,
data: data + code,
indentedSyntax: /\.sass$/.test(this.id),
sourceMap: this.sourceMap,
importer: [
(url, importer, done) => {
if (!moduleRe.test(url)) {
// 이부분에 alias importer 가 추가되어야한다.
if (/^@styles/.test(url)) {
return done({
file: url.replace(
/^@styles/,
path.resolve(__dirname, './src/styles'),
),
});
}
return done({ file: url });
}
const moduleUrl = url.slice(1);
const partialUrl = getUrlOfPartial(moduleUrl);

const options = {
basedir: path.dirname(importer),
extensions: ['.scss', '.sass', '.css'],
};
const finishImport = (id) => {
done({
// Do not add `.css` extension in order to inline the file
file: id.endsWith('.css') ? id.replace(/\.css$/, '') : id,
});
};

const next = () => {
// Catch all resolving errors, return the original file and pass responsibility back to other custom importers
done({ file: url });
};

// Give precedence to importing a partial
resolvePromise(partialUrl, options)
.then(finishImport)
.catch((error) => {
if (
error.code === 'MODULE_NOT_FOUND' ||
error.code === 'ENOENT'
) {
resolvePromise(moduleUrl, options)
.then(finishImport)
.catch(next);
} else {
next();
}
});
},
].concat(this.options.importer || []),
})
.then((result) => {
for (const file of result.stats.includedFiles) {
this.dependencies.add(file);
}

resolve({
code: result.css.toString(),
map: result.map && result.map.toString(),
});
})
.catch(reject),
);
});
},
};

// 이하 생략...

rollup.config.js

위의 커스터마이징된 sass-loader 를 use: ['sass'] 대신 등록해준다.

1
2
3
4
5
6
postcss({
// 추가
loaders: [customSassLoader],
// 제거
// use: ['sass']
})

결론

  • rollup-plugin-postcss 는 이슈가 있어 확장을 직접해야하고 이는 유지보수 포인트로 다가올 수 있다.
  • postcss-import 는 alias 기능이 없어 사용이 불가능하다.
  • postcss-import-alias 등등의 alias 를 추가한 라이브러리도 불가능한데, 이는 postcssLoader 가 먼저 등록 되는데 의외의 결과이다. rollup-plugin-postcss 를 직접 로컬에서 빌드해서 해당 지점을 확인해볼 수 있겠지만 PR 을 받지 않으므로 의미도 없다.
  • rollup-plugin-scss를 사용하고 postcss 를 processor 로 줘서 반대로 처리할 수 있어보이는데, 빌드 파이프라인을 다 리팩토링을 해야하므로 나중에 도전해보는걸로 하자.