mrsum / webpack-svgstore-plugin

Simple svg-sprite creating with webpack
https://www.npmjs.com/package/webpack-svgstore-plugin
200 stars 90 forks source link

How to include sprite in the html? #45

Closed timofei-iatsenko closed 8 years ago

timofei-iatsenko commented 8 years ago

I didn't see in docs. We have to include the sprite before use icons via xlink:href

So how do you do it?

When i use gulp, i used to use svg-inject plugin to achieve that, i inject it directly into the bottom of my html file.

mrsum commented 8 years ago

Did you see div block which contains svg onto your page?

timofei-iatsenko commented 8 years ago

nope, how and where it should appear?

mrsum commented 8 years ago

Can you'll paste here your webpack.config?

timofei-iatsenko commented 8 years ago

It's based on https://github.com/AngularClass/angular2-webpack-starter

// @AngularClass

/*
 * Helper: root(), and rootDir() are defined at the bottom
 */
var path = require('path');
// Webpack Plugins
var ProvidePlugin = require('webpack/lib/ProvidePlugin');
var DefinePlugin  = require('webpack/lib/DefinePlugin');
var CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
var CopyWebpackPlugin  = require('copy-webpack-plugin');
var HtmlWebpackPlugin  = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var autoprefixer = require('autoprefixer');
var SvgStore = require('webpack-svgstore-plugin');

var ENV = process.env.ENV = process.env.NODE_ENV = 'development';

var metadata = {
  title: 'SmartHome ClimateControl App',
  baseUrl: '/',
  host: '192.168.1.135',
  port: 3000,
  ENV: ENV
};
/*
 * Config
 */
module.exports = {
  // static data for index.html
  metadata: metadata,
  // for faster builds use 'eval'
  devtool: 'source-map',
  debug: true,

  entry: {
    'vendor': './src/vendor.ts',
    'main': './src/main.ts' // our angular app
  },

  // Config for our build files
  output: {
    path: root('dist'),
    filename: '[name].bundle.js',
    sourceMapFilename: '[name].map',
    chunkFilename: '[id].chunk.js'
  },

  resolve: {
    // ensure loader extensions match
    extensions: ['','.ts','.js','.json','.css','.html']
  },

  module: {
    preLoaders: [{ test: /\.ts$/, loader: 'tslint-loader', exclude: [/node_modules/] }],
    loaders: [
      // Support for .ts files.
      {
        test: /\.ts$/,
        loader: 'ts-loader',
        query: {
          'ignoreDiagnostics': [
            2403, // 2403 -> Subsequent variable declarations
            2300, // 2300 -> Duplicate identifier
            2374, // 2374 -> Duplicate number index signature
            2375  // 2375 -> Duplicate string index signature
          ]
        },
        exclude: [ /\.(spec|e2e)\.ts$/, /node_modules\/(?!(ng2-.+))/ ]
      },

      // Support for *.json files.
      { test: /\.json$/,  loader: 'json-loader' },

      // Support for CSS as raw text
      { test: /\.css$/,   loader: 'raw-loader' },

      // support for .html as raw text
      { test: /\.html$/,  loader: 'raw-loader' },

      { test: /\.jade$/,  loader: 'raw-loader!jade-html-loader' },

      // if you add a loader include the resolve file extension above
      {
        test: /\.scss$/,
        loader: ExtractTextPlugin.extract('style-loader', 'css-loader?sourceMap!postcss-loader!sass-loader?sourceMap'),
      },
    ],
  },
  postcss: function () {
    return [autoprefixer];
  },
  jadeLoader: {
    locals: {
      bem: require('bem-jade')({
        prefix: '',
        element: '__',
        modifier: '--',
        default_tag: 'div',
      })
    },
    basedir: __dirname + '/src'
  },
  plugins: [
    new ExtractTextPlugin('styles.css'),
    new CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.bundle.js', minChunks: Infinity }),
    // static assets
    new CopyWebpackPlugin([ { from: 'src/assets', to: 'assets' } ]),
    // generating html
    new HtmlWebpackPlugin({ template: 'src/index.html', inject: false }),
    // replace
    new DefinePlugin({
      'process.env': {
        'ENV': JSON.stringify(metadata.ENV),
        'NODE_ENV': JSON.stringify(metadata.ENV)
      }
    }),
    new SvgStore(path.join(__dirname + '/src', 'icons', '**/*.svg'), path.join('assets', 'svg'), {
      name: '[hash].sprite.svg',
      prefix: 'myprefix-',
      svgoOptions: {
        // options for svgo, optional
      }
    })
  ],

  // Other module loader config
  tslint: {
    emitErrors: false,
    failOnHint: false
  },
  // our Webpack Development Server config
  devServer: {
    port: metadata.port,
    host: metadata.host,
    historyApiFallback: true,
    watchOptions: { aggregateTimeout: 300, poll: 1000 }
  },
  // we need this due to problems with es6-shim
  node: {global: 'window', progress: false, crypto: 'empty', module: false, clearImmediate: false, setImmediate: false}
};

