cristovao-trevisan / svelte-icon

SVG [icon] string styler for svelte
https://cristovao-trevisan.github.io/svelte-icon/
MIT License
30 stars 6 forks source link

Does not work with Sapper #2

Closed kwiat1990 closed 3 years ago

kwiat1990 commented 3 years ago

Hi,

I have followed the docs and as soon as I want to use the Icon component in my Sapper App it doesn't work and all I can see is only this error:

export { default } from './Icon.svelte'
^^^^^^

SyntaxError: Unexpected token 'export'
    at wrapSafe (internal/modules/cjs/loader.js:1117:16)
    at Module._compile (internal/modules/cjs/loader.js:1165:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1221:10)
    at Module.load (internal/modules/cjs/loader.js:1050:32)
    at Function.Module._load (internal/modules/cjs/loader.js:938:14)
    at Module.require (internal/modules/cjs/loader.js:1090:19)
    at require (internal/modules/cjs/helpers.js:75:18)
    at Object.<anonymous> (/home/mateusz.kwiatkowski/Playground/sapper-demo/__sapper__/dev/server/server.js:11:1)
    at Module._compile (internal/modules/cjs/loader.js:1201:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1221:10)

Usage:

<script>
  import Icon from "svelte-icon";
  import arrow from "@/assets/icons/arrow-up.svg";
</script>

<Icon data={arrow} />

Rollup config:

...
string({
  include: "src/assets/icons/*.svg",
}),
...
cristovao-trevisan commented 3 years ago

Hello, sorry for the late response. I missed the notification.

Can you provide your entire rollup.config.js? It seems your config is not resolving correctly the file inside node_modules

