摘要:配置完成后就可以使用来打包代码了。值得注意的是会删除所有无作用代码也就是说那些包裹在这些全局变量下的代码块都会被删除这样就能保证这些代码不会因发布上线而泄露。默认会从项目的根目录下引入这些文件。
命令使用
npm install webpack -g 作为全局安装, 在任意目录使用 npm install webpack --save-dev 作为项目依赖安装 npm init 创建package.json npm install webpack-dev-server --save-dev 使用webpack-dev-server启动服务器 webpack --progress -colors 让编译的输出内容带有进度和颜色 webpack --watch 如果不想每次修改模块后都重新编译, 那么可以启动监听模式。 开启监听模式后, 没有变化的模块会在编译后缓存到内存中, 而不会每次都被重新编译, 所以监听模式的整体速度是很快的 webpack --display-error-details 用来打印错误详情 npm install xxx-loader --save-dev 安装多个加载器: npm install babel-core babel-preset-es2015 babel-preset-react npm webpack --config webpack.config.js 执行打包命令 npm start 启动开发模式下的server npm run start:prod 启动生产模式的server npm run build 打包生产模式的代码 npm run lint: eslint 代码检查 npm run lint:watch: eslint 监视 npm run remove:build 删除dist目录 npm run clean:build 清除dist目录 // 调用webpack webpack 开发环境下编译 webpack -p 产品编译及压缩 webpack --watch 开发环境下持续的监听文件变动来进行编译 webpack -d 引入source maps配置文件
webpack.config.dev.js: 开发模式相关配置 webpack.config.prod.js: 生产模式相关配置 server.js: 配置本地的server(包含dev server和prod server) 将server部分分离到一个多带带到的文件配置 package.json
//webpack.config.dev.js var webpack = require("webpack"); var path = require("path"); var config = { // 入口文件配置 entry: { path.resolve(__dirname, "app/index.js"); }, // 文件输出配置 output: { path: path.resolve(_dirname, "build"), filename: "bundle.js", publicPath: "/" }, // 插件项 plugins: [], // 加载器配置 module: { loaders: [ { test: /pattern/, loader: "xxx-loader", exclude: /dir/, query: { presets: ["react"] } }, { test: /.(png|jpg)$/, loader: "url-loader?limit=8192" // 内联的base64的图片地址, 图片要小于8k, 直接的url的地址则不解析 } ] }, // 其他解决方案配置 resolve: { extensions: ["", ".js", ".json"], alias: {} }, watch: true }; module.exports = config;
webpack.server.js var webpack = require("webpack"); var webpackServer = require("webpack-dev-server"); var config = require("./webpack.config.dev.js"); var compiler = webpack(config); var server = new webpackDevServer(compiler, { contentBase: "./app", historyApiFallback: true, hot: true, //热启动 inline: true, // 监控js变化 stats: { color: true } }); config.entry.unshift("webpack-dev-server/client?http://localhost:8080/", "webpack/hot/dev-server"); server.listen(8080, "localhost", function(err) { if(err) { console.log(err); } console.log("Listening at localhost:8080..."); }); "script": { "start": "node server.js" }配置详解
entry: 入口, 定义要打包的文件 output: 出口, 定义打包输出的文件;包括路径, 文件名,还可能有运行时的访问路径(publicPath)参数 module: webpack将所有的资源都看做是模块, 而模块就需要加载器; |---- loaders: 主要定义一些loaders, 定义哪些后缀名的文件应该用哪些loader |-------- test: 匹配文件后缀, 检测哪些文件需要此loader, 是一个正则表达式 |-------- exclude: 忽略哪些文件 |-------- query: 参数 (或直接写于loader如: loader: "url-loader?limit=8192") |------------ presets: resolve: 其他解决方案配置 |---- extensions: 忽略文件扩展名, require文件时可直接使用require("file"),而非带后缀如require("file.js") |-------- alias: 模块别名定义,方便后续直接饮用别名无需多写长地址, 后续直接require(key) plugins: 定义一些额外的插件 watch: 值为boolean, 监听文件变化配置生产环境
开发环境: webpack.config.dev.js 需要日志输出, sourcemap, 错误报告等 生产环境: webpack.config.prod.js 需要做代码压缩, 对文件名进行hash处理等区分环境
使用DefinePlugin设置环境变量, 根据设置的环境变量决定是否打包压缩及启动dev server或prod server
plugins: [ new webpack.DefinePlugin({ "process.evn.NODE_ENV": JSON.stringify("production") }); ]
判断当前是否是生产环境
var isProduction = function() { return process.env.NODE_ENV === "production"; } output: { path: path.resolve(isProduction ? "__build" : "./assets/"), filename: isProduction ? "[name].js" : "./assets/js/[chunkhash:8].[name].min.js", chunkFilename: isProduction ? "[chunkhash:8].chunk.js" : "./assets/js/[chunkhash:8].chunk.min.js", publicPath: isProduction ? "/__build/" : "http://cdn.site.com/" }代码压缩
new webpack.optimizeUglifyJsPlugin({ compress: { warnings: false } });添加Hash缓存
对于没有修改的文件, 从缓存中获取文件, 对于已经修改的文件, 不要从缓存中获取
output: { //chunkhash 默认16位, 可自定义配置 filename: "[chunkhash:8].bundle.js" }自动生成页面
文件名带上hash值后, 这个值在每次编译的时候都会发生变化,都需要在 html 文件里手动修改引用的文件名,这种重复工作很琐碎且容易出错, 这里我们可以使用 html-webpack-plugin 来帮我们自动处理这件事情, 用来简化创建服务于webpackbundle的HTML文件
解决方案: 在项目目录下建一个index.tpl.html作为钩子
My APP
在webpack.config.dev.js和webpack.config.prod.js添加配置代码, 即可生成相应的index.html
plugins: [ new HtmlWebpackPlugin({ template: "app/index.tpl.html", inject: "body", filename: index.html }) ]加载器 js处理
babel-loader: 转换JSX babel-core: babel核心包 babel-preset-react babel-preset-es2015
loaders:[ { loaders: "xxx-loader", query: { resets:["react", "es2015"] } } ]css处理
style-loader css-loader less-loaderimg处理
url-loader 可以根据自定义文件大小或者转化为 base64 格式的 dataUrl, 或者多带带作为文件, 也可以自定义对应的hash 文件名 file-loader 默认情况下会根据图片生成对应的 MD5hash 的文件格式 image-webpack-loader 提供压缩图片的功能
加载babel-loader需要配置query参数
loaders:[ { test: /.(jpe?g|png|gif|svg)$/i, loaders: [ // 当内容size小于8KB时, 会自动转成base64的方式内嵌进去, 这样可以减少一个HTTP的请求 // 当图片大于8KB时, 则会在img/下生成压缩后的图片, 命名是[hash:8].[name].[ext]的形式 // hash:8的意思是取图片内容hashsum值的前8位, // 这样做能够保证引用的是图片资源的最新修改版本, 保证浏览器端能够即时更新 "url?limit=8192&name=img/[hash:8].[name].[ext]", // 图片压缩 "image-webpack" ] } ]
loaders:[ { test: /.(jpe?g|png|gif|svg)$/i, loaders: [ // 生成md5 hash格式的文件名 "file?hash=sha512&digest=hex&name=[hash].[ext]", // 图片压缩 "image-webpack" ] } ]插件
plugins: [definPlugin, bannerPlugin, uglifyJsPlugin...]设置环境变量
var definPlugin = new webpack.DefinePlugin({ "process.env": { NODE_ENV: JSON.stringify("production") } // feature flags: 在开发环境(例如日志)活内部测试环境(例如没有发布的新功能)中使用 // __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || "true")), // __PRERELEASE__: JSON.stringify(JSON.parse(process.env.BUILD_PRERELEASE || "false")) });给输出的文件头部添加注释信息
var bannerPlugin = new webpack.BannerPlugin("This is test!");JS混淆
var uglifyJsPlugin = new webpack.optimize.UglifyJsPlugin({ mangle: { // 配置以下列表, 在混淆代码时, 以下配置的变量, 不会被混淆 except: ["$super", "$", "exports", "require"] } });压缩JS
var minChunkSizePlugin = new webpack.optimize.MinChunkSizePlugin({ compress: { warnings: false } });压缩React
var definPlugin = new webpack.DefinePlugin({ "process.env": { NODE_ENV: JSON.stringify("production") } });加载jQuery
new webpack.ProvidePlugin({ $: "jquery" });公共模块提取
new webpack.optimize.CommonsChunkPlugin({ name: "vendors", // 将公共模块提取, 生成名为`vendors`的chunk chunks: ["index","list","about"], //提取哪些模块共有的部分 minChunks: 3 // 提取至少3个模块共有的部分 });多带带使用link标签加载css并设置路径
new ExtractTextPlugin("css/[name].css"), // 相对于output配置中的publickPath自动生成html文件, 模板生成的相关配置, 每个对于一个页面的配置, 有几个写几个
new HtmlWebpackPlugin({ //根据模板插入css/js等生成最终HTML favicon: "./src/img/favicon.ico", //favicon路径, 通过webpack引入同时可以生成hash值 filename: "./view/index.html", //生成的html存放路径, 相对于path template: "./src/view/index.html", //html模板路径 inject: "body", //js插入的位置, true/"head"/"body"/false hash: true, //为静态资源生成hash值 chunks: ["vendors", "index"], //需要引入的chunk, 不配置就会引入所有页面的资源 minify: { //压缩HTML文件 removeComments: true, //移除HTML中的注释 collapseWhitespace: false //删除空白符与换行符 } });
new HtmlWebpackPlugin({ //根据模板插入css/js等生成最终HTML favicon: "./src/img/favicon.ico", //favicon路径, 通过webpack引入同时可以生成hash值 filename: "./view/list.html", //生成的html存放路径, 相对于path template: "./src/view/list.html", //html模板路径 inject: true, //js插入的位置, true/"head"/"body"/false hash: true, //为静态资源生成hash值 chunks: ["vendors", "list"], //需要引入的chunk, 不配置就会引入所有页面的资源 minify: { //压缩HTML文件 removeComments: true, //移除HTML中的注释 collapseWhitespace: false //删除空白符与换行符 } });其它插件
new webpack.HotModuleReplacementPlugin() // 热加载 HotModuleReplacementPlugin() // 代码热替换 NoErrorsPlugin() // 报错但不退出webpack进程 OpenBrowserPlugin() // 自动打开浏览器webpack使用 分析多个模块的公用代码提取并多带带打包
var commonsPlugin = new webpack.optimize.CommonsChunkPlugin("common.js"); module.exports = { entry: { page1: "./main1.js", page2: "./main2.js" }, output: { path: "build", filename: "[name].js" }, plugins: [ commonsPlugin ] }文件引用忽略扩展名配置
如果你希望在require文件时省略文件的扩展名, 只需要在webpack.config.js中添加 resolve.extensions 来配置。
// webpack.config.js module.exports = { entry: "./main.js", output: { filename: "bundle.js" }, module: { loaders: [ { test: /.coffee$/, loader: "coffee-loader" }, { test: /.js$/, loader: "babel-loader", query: { presets: ["es2015", "react"] } } ] }, resolve: { // 现在你require文件的时候可以直接使用require("file"), 不用使用require("file.coffee") extensions: ["", ".js", ".json", ".coffee"] } };css样式和图片的加载
首先你需要用require()去加载你的静态资源(named as they would with node"s require()):
require("./bootstrap.css"); require("./myapp.less"); var img = document.createElement("img"); img.src = require("./glyph.png");
当你require了CSS(less或者其他)文件, webpack会在页面中插入一个内联的, 去引入样式。当require图片的时候, bundle文件会包含图片的url, 并通过require()返回图片的url。
但是这需要你在webpack.config.js做相应的配置(这里还是使用loaders)
// webpack.config.js module.exports = { entry: "./main.js", output: { path: "./build", // 图片和js会放在这 publicPath: "http://mycdn.com/", // 这里用来生成图片的地址 filename: "bundle.js" }, module: { loaders: [ { test: /.less$/, loader: "style-loader!css-loader!less-loader" }, // 用!去链式调用loader { test: /.css$/, loader: "style-loader!css-loader" }, { test: /.(png|jpg)$/, loader: "url-loader?limit=8192" // 内联的base64的图片地址, 图片要小于8k, 直接的url的地址则不解析 } ] } };功能标识(Feature flags)
项目中有些代码我们只为在开发环境(例如日志)或者是内部测试环境(例如那些没有发布的新功能)中使用, 那就需要引入下面这些魔法全局变量(magic globals):
if (__DEV__) { console.warn("Extra logging"); } // ... if (__PRERELEASE__) { showSecretFeature(); }
同时还要在webpack.config.js中配置这些变量, 使得webpack能够识别他们。
// webpack.config.js // definePlugin 会把定义的string 变量插入到Js代码中。 var definePlugin = new webpack.DefinePlugin({ __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || "true")), __PRERELEASE__: JSON.stringify(JSON.parse(process.env.BUILD_PRERELEASE || "false")) }); module.exports = { entry: "./main.js", output: { filename: "bundle.js" }, plugins: [definePlugin] };
配置完成后, 就可以使用 BUILD_DEV=1 BUILD_PRERELEASE=1 webpack来打包代码了。
值得注意的是, webpack -p 会删除所有无作用代码, 也就是说那些包裹在这些全局变量下的代码块都会被删除, 这样就能保证这些代码不会因发布上线而泄露。
如果你有两个页面:profile和feed。如果你希望用户访问profile页面时不加载feed页面的代码, 那就需要生成多个bundles文件:为每个页面创建自己的“main module”(入口文件)。
// webpack.config.js module.exports = { entry: { Profile: "./profile.js", Feed: "./feed.js" }, output: { path: "build", filename: "[name].js" // name是基于上边entry中定义的key } };
在profile页面中插入。feed也一样。
优化通用代码Feed和Profile页面存在大量通用代码(比如React、公共的样式和组件等等)。webpack可以抽离页面间公共的代码, 生成一个公共的bundle文件, 供这两个页面缓存使用:
// webpack.config.js var webpack = require("webpack"); var commonsPlugin = new webpack.optimize.CommonsChunkPlugin("common.js"); // 引入插件 module.exports = { entry: { Profile: "./profile.js", Feed: "./feed.js" }, output: { path: "build", filename: "[name].js" // 为上面entry的key值 }, plugins: [commonsPlugin] };
在上一步引入自己的bundle之前引入
异步加载虽然CommonJS是同步加载的, 但是webpack也提供了异步加载的方式。这对于单页应用中使用的客户端路由非常有用。当真正路由到了某个页面的时候, 它的代码才会被加载下来。
指定你要异步加载的 拆分点。看下面的例子
if (window.location.pathname === "/feed") { showLoadingState(); require.ensure([], function() { // 这个语法痕奇怪, 但是还是可以起作用的 hideLoadingState(); require("./feed").show(); // 当这个函数被调用的时候, 此模块是一定已经被同步加载下来了 }); } else if (window.location.pathname === "/profile") { showLoadingState(); require.ensure([], function() { hideLoadingState(); require("./profile").show(); }); }
剩下的事就可以交给webpack, 它会为你生成并加载这些额外的 chunk 文件。
webpack 默认会从项目的根目录下引入这些chunk文件。你也可以通过 output.publicPath来配置chunk文件的引入路径
// webpack.config.js output: { path: "/home/proj/public/assets", // webpack的build路径 publicPath: "/assets/" // 你require的路径 }
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/85847.html
摘要:引言最近在学习,发现好多知识点,之前一点都没有接触过,如等等。使用本地安装,会存于文件夹内与属性内,更方便项目文件迁移以及协同开发等情况。 引言 最近在学习webpack,发现好多知识点,之前一点都没有接触过,如babel、core-js、browserslist等等。以前习惯了使用cli构建项目,很多东西不用考虑,拿来就用,这样的码农是不会有能力提升的,必须了解更多的知识点,才能成为...
摘要:新搭建的个人博客,本文地址学习笔记环境搭建本文的书写环境为,之后会补充下的差异创建学习目录初始化项目根据相关提示完善信息,入口文件安装相关包,并且使用也就是支持,需要包,因为我之前做个一些相关项目,所以部分包已经全局安装,比如等等,大家 新搭建的个人博客,本文地址:React学习笔记1:环境搭建 本文的书写环境为mac,之后会补充windows下的差异 1、创建学习目录 mkdir l...
摘要:前言在上一篇文章中我介绍了学习前的准备工作,下面开始的学习。目标一般我们接触到的关于的文章,都是以解读官方文档为主,而且是针对单页面项目的应用。我先在假设要做一个多页面应用,该如何去通过打包。 前言 在上一篇文章中我介绍了学习webpack前的准备工作,下面开始webpack的学习。 *创建webpack-demo文件夹 $ mkdir webpack-demo $ cd webpac...
摘要:前言在上一篇文章中我介绍了学习前的准备工作,下面开始的学习。目标一般我们接触到的关于的文章,都是以解读官方文档为主,而且是针对单页面项目的应用。我先在假设要做一个多页面应用,该如何去通过打包。 前言 在上一篇文章中我介绍了学习webpack前的准备工作,下面开始webpack的学习。 *创建webpack-demo文件夹 $ mkdir webpack-demo $ cd webpac...
摘要:运行该语句会执行如下步骤使用进行文件压缩。设置环境变量,触发某些包,以不同的方式进行编译。在原始的源码中执行查找和替换操作。等同于表示任何出现的地方都会被替换为。提供函数用来合并配置对象当文件小于限制,会返回。 选项 1.devtool:通过在浏览器调试工具(browser devtools)中添加元信息(meta info)增强调试。 2.resolve.alias:创建 impor...
阅读 1381·2021-09-02 09:53
阅读 2656·2021-07-29 13:50
阅读 1693·2019-08-30 11:07
阅读 1553·2019-08-30 11:00
阅读 1435·2019-08-29 14:00
阅读 1785·2019-08-29 12:52
阅读 2541·2019-08-29 11:11
阅读 3399·2019-08-26 12:23