webpack入门

本文大多整理于入门Webpack,看这篇就够了以及webpack源码分析,本文以两篇文章为基础,做了一定整理

什么是webpack?

如果你看到这篇文章,那你八成知道了它的主要功能——打包器

但是

为什么要打包呢?
  • 压缩,打包后,文件会明细的减少体积
  • 模块整合,把你五花八门的应用整合为依赖关系图
不止打包
除了打包这一主要功能,webpack还衍生出了其他功能,比如
  • 其他语言的转译,比如less
  • 特定写法的转译,比如Es6
  • 一切皆模块,css的font和图片都可以被正确的处理
  • 本地服务器,包括热加载
  • 强大的插件,可以达成很多的特别的需求,比如js文件中嵌入版权声明
或许webpack马上就过时了?
HTTP2协议马上就要到应用阶段了,届时,请求更快,请求上限的锁也会被解除,性能提升的情况下,webpack还是必要的吗?我认为它仍是必要的,毕竟就算HTTP2被应用了,服务器和客户端的性能并不会在短时间有质变。一个合理的整合工具还是必要的。就像这位同仁的见解: What is the value of using Webpack with HTTP/2

以上观点,欢迎评论讨论
那么现在

开始

安装
//全局安装
npm install -g webpack
//安装到你的项目目录
npm install --save-dev webpack
简单配置
webpack会自动寻找webpack.config.js文件,你需要建立一个,然后填充以下内容:
module.exports = {
  entry:  __dirname + "/app/main.js",//已多次提及的唯一入口文件
  output: {
    path: __dirname + "/public",//打包后的文件存放的地方
    filename: "bundle.js"//打包后输出文件的文件名
  }
}
其中 entry为入口文件,也就是未打包的、你项目的入口js文件;
而后output为打包后的文件,也就是生成的js文件存放的位置及名称。
其中__dirname为当前位置的意思
打包
命令行直接通过webpack打包
# {extry file}出填写入口文件的路径
# {destination for bundled file}处填写打包文件的存放路径
# 填写路径的时候不用添加{}
webpack {entry file} {destination for bundled file}
以上方法不通过webpack.config.js也可以进行,但不推荐,如果你进行了配置,只需要在目录
webpack(非全局安装需使用node_modules/.bin/webpack)
通过npm进行更快捷打包(不了解npm? npm
首先进行package.json的配置
{
  "name": "webpack-sample-project",
  "version": "1.0.0",
  "description": "Sample webpack project",
  "scripts": {
    "start": "webpack",
    "pack": "webpack"
  },
  "author": "zhang",
  "license": "ISC",
  "devDependencies": {
    "webpack": "3.10.0"
  }
}


然后你就可以
npm start
来进行打包了,这里其实只是给了npm一个快捷命令,npm start一定程度上与webpack命令相同,只不过可能在寻找执行程序上更为智能(毕竟是npm自己装的)
还有一个需要注意的点是在以上配置中,只有start是可以直接 npm start的,其他命令(比如pack)都需要使用
npm run pack
来进行(难道是npm把start写死了?这么酷炫?)
那么,基本的webpack基本的使用就结束了,但是如果只是这样使用价值不高,下面进行

真正的入门

开发相关
搭建本地服务器webpack-dev-server
先安装
npm install --save-dev webpack-dev-server
再配置(更改webpack.config.js文件)
module.exports = {
  devtool: 'eval-source-map',
  entry:  __dirname + "/app/main.js",
  output: {
    path: __dirname + "/public",
    filename: "bundle.js"
  },

  devServer: {
    contentBase: "./public",//本地服务器所加载的页面所在的目录
    historyApiFallback: true,//无论地址栏输入什么,都指向index.html,for单页面应用
    inline: true,//保存后自动刷新
    port: "8080"//localhost:xxx的端口号,一般不需要指定,此项不写默认8080
  } 
}


最后运行
webpack-dev-server --open
猜猜--open是什么意思,嗯,就是会打开一个新页面/标签页。
也可以配置在package.json,这样更为简便

"scripts": {
    "start": "webpack",
    "dev": "webpack-dev-server --open"
  },
记得要
npm run dev

并且,要注意的是,自动打包不会将新的webpack配置涵盖在内,如果你修改了配置,记得手动重新打包

使用source maps
这是一项配置,不需要安装,能在打包后,依然能找出是哪个文件出了bug
在webpack.config.js中进行配置如下

module.exports = {
  devtool: 'eval-source-map',
  entry:  __dirname + "/app/main.js",
  output: {
    path: __dirname + "/public",
    filename: "bundle.js"
  }
}
其中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选项具有相似的缺点;
因为会影响性能,又会被别人发现你的目录结构,记得上线时要去掉,现在记在小本本上
实用的功能
loaders
顾名思义,loaders根据相应文件的文件进行特别的加载和转译,如ES6转兼容性js,less转CSS等等,可以说是非常实用的。
一些js的转译(编译)需要Babel,既要配置loaders,又要安装相应Babel
先安装一些Babel
// npm一次性安装多个依赖模块,模块之间用空格隔开
npm install --save-dev babel-core babel-loader babel-preset-env babel-preset-react
babel-core:babel的核心模块
babel-loader:loader与babel的连接模块
babel-preset-env:ES6->ES5的转译模块
babel-preset-react:react插件转译模块,为什么不直接叫babel-preset-jsx呢,who knows

然后进行loader配置,在webpack.config.js文件中
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/
            }
        ]
    }
};
这个配置表示要怎样的preset
这样就你就可以自由的写ES6和JSX了,可以自己试验一下
css modules
如今流行的是模块式开发,但是css这位大佬明显没能跟上浪潮
一个主页面的.title显然要和弹出框的.title有不同的样式。但是如果我们直接引入几个.css文件显然就会冲突,而区分命名还会徒增工作量,也有悖于模块化思想。
于是就有了这个css modules
其实解决方式很简单,它会给你的类名等等加上一串与所在文件相关的哈希字符串,这样,就不会冲突了,每个模块的.title都将拥有自己的名称

