示例#1
0
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)),
      ]);
    },
  };
}
示例#2
0
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));
};
示例#3
0
    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);
  }
};
示例#4
0
      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) => {