But it works using Sapper (I'm using it in a project currently). If you want this as soon as possible, just copy the Icon.svelte component to your application

kwiat1990 commented 3 years ago

@cristovao-trevisan the rollup.config.js is below.

What I've noticed is the fact that with the string loader my SVGs get encoded to base64 data URL, so I end up with something like this: data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDo etc.

import alias from "@rollup/plugin-alias";
import babel from "@rollup/plugin-babel";
import commonjs from "@rollup/plugin-commonjs";
import resolve from "@rollup/plugin-node-resolve";
import replace from "@rollup/plugin-replace";
import url from "@rollup/plugin-url";
import path from "path";
import { string } from "rollup-plugin-string";
import svelte from "rollup-plugin-svelte";
import svgo from "rollup-plugin-svgo";
import { terser } from "rollup-plugin-terser";
import config from "sapper/config/rollup.js";
import pkg from "./package.json";
import { preprocess } from "./svelte.config";

const mode = process.env.NODE_ENV;
const dev = mode === "development";
const legacy = !!process.env.SAPPER_LEGACY_BUILD;

const onwarn = (warning, onwarn) =>
  (warning.code === "MISSING_EXPORT" && /'preload'/.test(warning.message)) ||
  (warning.code === "CIRCULAR_DEPENDENCY" &&
    /[/\\]@sapper[/\\]/.test(warning.message)) ||
  onwarn(warning);

export default {
  client: {
    input: config.client.input(),
    output: config.client.output(),
    plugins: [
      alias({
        entries: [{ find: "@", replacement: __dirname + "/src" }],
      }),
      replace({
        "process.browser": true,
        "process.env.NODE_ENV": JSON.stringify(mode),
      }),

      svelte({
        compilerOptions: {
          dev,
          hydratable: true,
        },
        preprocess,
      }),
      url({
        sourceDir: path.resolve(__dirname, "src/node_modules/images"),
        publicPath: "/client/",
      }),
      resolve({
        browser: true,
        dedupe: ["svelte"],
      }),
      string({
        include: "src/assets/icons/*.svg",
      }),
      // svgo({
      //   plugins: [
      //     { removeNonInheritableGroupAttrs: true },
      //     { collapseGroups: true },
      //     { convertColors: { currentColor: true } },
      //   ],
      // }),
      commonjs(),

      legacy &&
        babel({
          extensions: [".js", ".mjs", ".html", ".svelte"],
          babelHelpers: "runtime",
          exclude: ["node_modules/@babel/**"],
          presets: [
            [
              "@babel/preset-env",
              {
                targets: "> 0.25%, not dead",
              },
            ],
          ],
          plugins: [
            "@babel/plugin-syntax-dynamic-import",
            [
              "@babel/plugin-transform-runtime",
              {
                useESModules: true,
              },
            ],
          ],
        }),

      !dev &&
        terser({
          module: true,
        }),
    ],

    preserveEntrySignatures: false,
    onwarn,
  },

  server: {
    input: config.server.input(),
    output: config.server.output(),
    plugins: [
      alias({
        entries: [{ find: "@", replacement: __dirname + "/src" }],
      }),
      replace({
        "process.browser": false,
        "process.env.NODE_ENV": JSON.stringify(mode),
      }),

      svelte({
        compilerOptions: {
          dev,
          generate: "ssr",
          hydratable: true,
        },
        emitCss: false,
        preprocess,
      }),
      url({
        sourceDir: path.resolve(__dirname, "src/node_modules/images"),
        publicPath: "/client/",
        emitFiles: false, // already emitted by client build
      }),
      resolve({
        dedupe: ["svelte"],
      }),
      // string({
      //   include: "src/assets/icons/*.svg",
      // }),
      // svgo({
      //   plugins: [
      //     { removeNonInheritableGroupAttrs: true },
      //     { collapseGroups: true },
      //     { convertColors: { currentColor: true } },
      //   ],
      // }),
      commonjs(),
    ],
    external: Object.keys(pkg.dependencies).concat(
      require("module").builtinModules
    ),

    preserveEntrySignatures: "strict",
    onwarn,
  },

  serviceworker: {
    input: config.serviceworker.input(),
    output: config.serviceworker.output(),
    plugins: [
      resolve(),
      replace({
        "process.browser": true,
        "process.env.NODE_ENV": JSON.stringify(mode),
      }),
      commonjs(),
      !dev && terser(),
    ],

    preserveEntrySignatures: false,
    onwarn,
  },
};
cristovao-trevisan commented 3 years ago

I've found the problem!! Sapper is using the url plugin, which is also processing your images, so you need to disable it by using the following config:

      url({
        exclude: 'src/img/**/*.svg', // <- ignore files being processed by rollup-plugin-string
    sourceDir: path.resolve(__dirname, 'src/node_modules/images'),
        \\...

Notice you need to add this to both client and server.

Here is the complete configuration I've tested with:

rollup.config.js ```js import path from 'path'; import resolve from '@rollup/plugin-node-resolve'; import replace from '@rollup/plugin-replace'; import commonjs from '@rollup/plugin-commonjs'; import url from '@rollup/plugin-url'; import { string } from 'rollup-plugin-string'; import svelte from 'rollup-plugin-svelte'; import babel from '@rollup/plugin-babel'; import { terser } from 'rollup-plugin-terser'; import config from 'sapper/config/rollup.js'; import pkg from './package.json'; const mode = process.env.NODE_ENV; const dev = mode === 'development'; const legacy = !!process.env.SAPPER_LEGACY_BUILD; const onwarn = (warning, onwarn) => (warning.code === 'MISSING_EXPORT' && /'preload'/.test(warning.message)) || (warning.code === 'CIRCULAR_DEPENDENCY' && /[/\\]@sapper[/\\]/.test(warning.message)) || onwarn(warning); export default { client: { input: config.client.input(), output: config.client.output(), plugins: [ replace({ preventAssignment: true, values:{ 'process.browser': true, 'process.env.NODE_ENV': JSON.stringify(mode) }, }), svelte({ compilerOptions: { dev, hydratable: true } }), url({ exclude: 'src/img/**/*.svg', sourceDir: path.resolve(__dirname, 'src/node_modules/images'), publicPath: '/client/' }), string({ include: 'src/img/**/*.svg', }), resolve({ browser: true, dedupe: ['svelte'] }), commonjs(), legacy && babel({ extensions: ['.js', '.mjs', '.html', '.svelte'], babelHelpers: 'runtime', exclude: ['node_modules/@babel/**'], presets: [ ['@babel/preset-env', { targets: '> 0.25%, not dead' }] ], plugins: [ '@babel/plugin-syntax-dynamic-import', ['@babel/plugin-transform-runtime', { useESModules: true }] ] }), !dev && terser({ module: true }) ], preserveEntrySignatures: false, onwarn, }, server: { input: config.server.input(), output: config.server.output(), plugins: [ replace({ preventAssignment: true, values:{ 'process.browser': true, 'process.env.NODE_ENV': JSON.stringify(mode) }, }), svelte({ compilerOptions: { dev, generate: 'ssr', hydratable: true }, emitCss: false }), url({ exclude: 'src/img/**/*.svg', sourceDir: path.resolve(__dirname, 'src/node_modules/images'), publicPath: '/client/', emitFiles: false // already emitted by client build }), string({ include: 'src/img/**/*.svg', }), resolve({ dedupe: ['svelte'] }), commonjs() ], external: Object.keys(pkg.dependencies).concat(require('module').builtinModules), preserveEntrySignatures: 'strict', onwarn, }, serviceworker: { input: config.serviceworker.input(), output: config.serviceworker.output(), plugins: [ resolve(), replace({ preventAssignment: true, values:{ 'process.browser': true, 'process.env.NODE_ENV': JSON.stringify(mode) }, }), commonjs(), !dev && terser() ], preserveEntrySignatures: false, onwarn, } }; ```
cristovao-trevisan commented 3 years ago

Just added a note about it on README

kwiat1990 commented 3 years ago

@cristovao-trevisan wow, thanks for all your help! I didn't tested it yet but I'm sure it must work now since it does for you.

To be honest I would not even think of such solution and thanks to it I have discovered one more thing (how to display inline image placeholder), which should be of a great help for me in my project.

cristovao-trevisan commented 3 years ago

If it does not work feel free to re-open the issue :)

kwiat1990 commented 3 years ago

I gave it a shot and it doesn't seem to be a working solution for me. I end up with the very same error message regarding default export in Icon package.

In my projects all icons are stored under src/assets/icons directory and all images under static/images, so basically the path, which takes url plugin should affect only Sapper's "demo" images, which are places inside src/node_modules/images directory.

My rollup.config.js after changes looks so:

import alias from "@rollup/plugin-alias";
import babel from "@rollup/plugin-babel";
import commonjs from "@rollup/plugin-commonjs";
import resolve from "@rollup/plugin-node-resolve";
import replace from "@rollup/plugin-replace";
import url from "@rollup/plugin-url";
import path from "path";
import { string } from "rollup-plugin-string";
import svelte from "rollup-plugin-svelte";
import svgo from "rollup-plugin-svgo";
import { terser } from "rollup-plugin-terser";
import config from "sapper/config/rollup.js";
import pkg from "./package.json";
import { preprocess } from "./svelte.config";

const mode = process.env.NODE_ENV;
const dev = mode === "development";
const legacy = !!process.env.SAPPER_LEGACY_BUILD;

const onwarn = (warning, onwarn) =>
  (warning.code === "MISSING_EXPORT" && /'preload'/.test(warning.message)) ||
  (warning.code === "CIRCULAR_DEPENDENCY" &&
    /[/\\]@sapper[/\\]/.test(warning.message)) ||
  onwarn(warning);

export default {
  client: {
    input: config.client.input(),
    output: config.client.output(),
    plugins: [
      alias({
        entries: [{ find: "@", replacement: __dirname + "/src" }],
      }),
      replace({
        "process.browser": true,
        "process.env.NODE_ENV": JSON.stringify(mode),
      }),

      svelte({
        compilerOptions: {
          dev,
          hydratable: true,
        },
        preprocess,
      }),
      url({
        exclude: "src/assets/icons/*.svg",
        sourceDir: path.resolve(__dirname, "src/node_modules/images"),
        publicPath: "/client/",
      }),
      resolve({
        browser: true,
        dedupe: ["svelte"],
      }),
      string({
        include: "src/assets/icons/*.svg",
      }),
      // svgo({
      //   plugins: [
      //     { removeNonInheritableGroupAttrs: true },
      //     { collapseGroups: true },
      //     { convertColors: { currentColor: true } },
      //   ],
      // }),
      commonjs(),

      legacy &&
        babel({
          extensions: [".js", ".mjs", ".html", ".svelte"],
          babelHelpers: "runtime",
          exclude: ["node_modules/@babel/**"],
          presets: [
            [
              "@babel/preset-env",
              {
                targets: "> 0.25%, not dead",
              },
            ],
          ],
          plugins: [
            "@babel/plugin-syntax-dynamic-import",
            [
              "@babel/plugin-transform-runtime",
              {
                useESModules: true,
              },
            ],
          ],
        }),

      !dev &&
        terser({
          module: true,
        }),
    ],

    preserveEntrySignatures: false,
    onwarn,
  },

  server: {
    input: config.server.input(),
    output: config.server.output(),
    plugins: [
      alias({
        entries: [{ find: "@", replacement: __dirname + "/src" }],
      }),
      replace({
        "process.browser": false,
        "process.env.NODE_ENV": JSON.stringify(mode),
      }),

      svelte({
        compilerOptions: {
          dev,
          generate: "ssr",
          hydratable: true,
        },
        emitCss: false,
        preprocess,
      }),
      url({
        exclude: "src/assets/icons/*.svg",
        sourceDir: path.resolve(__dirname, "src/node_modules/images"),
        publicPath: "/client/",
        emitFiles: false, // already emitted by client build
      }),
      resolve({
        dedupe: ["svelte"],
      }),
      string({
        include: "src/assets/icons/*.svg",
      }),
      // svgo({
      //   plugins: [
      //     { removeNonInheritableGroupAttrs: true },
      //     { collapseGroups: true },
      //     { convertColors: { currentColor: true } },
      //   ],
      // }),
      commonjs(),
    ],
    external: Object.keys(pkg.dependencies).concat(
      require("module").builtinModules
    ),

    preserveEntrySignatures: "strict",
    onwarn,
  },

  serviceworker: {
    input: config.serviceworker.input(),
    output: config.serviceworker.output(),
    plugins: [
      resolve(),
      replace({
        "process.browser": true,
        "process.env.NODE_ENV": JSON.stringify(mode),
      }),
      commonjs(),
      !dev && terser(),
    ],

    preserveEntrySignatures: false,
    onwarn,
  },
};
cristovao-trevisan commented 3 years ago

I made it work with the latest sapper template (npx degit "sveltejs/sapper-template#rollup" my-app); Is your code open source? Or maybe your following another template? Can you provide the template your using or the repo so I can test it? Seems to be some miss configuration in your rollup, but it's hard to fix if I can't reproduce

kwiat1990 commented 3 years ago

@cristovao-trevisan here is a demo repo, where I face the very same problem: https://github.com/kwiat1990/sapper-icon

cristovao-trevisan commented 3 years ago

Hi, and sorry for taking so long, I had a rough week working 12h+ a day.

Just found the fix !!!!!

The thing is: sapper expects you to install the dependencies you use to build as "devDependencies" (npm install --save-dev ...), so it will not process node_modules that are not dev-deps ("dependencies" and "peerDependencies"). You just need to move svelte-icon to be a dev-dep (npm install --save-dev svelte-icon), and DONE!

Thank you for providing the demo repo

cristovao-trevisan commented 3 years ago

I also found that my readme had the wrong install command (--dev instead of --save-dev), but it's now fixed

kwiat1990 commented 3 years ago

I really appreciate your effort, thanks a lot for all that debbuging! I think it has to work now but nonetheless as soon as I will have opportunity to test it, I'll leave a feedback.

kwiat1990 commented 3 years ago

So as dev dependency it does work without any problems. Thanks again for the analyze.