// Helper functions

function root(args) {
  args = Array.prototype.slice.call(arguments, 0);
  return path.join.apply(path, [__dirname].concat(args));
}

function rootNode(args) {
  args = Array.prototype.slice.call(arguments, 0);
  return root.apply(path, ['node_modules'].concat(args));
}
mrsum commented 8 years ago

Yes, i know how can help you :)

new SvgStore(path.join(__dirname + '/src', 'icons', '**/*.svg'), path.join('assets', 'svg'), {
      name: '[hash].sprite.svg',
      prefix: 'myprefix-',
      chunk: 'main', // you miss this line :)
      svgoOptions: {
        // options for svgo, optional
      }
 })
timofei-iatsenko commented 8 years ago

Thanx, it isn't enough clear in readme. So i've corrected config, but now i have another error:

Cannot GET /assets/svg/6437c2219c5c2f766d7dc4c3f5599d30.sprite.svg

I use webpack dev server and got this error. When i build via webpack command, i see this file on this destination.

mrsum commented 8 years ago

Please check your publicPath value into config. Right now sprite has been builded and served from dev-server, but publicPath is incorrect

timofei-iatsenko commented 8 years ago

I finally figured out. Public path was correct, because all other my assets work fine. Problem was in plugin config:

new SvgStore(path.join(__dirname + '/src', 'icons', '**/*.svg'), path.join('assets', 'svg'), { ...})

// out path was incorrect. My build stored in the `dst` folder, so correct path is:
new SvgStore(path.join(__dirname + '/src', 'icons', '**/*.svg'), path.join('dst', 'assets', 'svg'), { ...})

I was confused, because when i build with webpack svg sprite was storred in correct place.

@mrsum Big thanks for support!

mrsum commented 8 years ago

@thekip Welcome!

timofei-iatsenko commented 8 years ago

Actually it is not solved. Solution from previously comment works only because before start dev-server i build with old config and had a file in correct location. Сoincidence..

Issue still here. I try to describe it below:

i have next file structure: src/ dst/

Icons stored in the src/icons, output configured to dst/svg/sprite.svg

Web pack dev server configured for dst/ folder (output.path property), this is content root.

examples: localhost:3000/index.html -> dst/index.html localhost:3000/assets/logo.png -> dst/assets/logo.png

It works fine. No publicPath needed.

The problem is svg sprite served from incorrect path when using dev server. It ignores output.path property and serves files from project root.

localhost:3000/assets/sprite.svg -> 404

BUT

localhost:3000/dist/assets/sprite.svg returns a file.

This behavoiur is incorrect, my content root is dst/, so all path have to be resolved relatively to this.

So if i add baseUrl: 'dst' to plugin config, dev server will work (it just prepend url with path), but it isn't a solution because build without dev-server will be incorrect.

mrsum commented 8 years ago

@thekip I think its depends of webpack.config environment. Cause nobody know how config should looking. But test example into this package works fine.

timofei-iatsenko commented 8 years ago

@mrsum what? I don't undersand that, please explain. Or provide you config and file structure, my be i just change my environment.

mrsum commented 8 years ago

Look up to this file https://github.com/mrsum/webpack-svgstore-plugin/blob/develop/platform/global.js

timofei-iatsenko commented 8 years ago

after 2 hours of debugging i found that problem in slashes. I don't why all other users don't have this problems, but i have (i work on windows).

if i replace filePath to string 'svg/spire.svg' in that code:

 compilation.assets[filePath] = {
        size: function() { return Buffer.byteLength(fileContent, 'utf8'); },
        source: function() { return new Buffer(fileContent); }
      };

Then i can get this file from dev server correctly:

http://localhost:3000/svg/sprite.svg -> OK

Initially in filePath we have backslashes: 'svg\spire.svg' and it doesn't work

http://localhost:3000/svg/sprite.svg -> 404

The most interesting thing that is other plugins as CopyWebpackPlugin work the same and use backslashes it paths, and it also doesn't work.

I don't believe that anybody don't test that plaugins on widows!

So my solution is sprite name without any slashes. It's simple and it's work.