zoukankan      html  css  js  c++  java
  • 关于wepack的使用总结以及优化探讨

    一、前言

      不知不觉,webpack版本已经到4.0了。使用它也有很长一段时间了,回头看看,自己木有总结webpack方面的知识,现在有空起个头,主要是总结自己常用的配置和一下优化的探讨,以后有啥想法也直接写到这里来。

    二、开始

      webpack做啥的,怎么配置?和gulp、grunt等构件工具有什么区别?这些就跳过了,当初也是直接看官方文档的,摸爬滚打走过来的。可以参考:

      1、https://www.webpackjs.com/

      2、《入门 Webpack,看这篇就够了》

      3、《vue-cli中webpack配置》系列

          4 《webpack持久化缓存实践

         5 、 https://www.jianshu.com/p/b9bf995f3712

         6、《解决疑惑,让你明白》

    三、实际项目中解析

    3.1、本项目支持的功能

     1 对less编译
     2 支持es6语法支持
     3 编译.vue组件,并自动内联组件样式
     4 图片打包,包括对html内图片处理(利用html-loader和es6字符串模板),对小图片生成base64
     5 利用htmlWebpackPlugin动态拼接html 的公共部分和内容部分,引入相应css/js资源,并构建到指定目录, 对ejs模板支持
     6 对js内依赖的css分离并压缩
     7 对js引用的公共模块抽取分离成单独文件
     8 区分开发环境和生产环境
     9 js 压缩
    10 静态文件(css/js/img)hash版本支持
    11 清除目标文件目录
    12 eslint支持并实现自动修复部分问题
    13 vue接口请求axios支持
    14 热更新,自动编译并刷新浏览器

    3.2、目录结构

    |__ html
            |__ dist
                  |__ income.html
                  |__ index.html
            |__ src
                  |__ income
                    |__ income.ejs
                    |__ income.js
                  |__ index
                    |__ index.ejs
                    |__ index.js
                  |__ layouts
                    |__ footer.ejs
                    |__ header.ejs
                    |__ layout.ejs
                    |__ layout.js
                    |__ side-menu.e
                    |__ top-nav.ejs
      |__ dist
            |__ css
            |__ img
            |__ js
                  |__ income.js
                  |__ index.js
                  |__ manifest.js
                  |__ vendors.js
      |__ src
            |__ css
            |__ img
            |__ js
                  |__ component
                    |__ App.vue
                  |__ income.js
                  |__ index.js
                  |__ lib
                    |__ axios.min.js
                    |__ layer.js
                    |__ vue.js
                    |__ vue.min.js
      |__ mock
      |__ node_modules
      |__ webpack-config
            |__ .eslintrc.dev.js
            |__ .eslintrc.js
            |__ postcss.config.js
            |__ resolve.config.js
      |__ package.json
      |__ .babelrc
      |__ .eslintrc.js

    四、入口entry

    var entries = getEntry('./src/**/*.js') // 获得入口js文件
    entries.vendors = ['vue','axios']
    
    module.exports = {
         /* 输入文件 */
        entry: entries
    } 

    通常我们的项目中有大量的js入口文件,基本一个功能页面有一个js,这时我们的 entry 文件为一个对象格式

    entries 为:
    
    { 
      income: './src/js/income.js',
      index: './src/js/index.js',
      vendors: [ 'vue', 'axios' ] 
    }

    key 值为对应模块的别名,webpack会依次处理这些模块。

    vendors 为公共模块,这里我们把vue, axios设置为公共模块,供下面进行提取公共模块操作。

    之所以可以直接写vue, axios,是因为我们在 alias 里设置了别名:

    var path = require('path')
    
    module.exports = {
      // 模块别名的配置,为了使用方便,一般来说所有模块都是要配置一下别名的
      alias: {
        'vue': path.resolve(__dirname, '../src/js/lib/vue.min.js'),
        'axios': path.resolve(__dirname, '../src/js/lib/axios.min.js')
      }
    } 

    这里的 path.resolve 作用是把相对路径转为绝对路径,假设我项目建在d:/demo 目录下,

    _dirname: d:demo
    
    path.resolve(__dirname, '../src/js/lib/vue.min.js'): d:demosrcjslibvue.min.js

    getEntry() 为获取文件路径的自定义函数:

    /***** 获取文件列表:输出正确的js和html路径 *****/
    var glob = require('glob')
    
    function getEntry(globPath) {
        var entries = {}, basename
    
        glob.sync(globPath).forEach(function (entry) {
        //排出layouts内的公共文件
            if(entry.indexOf('layouts') == -1 && entry.indexOf('lib') == -1){
                basename = path.basename(entry, path.extname(entry))
                entries[basename] = entry
            }
        })
        return entries
    } 

    通常webpack的entry入口文件,是功能性页面的js,对于js库等文件不需要列入入口文件进行处理。所以这里对lib文件夹进行了排除。layouts文件夹为获取html路径时需要排除的文件路径。  

    五、output介绍

    module.exports = {
        output: {
            /* 输出目录,没有则新建 */
            path: path.resolve(__dirname, './dist'),
            /* 静态目录,可以直接从这里取文件 */
            publicPath: 'http://www.xxx.com/dist/',
            /* 文件名 */
            filename: 'js/[name].js?v=[chunkhash:8]'
        }
    }

     publicPath: 如果有这项,则html中的引用的js路径会加上publicPath,即 http://www.xxx.com/dist/js/[name].js?v=[chunkhash:8]

     filename: 这里可以自定义输出后的文件名,加上版本号

      [name] :输入模块的别名

      [chunkhash] : 模块的hash值,":8"代表保留8位hash值

      [hash] : 整个编译环境的hash值

           hash和chunkhash具体区别请看这里

    六、module介绍

    Webpack有一个不可不说的优点,它把所有的文件都都当做模块处理,JavaScript代码,CSS和fonts以及图片等等通过合适的loader都可以被处理。

    webpack利用各种loader来把不同格式的文件封装成模块加载到js内,比如css-loader, vue-loader,下面,只列举一部分。

    6.1、babel-loader

    es6语法目前很多浏览器不支持,我们需要将其转化为大部分浏览器支持的es5语法,这就需要babel-loader

    {
        test: /.js$/,
        loader: 'babel-loader',
        exclude: ['node_modules','./src/js/lib','./src/js/component']
    }
    

      

    6.2、 css有关的loader

    css-loader style-loader post-loader less-loader

    {   
        test: /.css$/, 
        use: ['style-loader', 'css-loader', 'postcss-loader']
    },
    {
        test: /.less$/,
        use: ExtractTextPlugin.extract(['css-loader','postcss-loader','less-loader'])
    }
    

      

    对于有多个loader时,webpack v2也废弃了v1的 " !" 连接,改为数组形式,且不能省略 " -loader " 以免造成名称混乱意思模糊,执行顺序为从右到左

    postcss-loader:为集合处理css各种问题的平台,其上面有各种插件来处理css,我们这里只用到了autoprefixer插件,后面插件部分会详解

    style-loader:可以将css以style内联方式嵌入到html页面

    css-loader:使你能够使用类似@import 和 url(...)的方法实现 require()的功能

    ExtractTextPlugin:提取css, 后面插件部分会进行详解

    6.3、css module:

    把JS的模块化思想带入CSS中来,通过CSS模块,所有的类名,动画名默认都只作用于当前模块。Webpack对CSS模块化提供了非常好的支持,只需要在CSS loader中进行简单配置即可,然后就可以直接把CSS的类名传递到组件的代码中,这样做有效避免了全局污染。具体的代码如下:

    module.exports = {
    
        ...
    
        module: {
            rules: [
                {
                    test: /(.jsx|.js)$/,
                    use: {
                        loader: "babel-loader"
                    },
                    exclude: /node_modules/
                },
                {
                    test: /.css$/,
                    use: [
                        {
                            loader: "style-loader"
                        }, {
                            loader: "css-loader",
                            options: {
                                modules: true, // 指定启用css modules
                                localIdentName: '[name]__[local]--[hash:base64:5]' // 指定css的类名格式
                            }
                        }
                    ]
                }
            ]
        }
    };

    6.4、文件图片loader

    {
        test: /.(png|jpg|gif)$/,
        loader: 'url-loader?limit=5120&name=img/[name].[ext]?v=[hash:8]'
    }

    6.5、字体loader

    {
      test: /.(ttf|ttc|eot|svg|woff(2))$/,
        loader: 'file-loader',
    	options:{
    	name: function(p){
    		let tem_path = p.split(/\fonts\/)[1];
    		tem_path = tem_path.replace(/\/g,'/');
    		return 'fonts/'+tem_path + '?v=[hash:8]';
    	}
         }
    }
    

        

    七、插件plugin

    插件是用来拓展Webpack功能的,它们会在整个构建过程中生效,执行相关的任务。
    Loaders和Plugins常常被弄混,但是他们其实是完全不同的东西,可以这么来说,loaders是在打包构建过程中用来处理源文件的(JSX,Scss,Less..),一次处理一个,插件并不直接操作单个文件,它直接对整个构建过程其作用。

    使用方法一般如下:

    module: {},
    plugins: [
            new ExtractTextPlugin('css/[name].css?v=[contenthash:6]'),
            new webpack.LoaderOptionsPlugin({
                options: {
                    eslint: require( './webpack-config/.eslintrc.js'),
                    postcss: require( './webpack-config/postcss.config.js')
                },
            })
        ]  

    webpack声明插件的方式可以像上面的写法也可以如下方式:

    module.exports.plugins = module.exports.plugins.concat([
            //压缩css代码
            new OptimizeCssAssetsPlugin({
                assetNameRegExp: /.css/g,
                cssProcessor: require('cssnano'),
                cssProcessorOptions: { discardComments: {removeAll: true } },
                canPrint: true
            }),
            //压缩JS代码
            new webpack.optimize.UglifyJsPlugin({
                output: {
                    comments: false, // 去掉注释内容
                }
            })
        ]) 

    7.1、extract-text-webpack-plugin 插件

    默认情况下,js依赖引入css,编译后,css被加在js中,如果我们想把css提取出一个单独的文件,可以使用这个插件,并可以对提取出的css进行自定义命名和加版本hash值

    new ExtractTextPlugin('css/[name].[contenthash:8].css'),

    7.2、optimize-css-assets-webpack-plugin 插件

    压缩css文件,对从js中提取出的css文件亦有效

    注意:此插件是在css被提取出来加了hash值后进行处理,如果css文件提出来后被命名为  css/[name].css?v=[contenthash:8] 形式,插件的使用如下

    new OptimizeCssAssetsPlugin({
                assetNameRegExp: /.css/g,  //注意不要写成 /.css$/g, 否则匹配不到css文件会导致压缩不成功
                cssProcessor: require('cssnano'),
                cssProcessorOptions: { discardComments: {removeAll: true } },
                canPrint: true
            })

    7.3、webpack-plugin 插件

    用于根据模板组合html各个部分,并插入对应引用的js,对前后端分离贡献颇多,功能强大会有专门的篇章来介绍

    7.4、CommonsChunkPlugin 插件

     提取js的公共模块,此插件为webpack自带的插件

    new webpack.optimize.CommonsChunkPlugin({
        names:  ['vendors', 'manifest'], // 公共模块的名称
        //filename: 'js/[name]-[chunkhash:6].js', // 公共模块的名称
        chunks: 'vendors',  // chunks是需要提取的模块
        minChunks: Infinity  //公共模块最小被引用的次数
    }) 

      通常我们的js可能会引入一些公共js文件,包括一些类库,如果都打包在一个js中,这个js会变得非常庞大,而且一旦我们功能页面的js有变化,会导致打包后的js版本号进行更新然后重新加载,这个代价有些大,所以我们会考虑把一些公共的js文件提取出一个单独的文件,这样在第一次访问的时候会加载,之后就可以缓存下来,减少服务器请求的压力并提高加载速度。  

    7.5 CleanWebpackPlugin插件

    保证买次编译之后目标文件中只保留最新的文件

    new CleanWebpackPlugin(['dist']) 

    ------------有时间再添加了------------

    八、一些优化探索

     

     

      

  • 相关阅读:
    关系数据库设计一般方法 范式及完整性
    left join, right join , inner join, join, union的意义
    mysql 事务类型表的用法
    Java中静态变量与非静态变量的区别
    JSP生命周期
    Java&Tomcat环境变量配置
    JSP两种声明变量的区别
    一个web页面的访问的过程
    Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure 解决
    IDEA:修改JAVA文件自动引入import.*包
  • 原文地址:https://www.cnblogs.com/leaf930814/p/9024749.html
Copyright © 2011-2022 走看看