export default function styles(options = {}) { const filter = createFilter(options.include || ['**/*.css', '**/*.scss'], options.exclude); const { output, includePaths = [], includeAlways = [], generateScopedName: userGenerateScopedName, } = options; const compiledStyles = []; const tokensByFile = {}; const generateScopedName = typeof userGenerateScopedName === 'function' ? userGenerateScopedName : genericNames(userGenerateScopedName || '[path]___[name]___[local]___[hash:base64:5]', { context: process.cwd(), }); const includeAlwaysSource = includeAlways .map((resource) => readFileSync(resource, 'utf8')) .join('\n'); const processor = postcss([ cssModulesValues, cssModulesLocalByDefault, cssModulesExtractImports, cssModulesScope({generateScopedName}), new Parser({ fetch(to, from) { const fromDirectoryPath = dirname(from); const toPath = resolvePath(fromDirectoryPath, to); const source = readFileSync(toPath, 'utf8'); return getPostCSSOutput(processor, source, toPath); }, }), postcssShopify(), ]); return { name: 'shopify-styles', transform(source, id) { if (!filter(id)) { return null; } return new Promise((resolve, reject) => { render({ data: `${includeAlwaysSource}\n${source}`, includePaths: includePaths.concat(dirname(id)), }, (error, result) => { if (error) { reject(error); return; } const sassOutput = result.css.toString(); resolve(getPostCSSOutput(processor, sassOutput, id)); }); }) .then(({css, tokens}) => { tokensByFile[id] = tokens; const properties = Object .keys(tokens) .map((className) => ` ${JSON.stringify(className)}: ${JSON.stringify(tokens[className])},`) .join('\n'); compiledStyles.push(css); return `export default {\n${properties}\n};`; }); }, ongenerate(generateOptions) { if (output === false) { return null; } const jsDestination = generateOptions.dest || 'bundle.js'; let cssDestination = typeof output === 'string' ? output : null; if (cssDestination == null) { cssDestination = jsDestination.endsWith('.js') ? `${jsDestination.slice(0, -3)}.css` : `${jsDestination}.css`; } const minifiedCSSDestination = `${cssDestination.slice(0, -4)}.min.css`; const tokensDestination = `${cssDestination.slice(0, -4)}.tokens.json`; const css = compiledStyles.join('\n\n'); ensureDirSync(dirname(cssDestination)); return Promise.all([ write(cssDestination, css), write(tokensDestination, JSON.stringify(tokensByFile, null, 2)), cssnano.process(css).then((result) => write(minifiedCSSDestination, result.css)), ]); }, }; }
module.exports = function setupHook({ devMode, extensions = '.css', ignore, preprocessCss = identity, processCss, processorOpts, camelCase, append = [], prepend = [], createImportedName, generateScopedName, mode, use, rootDir: context = process.cwd(), }) { debugSetup(arguments[0]); validate(arguments[0]); const tokensByFile = {}; // debug option is preferred NODE_ENV === 'development' const debugMode = typeof devMode !== 'undefined' ? devMode : process.env.NODE_ENV === 'development'; let scopedName; if (generateScopedName) { scopedName = typeof generateScopedName !== 'function' ? genericNames(generateScopedName, {context}) // for example '[name]__[local]___[hash:base64:5]' : generateScopedName; } else { // small fallback scopedName = (local, filename) => { return Scope.generateScopedName(local, relative(context, filename)); }; } const plugins = (use || [ ...prepend, Values, mode ? new LocalByDefault({mode}) : LocalByDefault, createImportedName ? new ExtractImports({createImportedName}) : ExtractImports, new Scope({generateScopedName: scopedName}), ...append, ]).concat(new Parser({fetch})); // no pushing in order to avoid the possible mutations; // https://github.com/postcss/postcss#options const runner = postcss(plugins); /** * @todo think about replacing sequential fetch function calls with requires calls * @param {string} _to * @param {string} from * @return {object} */ function fetch(_to, from) { // getting absolute path to the processing file const filename = /[^\\/?%*:|"<>\.]/i.test(_to[0]) ? require.resolve(_to) : resolve(dirname(from), _to); // checking cache let tokens = tokensByFile[filename]; if (tokens) { debugFetch(`${filename} → cache`); debugFetch(tokens); return tokens; } const source = preprocessCss(readFileSync(filename, 'utf8'), filename); // https://github.com/postcss/postcss/blob/master/docs/api.md#processorprocesscss-opts const lazyResult = runner.process(source, assign({}, processorOpts, {from: filename})); // https://github.com/postcss/postcss/blob/master/docs/api.md#lazywarnings lazyResult.warnings().forEach(message => console.warn(message.text)); tokens = lazyResult.root.tokens; if (camelCase) { tokens = assign(mapKeys(tokens, (value, key) => camelCaseFunc(key)), tokens); } if (!debugMode) { // updating cache tokensByFile[filename] = tokens; } else { // clearing cache in development mode delete require.cache[filename]; } if (processCss) { processCss(lazyResult.css, filename); } debugFetch(`${filename} → fs`); debugFetch(tokens); return tokens; }; const exts = toArray(extensions); const isException = buildExceptionChecker(ignore); // @todo add possibility to specify particular config for each extension exts.forEach(extension => attachHook(filename => fetch(filename, filename), extension, isException)); };
var result = pattern; for (var key in interpolations) { if (interpolations.hasOwnProperty(key)) { var part = `[${key}]`; if (result.includes(part)) { result = result.replace(part, interpolations[key](params)); } } } return result; }, getAssetPath (cwd, filepath) { var relativepath = cwd ? path.relative(cwd, filepath) : filepath; return relativepath.startsWith('/') ? relativepath.slice(1) : relativepath; }, generateScopedName (cwd, pattern, interpolations, name, filepath, css) { var assetPath = this.getAssetPath(cwd, filepath); var genericPattern = this.getGenericPattern(pattern, interpolations, { name, filepath: assetPath, css }); return genericNames(genericPattern)(name, assetPath); }, getScopedNameGenerator (customPattern, componentResolver, cwd) { var patternInterpolations = this.getPatternInterpolations(componentResolver, this.getFilePrefix); return this.generateScopedName.bind(this, cwd, customPattern, patternInterpolations); } };
css: css.toResult().toString().replace(/\n/g, ''), name: name.replace('.', ''), args: args.join(',') }); }, angular2(name, template, css, args) { return Mustache.render(fs.readFileSync(path.join(__dirname, './angular2.template'), 'utf8'), { template: template.join('\n'), css: css.toResult().toString(), name: name.replace('.', '') }); } }; const generate = genericNames('[name]__[local]__[hash:base64:5]', { context: process.cwd() }); const parse = (source, type = 'react') => { const tree = postcss.parse(source); const output = []; const css = postcss.root(); const args = []; const getStyles = (rule) => { const selector = generate(rule.selector, 'Source'); const nextRule = postcss.rule({ selector: `.${selector}` }); rule.each((node) => {