直接配置在webpack.config.js
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/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true, // 指定启用css modules
                            localIdentName: '[name]__[local]--[hash:base64:5]' // 指定css的类名格式
                        }
                    }
                ]
            }
        ]
    }
};
不过要想真正生效,你需要这样写(ES6):
import styles from './Greeter.css';
className={styles['title']}
如果你想直接引入,比如你想用css来微调UI框架的一些样式,可以直接:

import './Greeter.css';
不过这种样式会在文件被引入后持续生效,影响子组件,请谨慎使用
CSS预处理器(.less等)
.less这种文件对复杂的样式编写起来会很有逻辑,也会减少一定的代码量。详情请自行搜索,总之又是对CSS的一波嘲讽,不多说,安装:
npm install --save-dev postcss-loader autoprefixer
postcss-loader:处理CSS与PostCSS的模块
autoprefixer: 自动添加前缀的插件

配置webpack.config.js
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/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true, // 指定启用css modules
                            localIdentName: '[name]__[local]--[hash:base64:5]' // 指定css的类名格式
                        }
                    }, {
                        loader: "postcss-loader"
                    }
                ]
            }
        ]
    }
};
新建个postcss的配置文件postcss.config.css
// postcss.config.js
module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}
放心,会自动引用的
Plugins(插件)
如果说loaders是来幼儿园找孩子的妈妈,那plugins就是幼儿园的管理老师,它雨露均沾,一般不会区分什么文件。(这样说不会混了吧)

先来个不用安装的webpack内置插件试一下,直接配置:
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/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true, // 指定启用css modules
                            localIdentName: '[name]__[local]--[hash:base64:5]' // 指定css的类名格式
                        }
                    }, {
                        loader: "postcss-loader"
                    }
                ]
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin('版权所有,翻版必究')
    ],
};
这个插件能让打包后的js文件有一个'版权所有'的注释,或者你也可以写上其他吓吓小朋友的词句。
接下来重量级登场了,一个应用很频繁的插件
热加载
虽然webpack内置了热加载模块,不过webpack的热加载模块通常需要相关Babel配合
比如React就需要react-tarnsform-hrm,我们先安装它
npm install --save-dev babel-plugin-react-transform react-transform-hmr
然后进行配置,考虑到Babel的配置越来越多了,我们新建一个会被自动引用的.babelrc来专门配置Babel
// .babelrc
{
  "presets": ["react", "env"],
  "env": {
    "development": {
    "plugins": [["react-transform", {
       "transforms": [{
         "transform": "react-transform-hmr",
         
         "imports": ["react"],
         
         "locals": ["module"]
       }]
     }]]
    }
  }
}
然后修改主配置文件webpack.config.js
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"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true, // 指定启用css modules
                            localIdentName: '[name]__[local]--[hash:base64:5]' // 指定css的类名格式
                        }
                    }, {
                        loader: "postcss-loader"
                    }
                ]
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin('版权所有,翻版必究'),
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html"//new 一个这个插件的实例,并传入相关的参数,这里为一个基础html文件
        }),
        new webpack.HotModuleReplacementPlugin()//热加载插件
    ]
};
这样就会热加载了
压缩
压缩需要多项配置来进行,最先要做的就是把刚才记在小本本上的devtool的值改为'null'
然后再配置中的plugins项中加入
new webpack.optimize.UglifyJsPlugin(),
暂时入门内容就到这里,楼主会随着学习的深入进行更新,欢迎讨论



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值