• webpack


    什么是webpack

    webpack是一个模块打包器,包(bundle)就是一个js文件,它把一堆资源合并在一起,以便在同一个文件请求中发回给客户端,webpack还能处理一些浏览器不能直接运行的拓展语言,如Scss,typeScript等。webpack是基于配置型的构建工具,它把整个项目作为一个整体,通过一个给定的主文件(如index.js),从这个主文件开始找到项目所有的依赖文件,使用loaders处理它们,最终打包为一个或多个浏览器可识别的js文件。

     

    webpack和gulp的区别

    webpack:作为一个智能解析器,几乎可以处理任何一个第三方的库,无论是commonjs,amd还是普通的js文件,甚至加载依赖的时候可以动态表达式。webpack是一种预编译的解决方案,不需要在浏览器中加载解释器,而且不管是AMD/CMD/ES6风格的模块化,它都认识,并且能编译成浏览器认识的JS。webpack是一种模块化的解决方案,webpack在很多场景下可以替代gulp/grunt类的工具 
    gulp:在一个配置文件中,指明对某些文件进行类似编译、组合、压缩等任务的具体步骤,工具之后可以在自动替你完成这些任务。gulp是一个能够优化前端的开发流程的工具。

     

    使用webpack

    项目环境

    //全局安装
    npm install -g webpack
    //安装到项目里
    npm install --save-dev webpack

    如果项目中没有package.json这个文件,可以通过以下指令创建:

    npm init

    一个简单的配置文件

    webpack.config.js

    // 一个常见的`webpack`配置文件
    const webpack = require('webpack');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const ExtractTextPlugin = require('extract-text-webpack-plugin');
    
    module.exports = {
            entry: __dirname + "/app/main.js", //已多次提及的唯一入口文件
            output: {
                path: __dirname + "/build",  //打包后的文件存放的地方
                filename: "bundle-[hash].js"  //打包后输出文件的文件名
            },
            devtool: 'none',
            devServer: {
                contentBase: "./public", //本地服务器所加载的页面所在的目录
                historyApiFallback: true, //不跳转
                inline: true,
                hot: true
            },
            module: {
                rules: [{
                        test: /(.jsx|.js)$/,
                        use: {
                            loader: "babel-loader"
                        },
                        exclude: /node_modules/
                    }, {
                        test: /.css$/,
                        use: ExtractTextPlugin.extract({
                            fallback: "style-loader",
                            use: [{
                                loader: "css-loader",
                                options: {
                                    modules: true,
                                    localIdentName: '[name]__[local]--[hash:base64:5]'
                                }
                            }, {
                                loader: "postcss-loader"
                            }],
                        })
                    }
                }
            ]
        },
        plugins: [
            new webpack.BannerPlugin('版权所有,翻版必究'),
            new HtmlWebpackPlugin({
                template: __dirname + "/app/index.tmpl.html" //new 一个这个插件的实例,并传入相关的参数
            }),
            new webpack.optimize.OccurrenceOrderPlugin(),
            new webpack.optimize.UglifyJsPlugin(),
            new ExtractTextPlugin("style.css")
        ]
    };

    配置分析

    一 entry和output 
    entry用来定义入口文件,可以是字符串或数组或对象 
    1.字符串:

    module.exports = {
      entry: './main.js'
    };

    2.数组:除了main.js作为入口js之外,还有一个是用来配置webpack提供的一个静态资源服务器webpack-dev-server,它会监控项目中每个文件的变化,实时构建,并自动刷新页面。

    module.exports = {
      entry: [
        'webpack/hot/only-dev-server',
        './main.js'
      ]
    };

    3.对象:将不同的文件按需构建,按需使用

    module.exports = {
      entry: {
        a: './a.js',
        b: './b.js'
      }
    };

    output用于定义构建后的文件的输出,是个对象,其中包含了path和filename

    module.exports = {
      output: {
        path: './build',
        filename: 'bundle.js'
      }
    };

    二 devtool 

    devtool属性可以配置调试代码的方式,有多种调试方式,一般只在开发时使用,生产环境下应该将值设置为false。常用值有两个:

    eval: 可以设断点调试,不显示信息,每个js模块代码用eval()执行,并且在生成的每个模块代码尾部加上注释,不 会生成.map文件。

    source-map: 可以设断点调试,不显示列信息,生成相应的.Map文件,并在合并后的代码尾部加上注释//# sourceMappingURL=**.js.map,可以看到模块代码并没有被eval()包裹,此种模式并没有将调试信息放入打 包后的代码中,保持了打包后代码的简洁性.

    devtool选项 配置结果
    source-map 在一个单独的文件中产生一个完整且功能完全的文件。这个文件具有最好的source map,但是它会减慢打包速度;
    cheap-module-source-map 在一个单独的文件中生成一个不带列映射的map,不带列映射提高了打包速度,但是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便;
    eval-source-map 使用eval打包源文件模块,在同一个文件中生成干净的完整的source map。这个选项可以在不影响构建速度的前提下生成完整的sourcemap,但是对打包后输出的JS文件的执行具有性能和安全的隐患。在开发阶段这是一个非常好的选项,在生产阶段则一定不要启用这个选项;
    cheap-module-eval-source-map 这是在打包文件时最快的生成source map的方法,生成的Source Map 会和打包后的JavaScript文件同行显示,没有列映射,和eval-source-map选项具有相似的缺点;

    上述选项由上到下打包速度越来越快,不过同时也具有越来越多的负面作用,较快的打包速度的后果就是对打包后的文件的的执行有一定影响。cheap-module-eval-source-map推荐在大型项目考虑时间成本时使用,对小到中型的项目中,eval-source-map是一个很好的选项。

    三 devserver 

    如果想让你的浏览器监听你的代码修改,并自动刷新显示修改后的结果,webpack提供了一个可选的本地开发服务器,这个本地服务器基于node.js构建,可以实现你想要的这些功能,不过这是一个单独的组件,在webpack进行配置之前需要单独安装它作为项目依赖。

    npm install --save-dev webpack-dev-server

    devserver有一些配置选项,可以参考如下的配置:

    devserver的配置选项 功能描述
    contentBase 默认webpack-dev-server会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录
    port 设置默认监听端口,如果省略,默认为”8080“
    inline 设置为true,当源文件改变时会自动刷新页面
    historyApiFallback 在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html
    module.exports = {
      devtool: 'eval-source-map',
      entry:  __dirname + "/app/main.js",
      output: {
        path: __dirname + "/public",
        filename: "bundle.js"
      },
      devServer: {
        contentBase: "./public",//本地服务器所加载的页面所在的目录
        historyApiFallback: true,//不跳转
        inline: true//实时刷新
      } 
    }

    Babel 

    Babel是一个编译JavaScript的平台,它可以编译代码帮你达到以下目的: 

    • 让你能使用最新的JavaScript代码(ES6,ES7),而不用管新标准是否被当前使用的浏览器完全支持;
    • 让你能使用基于JavaScript进行拓展的语言,如React的JSX;

    Babel其实是几个模块化的包,其核心功能位于称为babel-core的npm包中,webpack可以把其不同的包整合在一起使用,对于每一个你需要的功能或拓展,你都需要安装单独的包(用得最多的是解析Es6的babel-env-preset包和解析JSX的babel-preset-react包)。

    module.exports = {
        entry: __dirname + "/app/main.js",//已多次提及的唯一入口文件
        output: {
            path: __dirname + "/public",//打包后的文件存放的地方
            filename: "bundle.js"//打包后输出文件的文件名
        },
        devtool: 'eval-source-map',
        devServer: {
            contentBase: "./public",//本地服务器所加载的页面所在的目录
            historyApiFallback: true,//不跳转
            inline: true//实时刷新
        },
        module: {
            rules: [
                {
                    test: /(.jsx|.js)$/,
                    use: {
                        loader: "babel-loader",
                        options: {
                            presets: [
                                "env", "react"
                            ]
                        }
                    },
                    exclude: /node_modules/
                }
            ]
        }
    };

    现在你的webpack的配置已经允许你使用ES6以及JSX的语法了。

    五 module

    module主要是用来配置加载器(loaders)。webpack本身只能处理javascript模块,如果要处理其他类型的文件,就需要使用loader进行转换,每一种文件会用不同的加载器处理。 
    loadres,preLoadres,postLoaders的配置主要包括以下几项:

      • test:一个匹配loaders所处理的文件的拓展名的正则表达式(必须)
      • loader: loader的名称(必须)
      • include/exclude: 手动添加必须处理的文件/文件夹,或屏蔽不需要处理的文件/文件夹(可选)
      • query: 为loaders提供额外的设置选项(可选)
    module: {
        exprContextCritical: false,
        rules: [
          {
            test: /.ts$/,
            enforce: 'pre',
            loader: 'tslint-loader',
            exclude: /target/
          },
          {
            test: /.tsx?$/,
            use: [
              {
                loader: 'babel-loader',
                options: {
                  cacheDirectory: './.babelcache/',
                  plugins: ['angularjs-annotate']
                }
              }
            ],
            enforce: 'post',
            exclude: createBabelExclude()
          },
          {
            test: /.json$/,
            loader: 'json-loader'
          },
          {
            test: /.html$/,
            loader: 'html-loader'
          },
          {
            test: require.resolve('highcharts'),
            loader: 'expose-loader?Highcharts'
          }
        ]
      }

    六  resolve 

    resolve用来配置文件路径的指向。可以定义文件跟模块的默认路径及后缀等,节省webpack搜索文件的时间、优化引用模块时的体验。常用的包括alias,extensions,root,moduleDirectories属性。 

    • alias: 是个对象,把资源路径重定向到另一个路径
    • extensions: 是个数组,定义资源的默认后缀,比如定义后引用a.js、b.json、c.css等资源可以不用写后缀名直接写a、b、c
    • root: 是个数组,通过绝对路径的方式来定义查找模块的文件夹。可以是一个数组,主要是用来增加模块的搜寻位置使用的。root 的值必须是绝对路径,使用path.resolve设置。
    • modulesDirectories: 是个数组,用来设置搜索的目录名的,默认为["web_modules", "node_modules"]

    resolve: {
            //查找module的话从这里开始查找
            root: 'E:/github/flux-example/src', //绝对路径
            //自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名
            extensions: ['', '.js', '.json', '.scss'],
            //模块别名定义,方便后续直接引用别名,无须多写长长的地址
            alias: {
                AppStore : 'js/stores/AppStores.js',//后续直接 require('AppStore') 即可
                ActionType : 'js/actions/ActionType.js',
                AppAction : 'js/actions/AppAction.js'
            }
        }

    七 plugins 

    插件是用来拓展webpack的功能的,会在整个构建过程中生效,执行相关的任务。Loadres和Plugins是完全不同的,loaders是在打包构建过程中用来处理源文件的(JSX,Scss,Less),一次处理一个,插件并不是直接操作单个文件,它直接对整个构建过程起作用。webpack有很多内置插件和第三方插件。使用某个插件,先用npm安装,然后在webpack配置的plugins关键字部分添加该插件的一个实例。 
    比如常用的HtmlWebpackPlugin,这个插件的作用是依据一个简单的index.html模板,生成一个自动引用你打包后的JS文件的新index.html。这在每次生成的js文件名称不同时非常有用(比如添加了hash值)。 
    安装:

    npm install --save-dev html-webpack-plugin

    这个插件自动完成了我们之前手动做的一些事情,在正式使用之前需要对一直以来的项目结构做一些更改: 
    (1)移除public文件夹,利用此插件,index.html文件会自动生成,此外CSS已经通过前面的操作打包到JS中了。 
    (2)在app目录下,创建一个index.tmpl.html文件模板,这个模板包含title等必须元素,在编译过程中,插件会依据此模板生成最终的html页面,会自动添加所依赖的css,js,favicon等文件.

    index.tmpl.html中的模板源代码如下:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <title>Webpack Sample Project</title>
      </head>
      <body>
        <div id='root'>
        </div>
      </body>
    </html>

    (3)新webpack的配置文件,方法同上,新建一个build文件夹用来存放最终的输出文件

    const webpack = require('webpack');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
        entry: __dirname + "/app/main.js",//已多次提及的唯一入口文件
        output: {
            path: __dirname + "/build",
            filename: "bundle.js"
        },
        devtool: 'eval-source-map',
        devServer: {
            contentBase: "./public",//本地服务器所加载的页面所在的目录
            historyApiFallback: true,//不跳转
            inline: true//实时刷新
        },
        module: {
            rules: [
                {
                    test: /(.jsx|.js)$/,
                    use: {
                        loader: "babel-loader"
                    },
                    exclude: /node_modules/
                },
                {
                    test: /.css$/,
                    use: [
                        {
                            loader: "style-loader"
                        }, {
                            loader: "css-loader",
                            options: {
                                modules: true
                            }
                        }, {
                            loader: "postcss-loader"
                        }
                    ]
                }
            ]
        },
        plugins: [
            new webpack.BannerPlugin('版权所有,翻版必究'),
            new HtmlWebpackPlugin({
                template: __dirname + "/app/index.tmpl.html"//new 一个这个插件的实例,并传入相关的参数
            })
        ],
    };

    执行npm start,可以发现build文件夹下面生成了bundle.js和index.html
    介绍一些常用的插件:

    插件 作用
    extract-text-webpack-plugin 第三方插件,将 CSS 打包成独立文件,而非内联。
    HotModuleReplacementPlugin 代码热替换
    HtmlWebpackPlugin 生成 HTML 文件,配合 ExtractTextPlugin 可以加入打包后的 js 和 css。
    NoErrorsPlugin 报错但不退出 webpack 进程。
    DefinePlugin 主要用来定义全局的环境变量,以便我们在自己的程序中引用它。

    代码热替换 
    代码热替换在开发的时候无需刷新页面即可看到更新,只在开发环境的配置文件使用,具体配置如下。

    npm install --save-dev webpack-dev-server webpack-dev-middleware express

    把webpack/hot/dev-server加入到 webpack 配置文件的 entry 项:

    <!-- webpack.config.dev.js -->
    entry: [
        'webpack-dev-server/client?http://localhost:3000',
        './src/app.js'
    ],

    把new webpack.HotModuleReplacementPlugin()加入到 webpack 配置文件的 plugins 项:

    <!-- webpack.config.js -->
    plugins: [
    new webpack.HotModuleReplacementPlugin()
    ]

    在项目根目录新建个server.js文件,将server部分分离到一个单独的 :

    <!-- server.js -->
    var webpack = require('webpack');
    var WebpackDevServer = require('webpack-dev-server');
    var config = require('./webpack.config');
    var compiler = webpack(config);
    var server = new WebpackDevServer(compiler, {
    publicPath: config.output.publicPath,
    hot: true,
    historyApiFallback: true,
    stats: {
    colors: true,
    hash: false,
    timings: true,
    chunks: false,
    chunkModules: false,
    modules: false
    }
    });
    server.listen(3000, 'localhost', function(err, result) {
    if (err) {
    return console.log(err);
    }
    console.log('Listening at http://localhost:3000/');
    });

    在 package.json 中定义启动监听热加载:

    <!-- package.json -->
    "scripts": {
      "start": "node server.js"
    }

    现在你可以通过运行npm start启动服务器。

  • 相关阅读:
    list 集合工具类
    Java获取当前系统时间的前N小时时间
    注意点
    小bug
    Linux常用命令
    MySql的执行计划
    【解决问题】引入.vmx文件后,xshell连接Could not connect to ‘192.168.211.132‘ (port 22): Connection failed
    星涛:javaEE学习路线一览
    Vue响应式原理
    Java操作Xml文件
  • 原文地址:https://www.cnblogs.com/lyy-2016/p/8531102.html
Copyright © 2020-2023  润新知