Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Plugins] Combine build() and transform() #542

Closed
FredKSchott opened this issue Jun 24, 2020 · 2 comments
Closed

[Plugins] Combine build() and transform() #542

FredKSchott opened this issue Jun 24, 2020 · 2 comments
Assignees

Comments

@FredKSchott
Copy link
Owner

Right now these two plugin methods do essentially the same thing, but with the limitation that there can only ever be one build() per file type (and that build is able to transform file types).

We should combine these two into a single method (build(), transform(), or something else entirely) with the following qualities:

  • Always receives a file from memory, no longer responsible for loading from disk.
  • Gets a file object as it's input, instead of code/filename strings.
  • Can return a file of a new extension: foo.svg -> foo.js or foo.svg.js or foo-svg.js (entirely up to the plugin, although we can provide recommendations)
  • If filename changes, that file now matches plugins based on the new file extension.
  • Because we are passing object references, the "does this match" logic can live within the build function without impacting performance (every build function called on every file).
@chengcyber
Copy link
Contributor

chengcyber commented Jun 28, 2020

I found a way to support svg react component, which needs to extend the source code a little.

Adding the following code at https://github.com/pikapkg/snowpack/blob/master/src/commands/build-util.ts#L153 (neglecting a bit changes in function params syntax...)

for (const plugin of plugins) {
  const { wrapEsmProxyResponse } = plugin;
  if ("function" === typeof wrapEsmProxyResponse) {
    const customProxyResponse = wrapEsmProxyResponse({
      url,
      code,
      ext,
      hasHmr,
      config,
    });
    if (customProxyResponse) {
      return customProxyResponse;
    }
  }
}

which makes the plugin control proxy response.

thus, we can add a svg plugin maybe sth like this:

const { transformAsync, createConfigItem } = require('@babel/core');
const svgo = require('@svgr/plugin-svgo').default;
const jsx = require('@svgr/plugin-jsx').default;
const convert = require('@svgr/core').default;
const presetReact = require('@babel/preset-react');
const presetEnv = require('@babel/preset-env');
const pluginTransformReactConstantElements = require('@babel/plugin-transform-react-constant-elements');

const babelOptions = {
  babelrc: false,
  configFile: false,
  presets: [
    createConfigItem(presetReact, { type: 'preset' }),
    createConfigItem([presetEnv, { modules: false }], { type: 'preset' }),
  ],
  plugins: [createConfigItem(pluginTransformReactConstantElements)],
};

module.exports = function createPlugin(_, pluginOptions) {
  return {
    async transform({ urlPath, contents, isDev }) {
      // console.log(urlPath, contents, isDev);
      if (!urlPath.endsWith('.svg')) {
        return;
      }
      const code = await convert(contents, pluginOptions, {
        caller: {
          name: '@svgr/snowpack',
          defaultPlugins: [svgo, jsx],
        },
        urlPath,
      });

      const { code: result } = await transformAsync(code, babelOptions);

      return {
        result,
      };
    },

    wrapEsmProxyResponse({ url, code, ext, hasHmr, config: { buildOptions } }) {
      if (ext === '.svg') {
        return code;
      }
    },
  };
};

In this way, xxx.svg.proxy.js returns the react code for svg instead of export default '/path/to/svg.svg'

Hi @FredKSchott I have no idea whether this is the proper way to support svg react component. Any thoughts?

@FredKSchott
Copy link
Owner Author

Thanks @chengcyber! The work we just merged in #567 will allow for this via something like:

{
  input: [".svg"],
  output: [".js"],
  build() { /* run SVGR */ }
}

Or, if you only want to run this on a certain set of ".module.svg" files, you could use input: [".module.svg"].

This isn't quite supported yet, but the interface is now in place to support this in the near future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants