zoukankan      html  css  js  c++  java
  • Webpack 常见静态资源处理

    Webpack 常见静态资源处理 - 模块加载器(Loaders)+ExtractTextPlugin插件

    webpack系列目录

    基于webpack搭建纯静态页面型前端工程解决方案模板, 最终形态源码见github: https://github.com/ifengkou/webpack-template

    正文

    Webpack将所有静态资源都认为是模块,比如JavaScript,CSS,LESS,TypeScript,JSX,CoffeeScript,图片等等,从而可以对其进行统一管理。为此Webpack引入了加载器的概念,除了纯JavaScript之外,每一种资源都可以通过对应的加载器处理成模块。和大多数包管理器不一样的是,Webpack的加载器之间可以进行串联,一个加载器的输出可以成为另一个加载器的输入。比如LESS文件先通过less-load处理成css,然后再通过css-loader加载成css模块,最后由style-loader加载器对其做最后的处理,从而运行时可以通过style标签将其应用到最终的浏览器环境。

    一 常用loader

    安装css/sass/less loader加载器

    cnpm install file-loader css-loader style-loader sass-loader ejs-loader html-loader jsx-loader image-webpack-loader --save-dev
    

    webpack.config.js配置:

    module: {
        loaders: [
            {
                test: /.((woff2?|svg)(?v=[0-9].[0-9].[0-9]))|(woff2?|svg|jpe?g|png|gif|ico)$/,
                loaders: [
                    // 小于10KB的图片会自动转成dataUrl
                    'url?limit=10240&name=img/[hash:8].[name].[ext]',
                    'image?{bypassOnDebug:true, progressive:true,optimizationLevel:3,pngquant:{quality:"65-80",speed:4}}'
                ]
            },
            {
                test: /.((ttf|eot)(?v=[0-9].[0-9].[0-9]))|(ttf|eot)$/,
                loader: 'url?limit=10000&name=fonts/[hash:8].[name].[ext]'
            },
            {test: /.(tpl|ejs)$/, loader: 'ejs'},
            {test: /.css$/, loader: 'style-loader!css-loader'},
            { test: /.scss$/, loader: 'style!css!sass'}
        ]
    },
    

    index.html 新增两个div

    <div class="small-webpack"></div>
    <div class="webpack"></div>
    

    index.css 增加两个图片,同时将webpack.png(53kb) 和 small-webpack.png(9.8k)

    .webpack {
        background: url(../img/webpack.png) no-repeat center;
        height:500px;
    }
    .small-webpack {
        background: url(../img/small-webpack.png) no-repeat center;
        height:250px;
    }
    

    index.js 引入css

    require('../css/index.css');
    

    执行webpack指令

    $ webpack
    

    查看生成的目录结构

    其中并没有css文件,css被写入到了index.js中,index.js 部分截图

    总结:

    • 图片采用了url-loader加载,如果小于10kb,图片则被转化成 base64 格式的 dataUrl
    • css文件被打包进了js文件中

    css被打包进了js文件,如果接受不了,可以强制把css从js文件中独立出来。官方文档是以插件形式实现:文档docs点这插件的github点这

    二:extract-text-webpack-plugin 插件介绍

    Extract text from bundle into a file.从bundle中提取出特定的text到一个文件中。使用 extract-text-webpack-plugin就可以把css从js中独立抽离出来

    安装

    $ npm install extract-text-webpack-plugin --save-dev
    

    使用(css为例)

    var ExtractTextPlugin = require("extract-text-webpack-plugin");
    module.exports = {
        module: {
            loaders: [
                { test: /.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }
            ]
        },
        plugins: [
            new ExtractTextPlugin("styles.css")
        ]
    }
    

    它将从每一个用到了require("*.css")的entry chunks文件中抽离出css到单独的output文件

    API

    new ExtractTextPlugin([id: string], filename: string, [options])
    
    • id Unique ident for this plugin instance. (For advanded usage only, by default automatic generated)

    • filename the filename of the result file. May contain [name], [id] and [contenthash].

      • [name] the name of the chunk
      • [id] the number of the chunk
      • [contenthash] a hash of the content of the extracted file
    • options

      • allChunks extract from all additional chunks too (by default it extracts only from the initial chunk(s))
      • disable disables the plugin

      ExtractTextPlugin.extract([notExtractLoader], loader, [options])

    根据已有的loader,创建一个提取器(loader的再封装)

    • notExtractLoader (可选)当css没有被抽离时,加载器不应该使用(例如:当allChunks:false时,在一个additional 的chunk中)
    • loader 数组,用来转换css资源的加载器s
    • options
      • publicPath 重写该加载器(loader)的 publicPath 的设置

    多入口文件的extract的使用示例:

    let ExtractTextPlugin = require('extract-text-webpack-plugin');
    
    // multiple extract instances
    let extractCSS = new ExtractTextPlugin('stylesheets/[name].css');
    let extractLESS = new ExtractTextPlugin('stylesheets/[name].less');
    
    module.exports = {
      ...
      module: {
        loaders: [
          {test: /.scss$/i, loader: extractCSS.extract(['css','sass'])},
          {test: /.less$/i, loader: extractLESS.extract(['css','less'])},
          ...
        ]
      },
      plugins: [
        extractCSS,
        extractLESS
      ]
    };
    

    三:改造项目-抽离css

    安装插件到项目

    npm install extract-text-webpack-plugin --save-dev
    

    配置webpack.config.js,加入ExtractTextPlugin和相关处理:

    var webpack = require("webpack");
    var path = require("path");
    var srcDir = path.resolve(process.cwd(), 'src');
    var nodeModPath = path.resolve(__dirname, './node_modules');
    var pathMap = require('./src/pathmap.json');
    var glob = require('glob')
    var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
    var HtmlWebpackPlugin = require('html-webpack-plugin');
    var ExtractTextPlugin = require('extract-text-webpack-plugin');
    var entries = function () {
        var jsDir = path.resolve(srcDir, 'js')
        var entryFiles = glob.sync(jsDir + '/*.{js,jsx}')
        var map = {};
    
        for (var i = 0; i < entryFiles.length; i++) {
            var filePath = entryFiles[i];
            var filename = filePath.substring(filePath.lastIndexOf('/') + 1, filePath.lastIndexOf('.'));
            map[filename] = filePath;
        }
        return map;
    }
    
    var html_plugins = function () {
        var entryHtml = glob.sync(srcDir + '/*.html')
        var r = []
        var entriesFiles = entries()
        for (var i = 0; i < entryHtml.length; i++) {
            var filePath = entryHtml[i];
            var filename = filePath.substring(filePath.lastIndexOf('/') + 1, filePath.lastIndexOf('.'));
            var conf = {
                template: 'html!' + filePath,
                filename: filename + '.html'
            }
            //如果和入口js文件同名
            if (filename in entriesFiles) {
                conf.inject = 'body'
                conf.chunks = ['vendor', filename]
            }
            //跨页面引用,如pageA,pageB 共同引用了common-a-b.js,那么可以在这单独处理
            //if(pageA|pageB.test(filename)) conf.chunks.splice(1,0,'common-a-b')
            r.push(new HtmlWebpackPlugin(conf))
        }
        return r
    }
    var plugins = [];
    var extractCSS = new ExtractTextPlugin('css/[name].css?[contenthash]')
    var cssLoader = extractCSS.extract(['css'])
    var sassLoader = extractCSS.extract(['css', 'sass'])
    
    plugins.push(extractCSS);
    
    plugins.push(new CommonsChunkPlugin({
        name: 'vendor',
        minChunks: Infinity
    }));
    
    module.exports = {
        entry: Object.assign(entries(), {
            // 用到什么公共lib(例如jquery.js),就把它加进vendor去,目的是将公用库单独提取打包
            'vendor': ['jquery', 'avalon']
        }),
        output: {
            path: path.join(__dirname, "dist"),
            filename: "[name].js",
            chunkFilename: '[chunkhash:8].chunk.js',
            publicPath: "/"
        },
        module: {
            loaders: [
                {
                    test: /.((woff2?|svg)(?v=[0-9].[0-9].[0-9]))|(woff2?|svg|jpe?g|png|gif|ico)$/,
                    loaders: [
                        //小于10KB的图片会自动转成dataUrl,
                        'url?limit=10000&name=img/[hash:8].[name].[ext]',
                        'image?{bypassOnDebug:true, progressive:true,optimizationLevel:3,pngquant:{quality:"65-80",speed:4}}'
                    ]
                },
                {
                    test: /.((ttf|eot)(?v=[0-9].[0-9].[0-9]))|(ttf|eot)$/,
                    loader: 'url?limit=10000&name=fonts/[hash:8].[name].[ext]'
                },
                {test: /.(tpl|ejs)$/, loader: 'ejs'},
                {test: /.css$/, loader: cssLoader},
                {test: /.scss$/, loader: sassLoader}
            ]
        },
        resolve: {
            extensions: ['', '.js', '.css', '.scss', '.tpl', '.png', '.jpg'],
            root: [srcDir, nodeModPath],
            alias: pathMap,
            publicPath: '/'
        },
        plugins: plugins.concat(html_plugins())
    }
    

    其中,用ExtractTextPlugin 来抽离css

    var ExtractTextPlugin = require('extract-text-webpack-plugin');
    var extractCSS = new ExtractTextPlugin('css/[name].css?[contenthash]')
    var cssLoader = extractCSS.extract(['css'])
    var sassLoader = extractCSS.extract(['css', 'sass'])
    
    plugins.push(extractCSS);
    ......
    //conf - module - loaders
    {test: /.css$/, loader: cssLoader},
    {test: /.scss$/, loader: sassLoader}
    

    注意事项:

    • css中img的路径会出现问题,通过设置publicPath 解决,采用绝对路径

        output: {
            ......
            publicPath: "/"
        },
      

    运行:

    $ webpack
    

    期望

    • css单独抽离,打包成单独的css文件
    • html自动引用css文件
    • 小于10k的图片,转成base64 格式的 dataUrl
    • webpack.png 会被压缩,减少文件大小

    运行webpack后的项目的目录结构:

    生成的 dist/index.html 自动引用了 index.css 和相关的js,由于设置了publicPath 所以相应的链接都采用了绝对路径

    生成的 dist/index.css 小图片被转成了data:image形式:

    结果:

    • css单独打包到css目录
    • html自动注入了link 标签
    • small-webpack.png 小于10k,被打包进了index.css
    • webpack.png 由原来的50+k 被压缩成 10- k

    最后,运行 webpack-dev-server 看一下运行结果:

    总结

    Webpack将所有静态资源都认为是模块,而通过loader,几乎可以处理所有的静态资源,图片、css、sass之类的。并且通过一些插件如extract-text-webpack-plugin,可以将共用的css抽离出来

    下篇介绍改进webpack.config.js:

    • 区分开发环境和生产环境
    • 集成 gulp 实现自动构建打包部署
    • github 发布 前端自动化构建的项目模板
  • 相关阅读:
    IOC+AOP
    基础知识
    断点续传
    监听程序
    Action、View、ActionResult、ViewResult、ContentResult
    json的使用(JObect,JsonData,JArray)
    get/post 接口调用
    常见的加密和解密
    WebUtility(提供在处理 Web 请求时用于编码和解码 URL 的方法。)
    MyBatis动态SQL和缓存
  • 原文地址:https://www.cnblogs.com/sloong/p/5826818.html
Copyright © 2011-2022 走看看