webpack_webpack面试题 - CSDN
精华内容
参与话题
  • Webpack的基本使用

    千次阅读 多人点赞 2020-06-07 18:54:47
    一、什么是Webpack Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。 从图中我们可以看出,Webpack 可以将多种静态资源 js、css、less...

    一、什么是Webpack

    Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。

    从图中我们可以看出,Webpack 可以将多种静态资源 js、css、less 转换成一个静态文件,减少了页面的请求。

    在这里插入图片描述

    二、Webpack安装

    1、全局安装

    npm install -g webpack webpack-cli
    

    2、安装后查看版本号

    webpack -v
    

    三、初始化项目

    1、创建webpack文件夹

    进入webpack目录,执行命令

    npm init -y
    

    2、创建src文件夹

    3、src下创建common.js

    exports.info = function (str) {
        document.write(str);
    }
    

    4、src下创建utils.js

    exports.add = function (a, b) {
        return a + b;
    }
    

    5、src下创建main.js

    const common = require('./common');
    const utils = require('./utils');
    common.info('Hello world!' + utils.add(100, 200));
    

    四、JS打包

    1、webpack目录下创建配置文件webpack.config.js

    以下配置的意思是:读取当前项目目录下src文件夹中的main.js(入口文件)内容,分析资源依赖,把相关的js文件打包,打包后的文件放入当前目录的dist文件夹下,打包后的js文件名为bundle.js

    const path = require("path"); //Node.js内置模块
    module.exports = {
        entry: './src/main.js', //配置入口文件
        output: {
       path: path.resolve(__dirname, './dist'), //输出路径,__dirname:当前文件所在路径
            filename: 'bundle.js' //输出文件
        }
    }
    

    2、命令行执行编译命令

    webpack #有黄色警告
    webpack --mode=development #没有警告
    #执行后查看bundle.js 里面包含了上面两个js文件的内容并惊醒了代码压缩
    

    也可以配置项目的npm运行命令,修改package.json文件

    "scripts": {
        //...,
        "dev": "webpack --mode=development"
     }
    

    运行npm命令执行打包

    npm run dev
    

    3、webpack目录下创建index.html

    引用bundle.js

    <body>
        <script src="dist/bundle.js"></script>
    </body>
    

    4、浏览器中查看index.html

    五、CSS打包

    1、安装style-loader和 css-loader

    Webpack 本身只能处理 JavaScript 模块,如果要处理其他类型的文件,就需要使用 loader 进行转换。

    Loader 可以理解为是模块和资源的转换器。

    首先我们需要安装相关Loader插件,css-loader 是将 css 装载到 javascript;style-loader 是让 javascript 认识css

    npm install --save-dev style-loader css-loader 
    

    2、修改webpack.config.js

    const path = require("path"); //Node.js内置模块
    module.exports = {
        //...,
        output:{},
        module: {
            rules: [  
                {  
                    test: /\.css$/,    //打包规则应用到以css结尾的文件上
                    use: ['style-loader', 'css-loader']
                }  
            ]  
        }
    }
    

    3、在src文件夹创建style.css

    body{
        background:pink;
    }
    

    4、修改main.js

    在第一行引入style.css

    require('./style.css');
    

    5、浏览器中查看index.html

    看看背景是不是变成粉色啦?

    展开全文
  • webpack入门和实战(一)--webpack配置及技巧

    万次阅读 多人点赞 2018-09-18 14:24:06
    一、全面理解webpack 1、什么是 webpack?  webpack是近期最火的一款模块加载器兼打包工具,它能把各种资源,例如JS(含JSX)、coffee、样式(含less/sass)、图片等都作为模块来使用和处理,它能有Grunt或Gulp...

    一、全面理解webpack

    1、什么是 webpack?

           webpack是近期最火的一款模块加载器兼打包工具,它能把各种资源,例如JS(含JSX)、coffee、样式(含less/sass)、图片等都作为模块来使用和处理,它能有Grunt或Gulp所有基本功能。webpack的官网是 https://webpack.github.io/ ,文档地址是https://webpack.github.io/docs,官网对webpack的定义是MODULE BUNDLER,他的目的就是把有依赖关系的各种文件打包成一系列的静态资源。 请看下图:

    2、webpack 的优势

    其优势主要可以归类为如下几个:

    1. webpack 是以 commonJS 的形式来书写脚本滴,但对 AMD/CMD 的支持也很全面,方便旧项目进行代码迁移。
    2. 支持很多模块加载器的调用,可以使模块加载器灵活定制,比如babel-loader加载器,该加载器能使我们使用ES6的语法来编写代码;less-loader加载器,可以将less编译成css文件;
    3. 开发便捷,能替代部分 grunt/gulp 的工作,比如打包、压缩混淆、图片转base64等。
    4. 可以通过配置打包成多个文件,有效的利用浏览器的缓存功能提升性能。

    3、wepback它的目标是是什么?

    webpack它能将依赖的模块转化成可以代表这些包的静态文件

    • 将依赖的模块分片化,并且按需加载
    • 解决大型项目初始化加载慢的问题
    • 每一个静态文件都可以看成一个模块
    • 可以整合第三方库
    • 能够在大型项目中运用
    • 可以自定义切割模块的方式

    4、webpack较之其他类似工具有什么不同?

    • 有同步和异步两种不同的加载方式
    • Loader,加载器可以将其他资源整合到JS文件中,通过这种方式,可以讲所有的源文件形成一个模块
    • 优秀的语法分析能力,支持 CommonJs AMD 规范
    • 有丰富的开源插件库,可以根据自己的需求自定义webpack的配置

    5、webpack为什么要将所有资源放在一个文件里面?

    我们知道,对于浏览器来说,加载的资源越少,响应的速度也就越快,所以有时候我们为了优化浏览器的性能,会尽可能的将资源合并到一个主文件app.js里面。但是这导致的很大的缺点:

    • 当你的项目十分庞大的时候,不同的页面不能做到按需加载,而是将所有的资源一并加载,耗费时间长,性能降低。
    • 会导致依赖库之间关系的混乱,特别是大型项目时,会变得难以维护和跟踪。比如:哪些文件是需要A模块加载完后才能执行的?哪些页面会受到多个样式表同时影响的? 等许多问题。

    而webpack可以很好的解决以上缺点,因为它是一个十分聪明的模块打包系统,当你正确配置后,它会比你想象中的更强大,更优秀。

    二、开启wbpack之旅

    安装步骤如下:

    1、生成package.json文件;

    先装好node和npm,因为webpack是一个基于node的项目。然后首先我们需要在根目录下生成package.json文件,需要进入项目文件内根目录下执行如下命令:npm init

    如上通过一问一答的方式后会在根目录下生成package.json文件,如下所示:

    2 . 通过全局安装webpack

    执行命令如下:npm install -g webpack 如下所示:

    在c盘下会生成node_modules文件夹中会包含webpack,此时此刻我们可以使用webpack命令了;

    在常规项目中把webpack依赖加入到package.json

    npm init npm install webpack --save

    更详尽的安装方法个可以参考webpack安装

    3. 配置webpack

    每个目录下都必须有一个webpack.config.js,它的作用就好比Gulpfile.js、或者 Gruntfile.js,就是一个项目配置,告诉webpack需要做什么。

    首先先贴上一个比较完整的webpack.config.js的代码,再详细介绍:

    //详细的webpack.config.js结构分析:
    var path = require('path');
    var webpack = require('webpack');
    var HtmlWebpackPlugin = require('html-webpack-plugin');
    var TransferWebpackPlugin = require('transfer-webpack-plugin');
     
    module.exports = {
        devtool: 'source-map',//由于打包后的代码是合并以后的代码,不利于排错和定位,只需要在config中添加,这样出错以后就会采用source-map的形式直接显示你出错代码的位置。
        //noParse:[/jquery/],//表示跳过jquery,不对其进行编译,这样可以提高打包的速度
        //页面入口文件配置
        entry: {
            page1: "./src/index.js",
            //page2: ["./src/index.js", "./src/main.js"],支持数组形式,将加载数组中的所有模块,但以最后一个模块作为输出
        },
        //入口文件输出配置
        output: {
            path: "dist/js/page",
            filename: "[name].bundle.js",// page1.bundle.js 和 page2.bundle.js,并存放到 ./dist/js/page 文件夹下。
            publicPath: "/dist/"    //网站运行时的访问路径。
        },
        resolveLoader: {
            //指定默认的loader路径,否则依赖走到上游会找不到loader
            root: path.join(__dirname, 'node_modules'),
            alias: {//给自己写的loader设置别名
                "seajs-loader": path.resolve( __dirname, "./web_modules/seajs-loader.js" )
            }
        },
        //新建一个开发服务器,并且当代码更新的时候自动刷新浏览器。
        devServer: {
            historyApiFallback: true,
            noInfo: true,
            hot: true,
            inline: true,
            progress: true,
            port:9090 //端口你可以自定义
        },
        module: {
            // module.loaders 是最关键的一块配置。它告知 webpack每一种文件都需要使用什么加载器来处理:
            loaders: [
            { test: /\.css$/, loader: 'style-loader!css-loader' },//.css 文件使用 style-loader 和 css-loader 来处理.
            //{ test: /\.css$/, loader: 'style!css' },其他写法1、"-loader"其实是可以省略不写的,多个loader之间用“!”连接起来。
            //{ test: /\.css$/, loaders: ["style", "css"] },其他写法2、用loaders数组形式;
            //.scss 文件使用 style-loader、css-loader 和 sass-loader 来编译处理。
            //在chrome中我们通过sourcemap可以直接调试less、sass源文件文件
            { test: /\.scss$/, loader: 'style!css!sass?sourceMap'},
            { test: /\.less$/, loader: 'style!css!less?sourceMap'},//.less 文件使用 style-loader、css-loader 和 less-loader 来编译处理
            //.js 文件使用babel-loader来编译处理,设置exclude用来排除node_modules这个文件夹中的代码
            { test: /\.js$/, loader: 'babel!jsx',exclude: /node_modules/ }, 
            { test: /\.jsx$/, loader: "jsx-loader?harmony" },//.jsx 文件使用 jsx-loader 来编译处理
            { test: /\.json$/,loader: 'json'},
            //{ test: /\.(png|jpg|jpeg|gif)$/, loader: 'url-loader?limit=8192'}, //图片文件使用 url-loader 来处理,小于8kb的直接转为base64
            {test: /\.(png|jpg|gif|svg)$/,loader: 'url',
                query: {limit: 10000,name: '[name].[ext]?[hash]'}//设置图片名称扩展名
            },
            { test: /\.jade$/, loader: "jade-loader" },//.jade 文件使用 jade-loader 来编译处理
            { test: /\.ejs$/, loader: "ejs-loader" },//.ejs 文件使用 ejs-loader 来编译处理
            { test: /\.handlebars$/, loader: "handlebars-loader" },//.handlebars 文件使用handlebars-loader来编译处理handlebars模板文件
            { test: /\.dot$/, loader: "dot-loader" },//.dot 文件使用 dot-loader 来编译处理dot模板文件
            { test: /\.vue$/, loader: "vue-loader" },//.vue 文件使用 vue-loader 来编译处理
            { test: /\.coffee$/, loader: 'coffee-loader' },//.coffee 文件使用 coffee-loader 来编译处理
            { test: /\.html$/,loader: 'vue-html'},
            { test: /\.woff$/,loader: "url?limit=10000&minetype=application/font-woff"},
            { test: /\.ttf$/,loader: "file"},
            { test: /\.eot$/,loader: "file"},
            { test: /\.svg$/,loader: "file"}
            ]
        },
        //分内置插件和外置插件
        plugins: [
            //使用了一个 CommonsChunkPlugin 的插件,它用于提取多个入口文件的公共脚本部分,然后生成一个common.js来方便多页面之间进行复用。
            new webpack.optimize.CommonsChunkPlugin('common.js'),
            new webpack.optimize.UglifyJsPlugin({//压缩文件
              compressor: {
                warnings: false,//supresses warnings, usually from module minification
              },
              except: ['$super', '$', 'exports', 'require']    //排除关键字(可选)
            }),
            new webpack.DefinePlugin({// definePlugin 接收字符串插入到代码当中, 所以你需要的话可以写上 JS 的字符串
                 __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'true')),
                 __PRERELEASE__: JSON.stringify(JSON.parse(process.env.BUILD_PRERELEASE || 'false'))
            }),
            new webpack.ProvidePlugin({//把一个全局变量插入到所有的代码中,支持jQuery plugin的使用;使用ProvidePlugin加载使用频率高的模块
                 //provide $, jQuery and window.jQuery to every script
                 $: "jquery",
                 jQuery: "jquery",
                 "window.jQuery": "jquery"
             }),
            new webpack.NoErrorsPlugin(), //允许错误不打断程序
            new TransferWebpackPlugin([ //把指定文件夹下的文件复制到指定的目录
              {from: 'www'}
            ], path.resolve(__dirname,"src")),
            new HtmlwebpackPlugin({//用于生产符合要求的html文件;
               title: 'Hello World app',
               filename: 'assets/admin.html'
            })
        ],
        //其它解决方案配置
        resolve: {
            root: 'E:/github/flux-example/src', //绝对路径, 查找module的话从这里开始查找(可选)
            extensions: ['', '.js', '.html', '.css', '.scss'], //自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名
            alias: {                            //模块别名定义,方便后续直接引用别名,无须多写长长的地址//后续直接 require('AppStore') 即可
                AppStore : 'js/stores/AppStores.js',
                ActionType : 'js/actions/ActionType.js',
                AppAction : 'js/actions/AppAction.js'
            },
            modulesDirectories: [//取相对路径,所以比起 root ,所以会多很多路径。查找module(可选)
                 'node_modules',
                 'bower_components',
                 'lib',
                 'src'
            ]
        }
         
    };
     
    if (process.env.NODE_ENV === 'production') {
      module.exports.devtool = '#source-map'
      // http://vue-loader.vuejs.org/en/workflow/production.html
      module.exports.plugins = (module.exports.plugins || []).concat([
        new webpack.DefinePlugin({
          'process.env': {
            NODE_ENV: '"production"'
          }
        }),
        new webpack.optimize.UglifyJsPlugin({
          compress: {
            warnings: false
          }
        }),
        //为组件分配ID,通过这个插件webpack可以分析和优先考虑使用最多的模块,并为它们分配最小的ID
        new webpack.optimize.OccurenceOrderPlugin()
      ])
    }

    plugins中包含很多的内置插件和外部插件,它们都有各自的功能,用来处理相关的文件,这里只是罗列了部分,具体用法请看webpack入门和实战(二):全面理解和运用plugins和loader

    就像我在前面提到的,webpack.config.js的写法和在Node里的写法相同,我们主要看的就是文件中的module.exports里面的内容

    • entry 是指入口文件的配置项,它是一个数组的原因是webpack允许多个入口点。
    • output是指输出文件的配置项
      • path - 表示输出文件的路径
      • filename - 表示输出文件的文件名
    • plugins 顾名思义,使用插件可以给webpack添加更多的功能,使webpack更加的灵活和强大,webpack有两种类型的插件:
      • webpack内置的插件

    // 首先要先安装webpack模块

    var webpack = require("webpack");
    module.exports = {
        new webpack.optimize.UglifyJsPlugin({
          compressor: {
            warnings: false,
          },
        })
    };
      •  webpack外置插件
    //npm install component-webpack-plugin 先要在安装该模版
    var ComponentPlugin = require("component-webpack-plugin");
    module.exports = {
        plugins: [
            new ComponentPlugin()
        ]
    }

    更多的插件以及插件的用法,大家可以到webpack的插件上查看。

    • module 配置处理文件的选项
      • loaders 一个含有wepback中能处理不同文件的加载器的数组
        • test 用来匹配相对应文件的正则表达式
        • loaders 告诉webpack要利用哪种加载器来处理test所匹配的文件
      • loaders 的安装方法

            $ npm install xxx-loader --save-dev

    • resolve:其它解决方案配置;
      • resolve.root,绝对路径, 查找module的话从这里开始查找(可选)
      • resolve.modulesDirectories,取相对路径,所以比起 root ,所以会多 parse 很多路径。查找module(可选)
      • resolve.extensions,自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名
      • resolve.alias,模块别名定义,方便后续直接引用别名,无须多写长长的地址

    三、利用webpack实现在页面上合理使用打包过后的js文件和图片

    示例如下:

    webpack_test目录结构如下:

    最终完成版的目录结构为:

     index.html代码如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>demo1</title>
    </head>
    <body>
        <div id="content"></div>
        <img src="./build/img/demo.png">
        <script src="./build/js/index.js"></script>
    </body>
    </html>

    index.js代码如下:

    require('./index.css');

    index.css代码如下:

    #content{
        width:121px;
        height:140px;
        background-color: red;
    }

    demo.png自己随便找一张即可;

    根据webpack.config.js的配置情况,操作步骤如下:

    • 全局安装webpack,npm install webpack -g
    • 进入到webpack_test目录下,初始化生成package.json文件,npm init
    • 需要安装的loader有css-loader、style-loader、url-loader,webpack, npm install css-loader style-loader url-loader webpack--save-dev
    • 执行webpack,生成打包过后的build/js/index.js,build/img/demo.png
    • 在index.html中引入即可

    效果如下:

     源码地址为:http://download.csdn.net/detail/wdlhao/9612173,有需要的同学可以自行下载练习;

     四、理解webpack支持commonJS和AMD/CMD两种模块机制进行打包

     1.AMD/CMD模式:

         AMD 规范在这里:https://github.com/amdjs/amdjs-api/wiki/AMD,CMD 规范在这里:https://github.com/seajs/seajs/issues/242

    • AMD(Asynchronous Module Definition) 是 RequireJS 在推广过程中对模块定义的规范化产出。(即RequireJS模块规范)

    RequireJS是一个工具库,主要用于客户端的模块管理。它可以让客户端的代码分成一个个模块,实现异步或动态加载,从而提高代码的性能和可维护性。它的模块管理遵守AMD规范(Asynchronous Module Definition)。RequireJS的基本思想是,通过define方法,将代码定义为模块;通过require方法,实现代码的模块加载。首先,将require.js嵌入网页,然后就能在网页中进行模块化编程了。<script data-main="scripts/main" src="scripts/require.js"></script>上面代码的data-main属性不可省略,用于指定主代码所在的脚本文件,在上例中为scripts子目录下的main.js文件。用户自定义的代码就放在这个main.js文件中。

    • CMD(Common Module Definition )是 SeaJS 在推广过程中对模块定义的规范化产出。(即SeaJS模块规范)

    SeaJS是一个遵循CMD规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制。

    • CommonJS Modules/2.0 规范,是 BravoJS 在推广过程中对模块定义的规范化产出。

    CommonJS API定义很多普通应用程序(主要指非浏览器的应用)使用的API,从而填补了这个空白。它的终极目标是提供一个类似Python,Ruby和Java标准库。这样的话,开发者可以使用CommonJS API编写应用程序,然后这些应用可以运行在不同的JavaScript解释器和不同的主机环境中。在兼容CommonJS的系统中,你可以实用JavaScript程序开发:

    • 服务器端JavaScript应用程序
    • 命令行工具
    • 图形界面应用程序
    • 混合应用程序(如,Titanium或Adobe AIR)

    还有不少⋯⋯这些规范的目的都是为了 JavaScript 的模块化开发,特别是在浏览器端的。目前这些规范的实现都能达成浏览器端模块化开发的目的。

     2、AMD/CMD模式区别

    2.1从官方推荐的写法上面得出:

    CMD ----- 依赖就近

    Js代码 
    //CMD 
    define(function(require,exports,module){ 
       var a = require('./a'); 
       a.doSomthing(); 
    });

    AMD ----- 依赖前置

    Js代码 
    //AMD 
    define(['./a','./b'],function(a,b){ 
    //...... 
    a.doSomthing(); 
    //...... 
    b.doSomthing(); 
    })

    当然AMD也支持CMD的写法。

    2.2、执行顺序上:

      • CMD是延迟执行,推崇的是as lazy as possible
      • AMD是提前执行,requireJS从2.0开始可以延迟执行

    2.3、api设计角度:

      • CMD的API推崇职责单一,没有全局的require
      • AMD的API默认是一个当多个用:比如require有全局的和局部的。
    展开全文
  • webpack超详细配置, 使用教程(图文)

    万次阅读 多人点赞 2018-12-24 11:33:54
    博主在这里就不详细介绍webpack来源以及作用了, 本篇博文面向新手主要说明如何配置webpack, 以及webpack的使用方法, 直到创建出一个合理的属于自己webpack项目.流程webpack安装 Step 1: 首先安装Node.js, 可以去Node...

    博主在这里就不详细介绍webpack来源以及作用了, 本篇博文面向新手主要说明如何配置webpack, 以及webpack的使用方法, 直到创建出一个合理的属于自己webpack项目;

    注: 此篇博客适用于webpack2.x, 对于4.x版本变化还挺大的, 过一阵子会再写一篇, 点关注不走丢哦

    流程

    webpack安装

    • Step 1: 首先安装Node.js, 可以去Node.js官网下载.

    • Step 2: 在Git或者cmd中输入下面这段代码, 通过全局先将webpack指令安装进电脑中

    npm install webpack -g
    
    • Step 3: 使用Git Bash here 或者 cmd cd命令使当前目录转到当前项目的目录下, 然后输入下面这段命令
      npm init
      这里写图片描述
      接下来会弹出一些信息, 就是一些项目名和一些参数的描述, 可以全部按回车使用默认信息, 完成之后项目文件夹下会生成一个package.json的文件
      这里写图片描述
      这样webpack就安装完成了.




    webpack配置

    • Step1: 创建项目文件夹, 名字自起, 但路径名不要包含中文, 以及项目名也不要叫"webpack", 并且不要包含大写字母.
      例:这里写图片描述

    • Step2: 接下来创建并编写配置文件. 首先我们先介绍几个配置文件的参数.

      • entry: 是 页面入口文件配置 (html文件引入唯一的js 文件)
      • output:对应输出项配置
        • path :入口文件最终要输出到哪里,
        • filename:输出文件的名称
        • publicPath:公共资源路径
    • Step3: 在你的项目目录下创建webpack.config.js配置文件, 通过这个文件进行webpack的配置, 并且还要创建一些路径保存基本文件. 例如:
      这里写图片描述
      src文件夹
      这里写图片描述

    • Step4: 在src的js下创建一个入口文件, 我创建的叫做entry.js, 在项目目录再创建一个index.html用来调试使用. 编写webpack.config.js文件,

      //webpack.config.js
      module.exports = {
          entry : './src/js/entry.js',//入口文件
          output : {//输出文件
              filename : 'index.js',//输出文件名
              path : __dirname + '/out'//输出文件路径
          },
      

    }
    ```
    我们随便在index.html和入口文件entry.js写点什么看看是否成功配置,

    ```
    //index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8" />
        <title>ss</title>
    </head>
    <body>
    111
        <script src="./out/index.js"></script>//注意在这里引入的是打包完成的js文件
    </body>
    </html>
    ```
    
    
    ```javascript
    //entry.js
    console.log('1234');
    ```
    之后使用Git Bash here 或者 cmd cd命令使目录为当前项目目录, 输入**webpack**或者**webpack -w**命令, 查看index.html是否成功console出1234;
    

    webpack 和 webpack -w 区别
    webpack -w可以对项目打包并且实时监控, 当前配置文件下的文件如果发生更改时重新打包, 但如果webpack的配置文件即webpack.config.js更改时还是要通过webpack进行打包.(退出webpack -w 操作 ctrl+c)


    ### webpack loader加载器

    接下来我们继续配置loader, 通过加载器处理文件:比如 sass less 等, 告知 webpack 每一种文件都需要使用什么加载器来处理。

    • **Step1: **为了方便我们先统一把所有的包都先下载下来, 下面再慢慢解释.

      npm install babel-loader babel babel-core css-loader style-loader  url-loader file-loader less-loader less  --save-dev 
      
      

    - **Step2: **下载完成后, 我们修改webpack.config.js文件, 将加载器引入.
    ```
    module.exports = {
        entry :  './src/js/entry.js',
        output : {
            filename : 'index.js',
            path : __dirname + '/out'
        },
        module : {
            rules: [
                {test: /.js$/, use: ['babel-loader']},
                {test: /.css$/, use: ['style-loader', 'css-loader']},/*解析css, 并把css添加到html的style标签里*/
                //{test: /.css$/, use: ExtractTextPlugin.extract({fallback: 'style-loader',use: 'css-loader'})},/*解析css, 并把css变成文件通过link标签引入*/
                {test: /.(jpg|png|gif|svg)$/, use: ['url-loader?limit=8192&name=./[name].[ext]']},/*解析图片*/
                {test: /.less$/, use: ['style-loader', 'css-loader', 'less-loader']}/*解析less, 把less解析成浏览器可以识别的css语言*/
            ]
        },
        }
    ```
    <br>
    
    • **Step3: **接下来我们先测试css, 我们在项目文件夹下的src文件夹下创建index.css. 随便写一点属性.

      //index.css
      .demo1 {
          width: 100px;
          height: 100px;
          background: red;
      }
      .demo2 {
          width: 200px;
          height: 200px;
          background: orange;
      }
      
      //index.html
      <!DOCTYPE html>
      
    text
    ``` 因为在webpack中所有文件都是模块, 所以必须要将css引入. 在刚刚的entry.js中添加如下代码.
    ```javascript
    //entry.js
    require('../css/index.css');//引入css文件
    console.log("1234");
    ```
    
    打包webpack一下看看效果
    ![这里写图片描述](https://img-blog.csdn.net/20170506175719289?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY19raXRl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)<br>
    
    • **Step4: **当有多个js文件时, 如何进行引入呢? 接下来我们做一个简单小功能来说明这个问题, 让我们点击方块的时候, 方块变大.

      接下来在src的js文件夹下创建一个基本的工具tool.js (很多小的问题都被我扩大化了, 只是为了说明问题不一定适用)

      //tool.js
      var tool = {//获取DOM元素
          getDom: function(className) {
              return document.getElementsByClassName(className)[0];
          }
      }
      
      module.exports = tool;//模块出口
      

      src的js下创建一个demo1.js文件, demo2.js同理

      var obj = require('./tool.js');
          var demo1 = {
          init: function() {
              this.bindEvent();
          },
          bindEvent: function() {
              //var demo1 = document.getElementsByClassName('demo1')[0];
              var demo1 = obj.getDom('demo1');
              demo1.onclick = this.changeStyle;
          },
          changeStyle: function() {
              this.style.width = '200px';
              this.style.height = '200px';
              this.style.background = 'green';
              console.log('1');
          }
      }
      
      module.exports = demo1;
      

      修改入口文件entry.js

      require('../css/index.css');
      
      var demo1 = require('../js/demo1.js');
      var demo2 = require('../js/demo2.js');
      
          demo1.init();
          demo2.init();
      

      webpack一下, 看看效果
      这里写图片描述



    关于图片的打包

    • **Step1: **在img文件夹下随便找一个小一点的图片放进去.

    • **Step2: **修改entry.js

      require('../css/index.css');
      
      var demo1 = require('../js/demo1.js');
      var demo2 = require('../js/demo2.js');
      
          demo1.init();
          demo2.init();
      
      var oImg = new Image();
      oImg.src = require('../img/1.gif');//当成模块引入图片
      document.body.appendChild(oImg);
      

      由于我们引入的是静态资源, 在webpack.config.js中修改一下

      module.exports = {
      	    entry :  './src/js/entry.js',
      	    output : {
      	        filename : 'index.js',
      	        publicPath: __dirname + '/out',//添加静态资源, 否则会出现路径错误
      	        path : __dirname + '/out'
      	    },
      	    module : {
      	        rules: [
      	            {test: /.js$/, use: ['babel-loader']},
      	            {test: /.css$/, use: ['style-loader', 'css-loader']},/*解析css, 并把css添加到html的style标签里*/
      	            //{test: /.css$/, use: ExtractTextPlugin.extract({fallback: 'style-loader',use: 'css-loader'})},/*解析css, 并把css变成文件通过link标签引入*/
      	            {test: /.(jpg|png|gif|svg)$/, use: ['url-loader?limit=8192&name=./[name].[ext]']},/*解析图片*/
      	            {test: /.less$/, use: ['style-loader', 'css-loader', 'less-loader']}/*解析less, 把less解析成浏览器可以识别的css语言*/
      	        ]
      	    },
      }
      

      大家自己webpack看看效果



    webpack进阶设定

    我们在项目中有多个html文件时怎么处理呢?, 接下来我们重新设定配置文件, webpack.config.js

    	module.exports = {
    		    entry : {index1: './src/js/entry.js', index2: './src/js/entry2.js'},
    	    output : {
    		        filename : '[name].js',//这样就可以生成两个js文件, 名字分别为index1.js, 和index2.js
    		        publicPath: __dirname + '/out',//添加静态资源, 否则会出现路径错误
    		        path : __dirname + '/out'
    		    },
    		    module : {
    		        rules: [
    		            {test: /.js$/, use: ['babel-loader']},
    		            {test: /.css$/, use: ['style-loader', 'css-loader']},/*解析css, 并把css添加到html的style标签里*/
    		            //{test: /.css$/, use: ExtractTextPlugin.extract({fallback: 'style-loader',use: 'css-loader'})},/*解析css, 并把css变成文件通过link标签引入*/
    		            {test: /.(jpg|png|gif|svg)$/, use: ['url-loader?limit=8192&name=./[name].[ext]']},/*解析图片*/
    		            {test: /.less$/, use: ['style-loader', 'css-loader', 'less-loader']}/*解析less, 把less解析成浏览器可以识别的css语言*/
    		        ]
    		    },
    	}
    


    webpack插件使用

    首先我们由于要使用webpack插件, 因此我们要重新下载一下webpack包, 将目录定位到当前项目目录, 输入npm install webpack
    之后我们修改webpack.config.js, 将下面代码放到配置文件开头. 这样就可以使用插件了

    var webpack = require('webpack');
    

    将插件信息写到配置文件里

    var webpack = require('webpack');
    var uglifyPlugin = new webpack.optimize.UglifyJsPlugin({minimize: true});//代码压缩
    
    var CommonsChunkPlugin = new webpack.optimize.CommonsChunkPlugin('common');//把公共模块提取出来, 并取名为'common'(名字自起), webpack之后再out文件夹下生成common.js, 测试时记得引入提取出来的公共模块js文件
    
    var ExtractTextPlugin = require("extract-text-webpack-plugin");//将css独立引入变成link标签形式, 使用该插件需要独立下载'npm install extract-text-webpack-plugin --save-dev', 同时下面的rules也必须更改
    
    var providePlugin = new webpack.ProvidePlugin({$: 'jquery', jQuery: 'jquery', 'window.jQuery': 'jquery'});//引入jquery
    
    
    
    module.exports = {
        entry : {index: './src/js/entry.js', index2: './src/js/entry2.js'},
        output : {
            filename : '[name].js',
            publicPath: __dirname + '/out',
            path : __dirname + '/out'
        },
        module : {
            rules: [
                {test: /.js$/, use: ['babel-loader']},
                //{test: /.css$/, use: ['style-loader', 'css-loader']},
                {test: /.css$/, use: ExtractTextPlugin.extract({fallback: 'style-loader',use: 'css-loader'})},
                {test: /.(jpg|png|gif|svg)$/, use: ['url-loader?limit=8192&name=./[name].[ext]']},
                {test: /.less$/, use: ['style-loader', 'css-loader', 'less-loader']}
            ]
        },
        plugins: [uglifyPlugin, CommonsChunkPlugin, new ExtractTextPlugin('[name].css'),providePlugin]//插件集合
    }
    


    webpack服务器

    首先先定位目录输入命令 npm install webpack-dev-server -g, 修改webpack.config.js文件

    publicPath: 'http://localhost:8080/out',
    

    html文件所引用的目录也要更改:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8" />
        <title>text</title>
         <link rel="stylesheet" href="http://localhost:8080/out/index.css">
    </head>
    <body>
        <a href="http://localhost:8080/index2.html">11</a>
        <div class="demo1"></div>
        <div class="demo2"></div>
        <script src="http://localhost:8080/out/common.js"></script>
        <script src="http://localhost:8080/out/index.js"></script>
    </body>
    </html>
    

    webpack-dev-server一下看看效果

    小工具: webpace-dev-server --devtool eval-source-map --progess --colors打包时输入这一行可以直接找到文件如果出错时的位置

    小知识点: 上面这一句话如果觉得太长可以将

    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "xuan": "webpack-dev-server --devtool eval-source-map --progress --colors"
      },
    

    这一段代码放到项目目录下的package.json里, 这样调试时如果输入npm run xuan就等于输入那一长串代码

    展开全文
  • 入门Webpack,看这篇就够了

    千次阅读 2016-09-30 13:23:11
    阅读本文之前,先看下面这个webpack的配置文件,如果每一项你都懂,那本文能带给你的收获也许就比较有限,你可以快速浏览或直接跳过;如果你和十天前的我一样,对很多选项存在着疑惑,那花一段时间慢慢阅读本文,你...

    写在前面的话

    阅读本文之前,先看下面这个webpack的配置文件,如果每一项你都懂,那本文能带给你的收获也许就比较有限,你可以快速浏览或直接跳过;如果你和十天前的我一样,对很多选项存在着疑惑,那花一段时间慢慢阅读本文,你的疑惑一定一个一个都会消失;如果你以前没怎么接触过Webpack,而你又你对webpack感兴趣,那么动手跟着本文中那个贯穿始终的例子写一次,写完以后你会发现你已明明白白的走进了Webpack的大门。

    //一个常见的Webpack配置文件
    var webpack = require('webpack');
    var HtmlWebpackPlugin = require('html-webpack-plugin');
    var ExtractTextPlugin = require('extract-text-webpack-plugin');
    
    module.exports = {
      entry: __dirname + "/app/main.js",
      output: {
        path: __dirname + "/build",
        filename: "[name]-[hash].js"
      },
    
      module: {
        loaders: [
          {
            test: /\.json$/,
            loader: "json"
          },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel'
          },
          {
            test: /\.css$/,
            loader: ExtractTextPlugin.extract('style', 'css?modules!postcss')
          }
        ]
      },
      postcss: [
        require('autoprefixer')
      ],
    
      plugins: [
        new HtmlWebpackPlugin({
          template: __dirname + "/app/index.tmpl.html"
        }),
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.optimize.UglifyJsPlugin(),
        new ExtractTextPlugin("[name]-[hash].css")
      ]
    }

    WebPack为何物

    什么是Webpack

    WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。

    为什要使用WebPack

    现今的很多网页其实可以看做是功能丰富的应用,它们拥有着复杂的JavaScript代码和一大堆依赖包。为了简化开发的复杂度,前端社区涌现出了很多好的实践方法

    • 模块化,让我们可以把复杂的程序细化为小的文件;
    • 类似于TypeScript这种在JavaScript基础上拓展的开发语言:使我们能够实现目前版本的JavaScript不能直接使用的特性,并且之后还能能装换为JavaScript文件使浏览器可以识别;
    • Scss,less等CSS预处理器…

    这些改进确实大大的提高了我们的开发效率,但是利用它们开发的文件往往需要进行额外的处理才能让浏览器识别,而手动处理又是非常反锁的,这就为WebPack类的工具的出现提供了需求。

    WebPack和Grunt以及Gulp相比有什么特性

    其实Webpack和另外两个并没有太多的可比性,Gulp/Grunt是一种能够优化前端的开发流程的工具,而WebPack是一种模块化的解决方案,不过Webpack的优点使得Webpack可以替代Gulp/Grunt类的工具。

    Grunt和Gulp的工作方式是:在一个配置文件中,指明对某些文件进行类似编译,组合,压缩等任务的具体步骤,这个工具之后可以自动替你完成这些任务。
    Grunt和Gulp的工作流程

    Webpack的工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个浏览器可识别的JavaScript文件。
    Webpack工作方式

    Webpack工作方式
    如果实在要把二者进行比较,Webpack的处理速度更快更直接,能打包更多不同类型的文件。

    开始使用Webpack

    初步了解了Webpack工作方式后,我们一步步的开始学习使用Webpack。

    安装

    Webpack可以使用npm安装,新建一个空的练习文件夹(此处命名为webpack sample progect),在终端中转到该文件夹后执行下述指令就可以完成安装。

    //全局安装
    npm install -g webpack
    //安装到你的项目目录
    npm install --save-dev webpack

    使用Webpack前的准备

    在上述练习文件夹中创建一个package.json文件,这是一个标准的npm说明文件,里面蕴含了丰富的信息,包括当前项目的依赖模块,自定义的脚本任务等等。在终端中使用npm init命令可以自动创建这个package.json文件

    npm init

    输入这个命令后,终端会问你一系列诸如项目名称,项目描述,作者等信息,不过不用担心,如果你不准备在npm中发布你的模块,这些问题的答案都不重要,回车默认即可。

    package.json文件已经就绪,我们在本项目中安装Webpack作为依赖包

    // 安装Webpack
    npm install --save-dev webpack

    回到之前的空文件夹,并在里面创建两个文件夹,app文件夹和public文件夹,app文件夹用来存放原始数据和我们将写的JavaScript模块,public文件夹用来存放准备给浏览器读取的数据(包括使用webpack生成的打包后的js文件以及一个index.html文件)。在这里还需要创建三个文件,index.html 文件放在public文件夹中,两个js文件(Greeter.js和main.js)放在app文件夹中,此时项目结构如下图所示
    这里写图片描述

    index.html文件只有最基础的html代码,它唯一的目的就是加载打包后的js文件(bundle.js)

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

    Greeter.js只包括一个用来返回包含问候信息的html元素的函数。

    //main.js 
    var greeter = require('./Greeter.js');
    document.getElementById('root').appendChild(greeter());
    main.js用来把Greeter模块返回的节点插入页面。
    
    // Greeter.js
    module.exports = function() {
      var greet = document.createElement('div');
      greet.textContent = "Hi there and greetings!";
      return greet;
    };

    正式使用Webpack

    webpack可以在终端中使用,其命令是:

    //第1个参数为入口文件,第2个参数为放bundle.js的地方
    webpack {entry file} {destination for bundled file}

    只需要指定一个入口文件,webpack将自动识别项目所依赖的其它文件,不过需要注意的是如果你的webpack没有进行全局安装,那么当你在终端中使用此命令时,需要额外指定其在node_modules中的地址,继续上面的例子,在终端中属于如下命令

    //webpack非全局安装的情况
    node_modules/.bin/webpack app/main.js public/bundle.js

    结果如下
    这里写图片描述
    可以看出webpack同时编译了main.js 和Greeter,js,现在打开index.html,可以看到如下结果
    这里写图片描述
    有没有很激动,已经成功的使用Webpack打包了一个文件了。不过如果在终端中进行复杂的操作,还是不太方便且容易出错的,接下来看看Webpack的另一种使用方法。

    通过配置文件来使用Webpack

    Webpack拥有很多其它的比较高级的功能(比如说本文后面会介绍的loaders和plugins),这些功能其实都可以通过命令行模式实现,但是正如已经提到的,这样不太方便且容易出错的,一个更好的办法是定义一个配置文件,这个配置文件其实也是一个简单的JavaScript模块,可以把所有的与构建相关的信息放在里面。

    还是继续上面的例子来说明如何写这个配置文件,在当前练习文件夹的根目录下新建一个名为webpack.config.js的文件,并在其中进行最最简单的配置,如下所示,它包含入口文件路径和存放打包后文件的地方的路径。

    module.exports = {
      entry:  __dirname + "/app/main.js",//已多次提及的唯一入口文件
      output: {
        path: __dirname + "/public",//打包后的文件存放的地方
        filename: "bundle.js"//打包后输出文件的文件名
      }
    }

    注:“__dirname”是node.js中的一个全局变量,它指向当前执行脚本所在的目录。

    现在如果你需要打包文件只需要在终端里你运行webpack(非全局安装需使用node_modules/.bin/webpack)命令就可以了,这条命令会自动参考webpack.config.js文件中的配置选项打包你的项目,输出结果如下
    这里写图片描述

    又学会了一种使用Webpack的方法,而且不用管那烦人的命令行参数了,有没有感觉很爽。有没有想过如果可以连webpack(非全局安装需使用node_modules/.bin/webpack)这条命令都可以不用,那种感觉会不会更爽~,继续看下文。

    更快捷的执行打包任务

    执行类似于node_modules/.bin/webpack这样的命令其实是比较烦人且容易出错的,不过值得庆幸的是npm可以引导任务执行,对其进行配置后可以使用简单的npm start命令来代替这些繁琐的命令。在package.json中对npm的脚本部分进行相关设置即可,设置方法如下。

    {
      "name": "webpack-sample-project",
      "version": "1.0.0",
      "description": "Sample webpack project",
      "scripts": {
        "start": "webpack" //配置的地方就是这里啦,相当于把npm的start命令指向webpack命令
      },
      "author": "zhang",
      "license": "ISC",
      "devDependencies": {
        "webpack": "^1.12.9"
      }
    }

    注:package.json中的脚本部分已经默认在命令前添加了node_modules/.bin路径,所以无论是全局还是局部安装的Webpack,你都不需要写前面那指明详细的路径了。

    npm的start是一个特殊的脚本名称,它的特殊性表现在,在命令行中使用npm start就可以执行相关命令,如果对应的此脚本名称不是start,想要在命令行中运行时,需要这样用npm run {script name}如npm run build,以下是执行npm start后命令行的输出显示
    这里写图片描述
    现在只需要使用npm start就可以打包文件了,有没有觉得webpack也不过如此嘛,不过不要太小瞧Webpack,其强大的功能包含在其一系列可供配置的选项中,我们一项项来看。

    Webpack的强大功能

    生成Source Maps(使调试更容易)

    开发总是离不开调试,如果可以更加方便的调试当然就能提高开发效率,不过打包后的文件有时候你是不容易找到出错了的地方对应的源代码的位置的,Source Maps就是来帮我们解决这个问题的。
    通过简单的配置后,Webpack在打包时可以为我们生成的source maps,这为我们提供了一种对应编译文件和源文件的方法,使得编译后的代码可读性更高,也更容易调试。

    在webpack的配置文件中配置source maps,需要配置devtool,它有以下四种不同的配置选项,各具优缺点,描述如下:
    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选项具有相似的缺点;
    正如上表所述,上述选项由上到下打包速度越来越快,不过同时也具有越来越多的负面作用,较快的构建速度的后果就是对打包后的文件的的执行有一定影响。

    在学习阶段以及在小到中性的项目上,eval-source-map是一个很好的选项,不过记得只在开发阶段使用它,继续上面的例子,进行如下配置

    module.exports = {
      devtool: 'eval-source-map',//配置生成Source Maps,选择合适的选项
      entry:  __dirname + "/app/main.js",
      output: {
        path: __dirname + "/public",
        filename: "bundle.js"
      }
    }

    cheap-module-eval-source-map方法构建速度更快,但是不利于调试,推荐在大型项目考虑da时间成本是使用。

    使用webpack构建本地服务器

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

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

    devserver作为webpack配置选项中的一项,具有以下配置选项

    devserver配置选项 功能描述
    contentBase 默认webpack-dev-server会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录(本例设置到“public”目录)
    port 设置默认监听端口,如果省略,默认为”8080“
    inline 设置为true,当源文件改变时会自动刷新页面
    colors 设置为true,使终端输出的文件为彩色的
    historyApiFallback 在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html
    继续把这些命令加到webpack的配置文件中,现在的配置文件如下所示

    module.exports = {
      devtool: 'eval-source-map',
    
      entry:  __dirname + "/app/main.js",
      output: {
        path: __dirname + "/public",
        filename: "bundle.js"
      },
    
      devServer: {
        contentBase: "./public",//本地服务器所加载的页面所在的目录
        colors: true,//终端中输出结果为彩色
        historyApiFallback: true,//不跳转
        inline: true//实时刷新
      } 
    }

    Loaders

    鼎鼎大名的Loaders登场了!Loaders是webpack中最让人激动人心的功能之一了。通过使用不同的loader,webpack通过调用外部的脚本或工具可以对各种各样的格式的文件进行处理,比如说分析JSON文件并把它转换为JavaScript文件,或者说把下一代的JS文件(ES6,ES7)转换为现代浏览器可以识别的JS文件。或者说对React的开发而言,合适的Loaders可以把React的JSX文件转换为JS文件。

    Loaders需要单独安装并且需要在webpack.config.js下的modules关键字下进行配置,Loaders的配置选项包括以下几方面:
    test:一个匹配loaders所处理的文件的拓展名的正则表达式(必须)
    **loader:**loader的名称(必须)
    include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选);
    query:为loaders提供额外的设置选项(可选)
    继续上面的例子,我们把Greeter.js里的问候消息放在一个单独的JSON文件里,并通过合适的配置使Greeter.js可以读取该JSON文件的值,配置方法如下

    //安装可以装换JSON的loader
    npm install --save-dev json-loader
    module.exports = {
      devtool: 'eval-source-map',
    
      entry:  __dirname + "/app/main.js",
      output: {
        path: __dirname + "/public",
        filename: "bundle.js"
      },
    
      module: {//在配置文件里添加JSON loader
        loaders: [
          {
            test: /\.json$/,
            loader: "json"
          }
        ]
      },
    
      devServer: {
        contentBase: "./public",
        colors: true,
        historyApiFallback: true,
        inline: true
      }
    }

    创建带有问候信息的JSON文件(命名为config.json)

    //config.json
    {
      "greetText": "Hi there and greetings from JSON!"
    }

    更新后的Greeter.js

    var config = require('./config.json');
    
    module.exports = function() {
      var greet = document.createElement('div');
      greet.textContent = config.greetText;
      return greet;
    };

    Loaders很好,不过有的Loaders使用起来比较复杂,比如说Babel。

    Babel

    Babel其实是一个编译JavaScript的平台,它的强大之处表现在可以通过编译帮你达到以下目的:

    • 下一代的JavaScript标准(ES6,ES7),这些标准目前并未被当前的浏览器完全的支持;
    • 使用基于JavaScript进行了拓展的语言,比如React的JSX

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

    我们先来一次性安装这些依赖包

    // npm一次性安装多个依赖模块,模块之间用空格隔开
    npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react

    在webpack中配置Babel的方法如下

    module.exports = {
      devtool: 'eval-source-map',
    
      entry:  __dirname + "/app/main.js",
      output: {
        path: __dirname + "/public",
        filename: "bundle.js"
      },
    
      module: {
        loaders: [
          {
            test: /\.json$/,
            loader: "json"
          },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel',//在webpack的module部分的loaders里进行配置即可
            query: {
              presets: ['es2015','react']
            }
          }
        ]
      },
    
      devServer: {
        contentBase: "./public",
        colors: true,
        historyApiFallback: true,
        inline: true
      }
    }

    现在你的webpack的配置已经允许你使用ES6以及JSX的语法了。继续用上面的例子进行测试,不过这次我们会使用React,记得先安装 React 和 React-DOM

    npm install --save react react-dom

    使用ES6的语法,更新Greeter.js并返回一个React组件

    //Greeter,js
    import React, {Component} from 'react'
    import config from './config.json';
    
    class Greeter extends Component{
      render() {
        return (
          <div>
            {config.greetText}
          </div>
        );
      }
    }
    export default Greeter

    使用ES6的模块定义和渲染Greeter模块

    import React from 'react';
    import {render} from 'react-dom';
    import Greeter from './Greeter';
    
    render(<Greeter />, document.getElementById('root'));

    Babel的配置选项
    Babel其实可以完全在webpack.config.js中进行配置,但是考虑到babel具有非常多的配置选项,在单一的webpack.config.js文件中进行配置往往使得这个文件显得太复杂,因此一些开发者支持把babel的配置选项放在一个单独的名为 “.babelrc” 的配置文件中。我们现在的babel的配置并不算复杂,不过之后我们会再加一些东西,因此现在我们就提取出相关部分,分两个配置文件进行配置(webpack会自动调用.babelrc里的babel配置选项),如下:

    // webpack.config.js
    module.exports = {
      devtool: 'eval-source-map',
    
      entry:  __dirname + "/app/main.js",
      output: {
        path: __dirname + "/public",
        filename: "bundle.js"
      },
    
      module: {
        loaders: [
          {
            test: /\.json$/,
            loader: "json"
          },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel'
          }
        ]
      },
    
      devServer: {...} // Omitted for brevity
    }
    //.babelrc
    {
      "presets": ["react", "es2015"]
    }

    到目前为止,我们已经知道了,对于模块,Webpack能提供非常强大的处理功能,那那些是模块呢。

    一切皆模块

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

    CSS

    webpack提供两个工具处理样式表,css-loader 和 style-loader,二者处理的任务不同,css-loader使你能够使用类似@import 和 url(…)的方法实现 require()的功能,style-loader将所有的计算后的样式加入页面中,二者组合在一起使你能够把样式表嵌入webpack打包后的JS文件中。

    继续上面的例子

    //安装
    npm install --save-dev style-loader css-loader
    //使用
    module.exports = {
      devtool: 'eval-source-map',
    
      entry:  __dirname + "/app/main.js",
      output: {
        path: __dirname + "/build",
        filename: "bundle.js"
      },
    
      module: {
        loaders: [
          {
            test: /\.json$/,
            loader: "json"
          },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel'
          },
          {
            test: /\.css$/,
            loader: 'style!css'//添加对样式表的处理
          }
        ]
      },
    
      devServer: {...}
    }

    注:感叹号的作用在于使同一文件能够使用不同类型的loader

    接下来,在app文件夹里创建一个名字为”main.css”的文件,对一些元素设置样式

    html {
      box-sizing: border-box;
      -ms-text-size-adjust: 100%;
      -webkit-text-size-adjust: 100%;
    }
    
    *, *:before, *:after {
      box-sizing: inherit;
    }
    
    body {
      margin: 0;
      font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
    }
    
    h1, h2, h3, h4, h5, h6, p, ul {
      margin: 0;
      padding: 0;
    }

    你还记得吗?webpack只有单一的入口,其它的模块需要通过 import, require, url等导入相关位置,为了让webpack能找到”main.css“文件,我们把它导入”main.js “中,如下

    //main.js
    import React from 'react';
    import {render} from 'react-dom';
    import Greeter from './Greeter';
    
    import './main.css';//使用require导入css文件
    
    render(<Greeter />, document.getElementById('root'));

    通常情况下,css会和js打包到同一个文件中,并不会打包为一个单独的css文件,不过通过合适的配置webpack也可以把css打包为单独的文件的。
    不过这也只是webpack把css当做模块而已,咱们继续看看一个真的CSS模块的实践。

    CSS module

    在过去的一些年里,JavaScript通过一些新的语言特性,更好的工具以及更好的实践方法(比如说模块化)发展得非常迅速。模块使得开发者把复杂的代码转化为小的,干净的,依赖声明明确的单元,且基于优化工具,依赖管理和加载管理可以自动完成。
    不过前端的另外一部分,CSS发展就相对慢一些,大多的样式表却依旧是巨大且充满了全局类名,这使得维护和修改都非常困难和复杂。

    最近有一个叫做 CSS modules 的技术就意在把JS的模块化思想带入CSS中来,通过CSS模块,所有的类名,动画名默认都只作用于当前模块。Webpack从一开始就对CSS模块化提供了支持,在CSS loader中进行配置后,你所需要做的一切就是把”modules“传递都所需要的地方,然后就可以直接把CSS的类名传递到组件的代码中,且这样做只对当前组件有效,不必担心在不同的模块中具有相同的类名可能会造成的问题。具体的代码如下

    module.exports = {
      devtool: 'eval-source-map',
    
      entry:  __dirname + "/app/main.js",
      output: {...},
    
      module: {
        loaders: [
          {
            test: /\.json$/,
            loader: "json"
          },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel'
          },
          {
            test: /\.css$/,
            loader: 'style!css?modules'//跟前面相比就在后面加上了?modules
          }
        ]
      },
    
      devServer: {...}
    }

    创建一个Greeter.css文件

    .root {
      background-color: #eee;
      padding: 10px;
      border: 3px solid #ccc;
    }
    导入.root到Greeter.js中
    
    import React, {Component} from 'react';
    import config from './config.json';
    import styles from './Greeter.css';//导入
    
    class Greeter extends Component{
      render() {
        return (
          <div className={styles.root}>//添加类名
            {config.greetText}
          </div>
        );
      }
    }
    
    export default Greeter

    放心使用把,相同的类名也不会造成不同组件之间的污染。
    CSS modules 也是一个很大的主题,有兴趣的话可以去官方文档查看更多消息

    CSS预处理器

    Sass 和 Less之类的预处理器是对原生CSS的拓展,它们允许你使用类似于variables, nesting, mixins, inheritance等不存在于CSS中的特性来写CSS,CSS预处理器可以这些特殊类型的语句转化为浏览器可识别的CSS语句,
    你现在可能都已经熟悉了,在webpack里使用相关loaders进行配置就可以使用了,以下是常用的CSS 处理loaders

    • Less Loader
    • Sass Loader
    • Stylus Loader
      不过其实也存在一个CSS的处理平台-PostCSS,它可以帮助你的CSS实现更多的功能,在其CSS官方文档可了解更多相关知识。

    举例来说如何使用PostCSS,我们使用PostCSS来为CSS代码自动添加适应不同浏览器的CSS前缀。

    首先安装postcss-loader 和 autoprefixer(自动添加前缀的插件)

    npm install –save-dev postcss-loader autoprefixer
    接下来,在webpack配置文件中进行设置,只需要新建一个postcss关键字,并在里面申明依赖的插件,如下,现在你写的css会自动根据Can i use里的数据添加不同前缀了。

    //webpack配置文件
    module.exports = {
      devtool: 'eval-source-map',
      entry: __dirname + "/app/main.js",
      output: {...},
    
      module: {
        loaders: [
          {
            test: /\.json$/,
            loader: "json"
          },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel'
          },
          {
            test: /\.css$/,
            loader: 'style!css?modules!postcss'
          }
        ]
      },
    
      postcss: [
        require('autoprefixer')//调用autoprefixer插件
      ],
    
      devServer: {...}
    }

    到现在,本文已经涉及到处理JS的Babel和处理CSS的PostCSS,它们其实也是两个单独的平台,配合Webpack可以很好的发挥它们的作用。接下来介绍Webpack中另一个非常重要的功能-Plugins

    插件

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

    Webpack有很多内置插件,同时也有很多第三方插件,可以让我们完成更加丰富的功能。

    使用插件的方法
    要使用某个插件,我们需要通过npm安装它,然后要做的就是在webpack配置中的plugins关键字部分添加该插件的一个实例(plugins是一个数组)继续看例子,我们添加了一个实现版权声明的插件。

    //webpack.config.js
    var webpack = require('webpack');
    
    module.exports = {
      devtool: 'eval-source-map',
      entry:  __dirname + "/app/main.js",
      output: {...},
    
      module: {
        loaders: [
          { test: /\.json$/, loader: "json" },
          { test: /\.js$/, exclude: /node_modules/, loader: 'babel' },
          { test: /\.css$/, loader: 'style!css?modules!postcss' }//这里添加PostCSS
        ]
      },
      postcss: [
        require('autoprefixer')
      ],
    
      plugins: [
        new webpack.BannerPlugin("Copyright Flying Unicorns inc.")//在这个数组中new一个就可以了
      ],
    
      devServer: {...}
    }

    通过这个插件,打包后的JS文件显示如下

    bundled JavaScript file

    知道Webpack中的插件如何使用了,下面给大家推荐几个常用的插件

    HtmlWebpackPlugin

    这个插件的作用是依据一个简单的模板,帮你生成最终的Html5文件,这个文件中自动引用了你打包后的JS文件。每次编译都在文件名中插入一个不同的哈希值。

    安装

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

    这个插件自动完成了我们之前手动做的一些事情,在正式使用之前需要对一直以来的项目结构做一些改变:

    1. 移除public文件夹,利用此插件,HTML5文件会自动生成,此外CSS已经通过前面的操作打包到JS中了,public文件夹里。
    2. 在app目录下,创建一个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>
    1. 更新webpack的配置文件,方法同上,新建一个build文件夹用来存放最终的输出文件
    var webpack = require('webpack');
    var HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      devtool: 'eval-source-map',
    
      entry:  __dirname + "/app/main.js",
      output: {
        path: __dirname + "/build",
        filename: "bundle.js"
      },
    
      module: {
        loaders: [
          { test: /\.json$/, loader: "json" },
          { test: /\.js$/, exclude: /node_modules/, loader: 'babel' },
          { test: /\.css$/, loader: 'style!css?modules!postcss' }
        ]
      },
      postcss: [
        require('autoprefixer')
      ],
    
      plugins: [
        new HtmlWebpackPlugin({
          template: __dirname + "/app/index.tmpl.html"//new 一个这个插件的实例,并传入相关的参数
        })
      ],
    
      devServer: {
        colors: true,
        historyApiFallback: true,
        inline: true
      }
    }

    Hot Module Replacement

    Hot Module Replacement(HMR)也是webpack里很有用的一个插件,它允许你在修改组件代码后,自动刷新实时预览修改后的效果。
    在webpack中实现HMR也很简单,只需要做两项配置

    1. 在webpack配置文件中添加HMR插件;
    2. 在Webpack Dev Server中添加“hot”参数;

    不过配置完这些后,JS模块其实还是不能自动热加载的,还需要在你的JS模块中执行一个Webpack提供的API才能实现热加载,虽然这个API不难使用,但是如果是React模块,使用我们已经熟悉的Babel可以更方便的实现功能热加载。

    整理下我们的思路,具体实现方法如下

    • Babel和webpack是独立的工具
    • 二者可以一起工作
    • 二者都可以通过插件拓展功能
    • HMR是一个webpack插件,它让你能浏览器中实时观察模块修改后的效果,但是如果你想让它工作,需要对模块进行额外的配额;
    • Babel有一个叫做react-transform-hrm的插件,可以在不对React模块进行额外的配置的前提下让HMR正常工作;

    更新我们的例子来实际看看如何配置

    //webpack中的配置
    var webpack = require('webpack');
    var HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      devtool: 'eval-source-map',
      entry: __dirname + "/app/main.js",
      output: {
        path: __dirname + "/build",
        filename: "bundle.js"
      },
    
      module: {
        loaders: [
          { test: /\.json$/, loader: "json" },
          { test: /\.js$/, exclude: /node_modules/, loader: 'babel' },
          { test: /\.css$/, loader: 'style!css?modules!postcss' }
        ]
      },
      postcss: [
        require('autoprefixer')
      ],
    
      plugins: [
        new HtmlWebpackPlugin({
          template: __dirname + "/app/index.tmpl.html"
        }),
        new webpack.HotModuleReplacementPlugin()//热加载插件
      ],
    
      devServer: {
        colors: true,
        historyApiFallback: true,
        inline: true,
        hot: true
      }
    }

    安装react-transform-hmr

    npm install –save-dev babel-plugin-react-transform react-transform-hmr
    配置Babel

    {
      "presets": ["react", "es2015"],
      "env": {
        "development": {
        "plugins": [["react-transform", {
           "transforms": [{
             "transform": "react-transform-hmr",
    
             "imports": ["react"],
    
             "locals": ["module"]
           }]
         }]]
        }
      }
    }

    现在当你使用React时,可以热加载模块了

    产品阶段的构建

    目前为止,我们已经使用webpack构建了一个完整的开发环境。但是在产品阶段,可能还需要对打包的文件进行额外的处理,比如说优化,压缩,缓存以及分离CSS和JS。

    对于复杂的项目来说,需要复杂的配置,这时候分解配置文件为多个小的文件可以使得事情井井有条,以上面的例子来说,我们创建一个“webpack.production.config.js”的文件,在里面加上基本的配置,它和原始的webpack.config.js很像,如下

    var webpack = require('webpack');
    var HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      entry: __dirname + "/app/main.js",
      output: {
        path: __dirname + "/build",
        filename: "bundle.js"
      },
    
      module: {
        loaders: [
          {
            test: /\.json$/,
            loader: "json"
          },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel'
          },
          {
            test: /\.css$/,
            loader: 'style!css?modules!postcss'
          }
        ]
      },
      postcss: [
        require('autoprefixer')
      ],
    
      plugins: [
        new HtmlWebpackPlugin({
          template: __dirname + "/app/index.tmpl.html"
        }),
      ],
    
    }
    //package.json
    {
      "name": "webpack-sample-project",
      "version": "1.0.0",
      "description": "Sample webpack project",
      "scripts": {
        "start": "webpack-dev-server --progress",
        "build": "NODE_ENV=production webpack --config ./webpack.production.config.js --progress"
      },
      "author": "Cássio Zen",
      "license": "ISC",
      "devDependencies": {...},
      "dependencies": {...}
    }

    优化插件

    webpack提供了一些在发布阶段非常有用的优化插件,它们大多来自于webpack社区,可以通过npm安装,通过以下插件可以完成产品发布阶段所需的功能

    OccurenceOrderPlugin :为组件分配ID,通过这个插件webpack可以分析和优先考虑使用最多的模块,并为它们分配最小的ID
    UglifyJsPlugin:压缩JS代码;
    ExtractTextPlugin:分离CSS和JS文件
    我们继续用例子来看看如何添加它们,OccurenceOrder 和 UglifyJS plugins 都是内置插件,你需要做的只是安装它们

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

    在配置文件的plugins后引用它们

    var webpack = require('webpack');
    var HtmlWebpackPlugin = require('html-webpack-plugin');
    var ExtractTextPlugin = require('extract-text-webpack-plugin');
    
    module.exports = {
      entry: __dirname + "/app/main.js",
      output: {
        path: __dirname + "/build",
        filename: "bundle.js"
      },
    
      module: {
        loaders: [
          {
            test: /\.json$/,
            loader: "json"
          },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel'
          },
          {
            test: /\.css$/,
            loader: ExtractTextPlugin.extract('style', 'css?modules!postcss')
          }
        ]
      },
      postcss: [
        require('autoprefixer')
      ],
    
      plugins: [
        new HtmlWebpackPlugin({
          template: __dirname + "/app/index.tmpl.html"
        }),
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.optimize.UglifyJsPlugin(),
        new ExtractTextPlugin("style.css")
      ]
    }

    缓存

    缓存无处不在,使用缓存的最好方法是保证你的文件名和文件内容是匹配的(内容改变,名称相应改变)

    webpack可以把一个哈希值添加到打包的文件名中,使用方法如下,添加特殊的字符串混合体([name], [id] and [hash])到输出文件名前

    var webpack = require('webpack');
    var HtmlWebpackPlugin = require('html-webpack-plugin');
    var ExtractTextPlugin = require('extract-text-webpack-plugin');
    
    module.exports = {
      entry: __dirname + "/app/main.js",
      output: {
        path: __dirname + "/build",
        filename: "[name]-[hash].js"
      },
    
      module: {
        loaders: [
          {
            test: /\.json$/,
            loader: "json"
          },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel'
          },
          {
            test: /\.css$/,
            loader: ExtractTextPlugin.extract('style', 'css?modules!postcss')
          }
        ]
      },
      postcss: [
        require('autoprefixer')
      ],
    
      plugins: [
        new HtmlWebpackPlugin({
          template: __dirname + "/app/index.tmpl.html"
        }),
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.optimize.UglifyJsPlugin(),
        new ExtractTextPlugin("[name]-[hash].css")
      ]
    }

    现在用户会有合理的缓存了。

    总结

    这是一篇好长的文章,谢谢你的耐心,能仔细看到了这里,大概半个月前我第一次自己一步步配置项目所需的Webpack后就一直想写一篇笔记做总结,几次动笔都不能让自己满意,总觉得写不清楚。直到看到本文的英文版Webpack for React,真的有多次豁然开朗的感觉,喜欢看原文的点链接就可以看了。其实关于Webpack本文讲述得仍不完全,不过相信你看完后已经进入Webpack的大门,能够更好的探索其它的关于Webpack的知识了。

    本文有修改,参考自简书作者zhangwang,原文链接:http://www.jianshu.com/p/42e11515c10f

    展开全文
  • 在本课程中,首先介绍了webpack打包工具的基础知识,安装过程,然后介绍工具如何打包第三方插件、打包样式的方法,后,介绍打包工具的配置,并详细介绍如何将项目部署到服务端的全部流程。
  • webpack

    2019-11-11 19:06:33
    什么是webpack? 为什么在 vue 中使用 npm run build 命令就可以把开发环境中的文件进行合并? 无论是 vue 还是 react、angular,使用 cli 创建出来的项目,都自动的把结构做好了,内部的 webpack 也都配置好了,...
  • webpack从零开始

    2020-10-12 16:52:06
    首先配置webpack webpack.config.js const path = require('path') module.exports = { entry:'./src/main.js', output:{ path:path.resolve(__dirname,'dist'), filename:'bundle.js' }, } 命令行npm init...
  • webpack初始化配置 (史上最详细版本)

    千次阅读 2018-11-18 22:00:18
    webpack官网: https://www.webpackjs.com/ 注意:因为webpack一些插件总是不断更新,所以在以后的...webpack 是前端的一个项目构建工具,它是基于 Node.js 开发出来的一个前端工具,借助于webpack这个前端自动化构建...
  • webpack基本用法

    千次阅读 2018-09-02 11:02:04
    网页中常见的静态资源: JS:.js .jsx .coffee .ts(TypeScript 类c#语言) CSS:.css .less .sass .scss Images:.jpg .jpeg .png .gif .bmp 字体文件(Fonts): .svg .ttf .eot .woff .woff2 ...
  • 什么是 webpack 以及 其作用?

    千次阅读 2019-06-15 14:02:18
    1.理解什么是webpack。 上网搜索的直接解释是: 模块化打包机 或者 模块打包工具。 **首先**,认为它是一个工具,帮助我们更好的处理事情的。 **其次**,“打包”,如何理解? 假设我们需要寄快递。我们将许多的...
  • 什么是 webpackwebpack是近期最火的一款模块加载器兼打包工具,它能把各种资源,例如JS(含JSX)、coffee、样式(含less/sass)、图片等都作为模块来使用和处理。 我们可以直接使用 require(XXX) 的形式来...
  • Gulp与WebPack有区别吗?如果有,有什么区别?

    千次阅读 多人点赞 2020-03-22 12:33:23
    Gulp与webpack有区别吗?如果有,有什么区别? 可以这么说,它们既有区别,也有相似… 先来具体看一下它们不同的概念: (1)Gulp:        Gulp是一个自动化构建工具,强调的是...
  • 如上图所示,这就是依赖包出问题了,我们把所有依赖删掉重新下载即可,找到项目所在的文件夹,删掉node_modules文件夹,然后运行npm install 初始化项目重新下载依赖,再次npm run dev项目就可以运行起来了 ...
  • 查看webpack版本

    万次阅读 2019-02-09 17:10:45
    1,npm info webpack   2,webpack -v 如果没有出现,npm install --global webpack-cli,因为 注意:webpack 4x以上,webpack将命令相关的内容都放到了webpack-cli,所以还需要安装webpack-cli; 之后再...
  • 一、问题描述在安装webpack时,输入webpack -v提示我需要安装webpack-cli,如图:二、解决因为在webpack 3中,webpack本身和它的CLI以前都是在同一个包中,但在第4版中,他们已经将两者分开来更好地管理它们。...
  • webpackwebpack-cli要求是要全局安装,如果需要使用uglifyjs-webpack-plugin插件压缩js, 则需要项目内安装webpackwebpack-cli, 且项目名称不能为"webpack", npm install -D webpack-cli ...
  • 安装的webpack版本是4.9.1,webpack-cli版本号是2.1.4。运行webpack命令提示: One CLI for webpack must be installed. These are recommended choices, delivered as separate packages: webpack-cli ...
  • 直接按照提示安装 提示Module webpack-cli 不存在 One CLI for webpack must be installed. These are recommended choices, delivered as separate packages: - webpack-cli (https://github...
  • 完全卸载webpack,再重新安装

    万次阅读 2018-05-16 08:57:20
    1.安装 在全局下安装:npm install webpack -g 安装指定版本:npm install webpack@&lt;version&gt; -g 例如:npm install webpack@3.4.1 -g 如果只是用来练习全局安装就可以了,一开始装了个...
  • 指定安装webpack3.0.0版

    千次阅读 2018-05-29 17:42:48
    npm install webpack@3.0.0 -g
1 2 3 4 5 ... 20
收藏数 127,529
精华内容 51,011
关键字:

webpack