@hippy/vue-css-loader
Version:
hippy-vue style loader module for webpack
85 lines (77 loc) • 2.94 kB
text/typescript
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2022 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import crypto from 'crypto';
import { getOptions } from 'loader-utils';
import { GLOBAL_STYLE_NAME, GLOBAL_DISPOSE_STYLE_NAME } from '@vue/runtime/constants';
import parseCSS from './css-parser';
import translateColor, { names as colorNames } from './color-parser';
let sourceId = 0;
/**
* Convert the CSS text to AST that able to parse by selector parser.
*/
function hippyVueCSSLoader(this: any, source: any) {
const options = getOptions(this);
const parsed = parseCSS(source, { source: sourceId });
const majorNodeVersion = parseInt(process.versions.node.split('.')[0], 10);
const hashType = majorNodeVersion >= 17 ? 'md5' : 'md4';
const hash = crypto.createHash(hashType);
const contentHash = hash.update(source).digest('hex');
sourceId += 1;
const rulesAst = parsed.stylesheet.rules.filter((n: any) => n.type === 'rule').map((n: any) => ({
hash: contentHash,
selectors: n.selectors,
declarations: n.declarations.map((dec: any) => {
let { value } = dec;
const isVariableColor = dec.property?.startsWith('-') && typeof value === 'string'
&& (
value.includes('#')
|| value.includes('rgb')
|| value.includes('hls')
|| value.includes('hue')
|| value.trim() in colorNames
);
if (dec.property && (dec.property.toLowerCase().indexOf('color') > -1 || isVariableColor)) {
value = translateColor(value);
}
return {
type: dec.type,
property: dec.property,
value,
};
}),
}));
const code = `(function() {
if (!global['${GLOBAL_STYLE_NAME}']) {
global['${GLOBAL_STYLE_NAME}'] = [];
}
global['${GLOBAL_STYLE_NAME}'] = global['${GLOBAL_STYLE_NAME}'].concat(${JSON.stringify(rulesAst)});
if(module.hot) {
module.hot.dispose(() => {
console.log('disposeHandlers');
if(!global['${GLOBAL_DISPOSE_STYLE_NAME}']) {
global['${GLOBAL_DISPOSE_STYLE_NAME}'] = [];
}
global['${GLOBAL_DISPOSE_STYLE_NAME}'] = global['${GLOBAL_DISPOSE_STYLE_NAME}'].concat('${contentHash}');
})
}
})()`;
return `module.exports=${code}`;
}
export default hippyVueCSSLoader;