React实战之webpack搭建开发工作流

1、介绍


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

2、安装


  • 全局安装

以下的 NPM 安装方式,将使 webpack 在全局环境下可用:

npm install -g webpack

不推荐全局安装 webpack。这会将您项目中的 webpack 锁定到指定版本,并且在使用不同的 webpack 版本的项目中,可能会导致构建失败。

  • 本地安装

//安装最新版本
npm install --save-dev webpack
//安装特定版本
npm install --save-dev webpack@

对于大多数项目,我们建议本地安装。这可以使我们在引入破坏式变更(breaking change)的依赖时,更容易分别升级项目。

  • 安装操作

首先我们创建一个目录,初始化 npm,以及在本地安装 webpack:

mkdir webpack-demo && cd webpack-demo
npm init -y
npm install --save-dev webpack
React实战之webpack搭建开发工作流_第1张图片
安装操作
React实战之webpack搭建开发工作流_第2张图片
执行完以后目录结构

2、Webpack使用


  • 简单使用webpack

现在我们将创建以下目录结构和内容
React实战之webpack搭建开发工作流_第3张图片
目录结构
src/index.js
function component() {
    var element = document.createElement('div');
    element.innerHTML = 'Hello, webpack';
    return element;
}
document.body.appendChild(component());
dist/index.html
 
   
     Getting Started
   
   
     
   
 
执行 webpack,会将我们的脚本作为入口起点,然后输出为 bundle.js
./node_modules/.bin/webpack src/index.js dist/bundle.js
React实战之webpack搭建开发工作流_第4张图片
执行 webpack
在浏览器中打开 index.html,如果一切访问都正常,你应该能看到以下文本:'Hello webpack'。
在浏览器中打开 index.html
  • 使用配置文件webpack.config.js

大多数项目会需要很复杂的设置,这就是为什么 webpack 要支持配置文件。这比在终端(terminal)中输入大量命令要高效的多,所以让我们创建一个取代以上使用 CLI 选项方式的配置文件:webpack.config.js

React实战之webpack搭建开发工作流_第5张图片
目录结构
webpack.config.js
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};
现在,让我们再次执行构建,通过使用我们的新配置:
./node_modules/.bin/webpack --config webpack.config.js
React实战之webpack搭建开发工作流_第6张图片
使用webpack.config.js
NPM 脚本(NPM Scripts)

考虑到用 CLI 这种方式来运行本地的 webpack 不是特别方便,我们可以设置一个快捷方式。在 package.json 添加一个 npm 脚本(npm script):

package.json
React实战之webpack搭建开发工作流_第7张图片
package.json

现在,可以使用 npm run build 命令,来替代我们之前用到的较长命令。注意,使用 npm 的 scripts,我们可以通过模块名,来引用本地安装的 npm 包,而不是写出完整路径。这是大多数基于 npm 的项目遵循的标准,允许我们直接调用 webpack,而不是去调用 ./node_modules/.bin/webpack。

现在运行以下命令,然后看看你的脚本别名是否正常运行:
npm run build
React实战之webpack搭建开发工作流_第8张图片
npm run build 运行结果

2、React和ES6以及JSX语法的支持


  • ES6以及JSX语法的支持

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

安装Babel依赖包
// npm一次性安装多个依赖模块,模块之间用空格隔开
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react
React实战之webpack搭建开发工作流_第9张图片
目录结构
.babelrc
{
  "presets": ["react", "es2015"]
}
babel 在webpack.config.js 中进行配置
React实战之webpack搭建开发工作流_第10张图片
babel 在webpack.config.js 中进行配置
React的支持

安装 React 和 React-DOM

npm install --save react react-dom
使用React和ES6的语法更新index.js

注意这里我没有直接渲染到 document.body上,而是特别选择了 id 为 root 的 :
ReactDOM.render(, document.getElementById('root'));
React官方不推荐将组件渲染到 document.body 上,因为这个节点很可能会改变,比如动态添加一个

运行
React实战之webpack搭建开发工作流_第11张图片
运行

浏览器运行效果

3、通过 loader 引入任何其他类型的文件


  • 加载 CSS

为了从 JavaScript 模块中 import 一个 CSS 文件,你需要在 module 配置中 安装并添加 style-loader 和 css-loader:

npm install --save-dev style-loader css-loader
加载css在webpack.config.js 中进行配置
React实战之webpack搭建开发工作流_第12张图片
加载css在webpack.config.js 中进行配置
我们尝试一下,通过在项目中添加一个新的 style.css 文件,并将其导入到我们的 index.js 中:
React实战之webpack搭建开发工作流_第13张图片
目录结构
src/style.css
.hello {
  color: red;
}
src/index.js
React实战之webpack搭建开发工作流_第14张图片
src/index.js
运行
React实战之webpack搭建开发工作流_第15张图片
npm run build

浏览器运行结果
CSS module

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

CSS module在webpack.config.js 中进行配置
React实战之webpack搭建开发工作流_第16张图片
CSS module在webpack.config.js 中进行配置
src/index.js
React实战之webpack搭建开发工作流_第17张图片
屏幕快照 2017-09-06 10.48.17.png
运行
React实战之webpack搭建开发工作流_第18张图片
npm run build

浏览器运行结果
  • 加载图片

使用 file-loader,我们可以轻松地将这些内容混合到 CSS 中:
npm install --save-dev file-loader
加载图片在webpack.config.js 中进行配置
React实战之webpack搭建开发工作流_第19张图片
加载图片在webpack.config.js 中进行配置
增加一张test.png图片
React实战之webpack搭建开发工作流_第20张图片
目录结构
src/style.css
src/style.css
运行
React实战之webpack搭建开发工作流_第21张图片
npm run build

浏览器运行结果

4、webpack plugin


  • HtmlWebpackPlugin

作用

1、html文件中引入的外部资源如script、link动态添加每次compile后的hash,防止引用缓存的外部文件问题
2、可以生成创建html入口文件,比如单页面可以生成一个html文件入口,配置N个html-webpack-plugin可以生成N个页面入口

安装
npm install --save-dev html-webpack-plugin
创建src/index.tmpl.html,并删除dist/index.html
React实战之webpack搭建开发工作流_第22张图片
目录结构
src/index.tmpl.html
  
   
     Getting Started
   
   
        
webpack.config.js配置
React实战之webpack搭建开发工作流_第23张图片
webpack.config.js配置
运行
React实战之webpack搭建开发工作流_第24张图片
npm run build

React实战之webpack搭建开发工作流_第25张图片
dist目录下生成了index.html

浏览器运行index.html
了解更多 HtmlWebpackPlugin 插件

如果你想要了解更多 HtmlWebpackPlugin 插件提供的全部功能和选项,那么你就应该多多熟悉HtmlWebpackPlugin 仓库。
你还可以看一下 html-webpack-template,除了默认模板之外,还提供了一些额外的功能。

  • clean-webpack-plugin

你可能已经注意到,由于过去的指南和代码示例遗留下来,导致我们的 /dist 文件夹相当杂乱。webpack 会生成文件,然后将这些文件放置在 /dist 文件夹中,但是 webpack 无法追踪到哪些文件是实际在项目中用到的。

通常,在每次构建前清理 /dist 文件夹,是比较推荐的做法,因此只会生成用到的文件。让我们完成这个需求。

安装
npm install clean-webpack-plugin --save-dev
webpack.config.js配置
React实战之webpack搭建开发工作流_第26张图片
webpack.config.js配置
现在执行 npm run build,再检查 /dist 文件夹。如果一切顺利,你现在应该不会再看到旧的文件,只有构建后生成的文件!

5、开发常用配置


  • webpack-dev-server

webpack-dev-server 为你提供了一个简单的 web 服务器,并且能够实时重新加载(live reloading)。

安装
npm install --save-dev webpack-dev-server
webpack.config.js配置
React实战之webpack搭建开发工作流_第27张图片
webpack.config.js配置

localhost:8080 下建立服务,并启用gzip压缩

package.json配置npm script
React实战之webpack搭建开发工作流_第28张图片
package.json配置npm script
运行
React实战之webpack搭建开发工作流_第29张图片
npm start

自动打开浏览器并修改自动刷新
  • source map

介绍

当 webpack 打包源代码时,可能会很难追踪到错误和警告在源代码中的原始位置。例如,如果将三个源文件(a.js, b.js 和 c.js)打包到一个 bundle(bundle.js)中,而其中一个源文件包含一个错误,那么堆栈跟踪就会简单地指向到 bundle.js。这并通常没有太多帮助,因为你可能需要准确地知道错误来自于哪个源文件。

为了更容易地追踪错误和警告,JavaScript 提供了 source map 功能,将编译后的代码映射回原始源代码。如果一个错误来自于 b.js,source map 就会明确的告诉你。

devtool选项
以下选项是开发的理想选择:

eval- 每个模块都用eval()和执行//@ sourceURL。这很快。主要的缺点是它不会正确显示行号,因为它被映射到折叠代码而不是原始代码(没有来自加载器的源地图)。

eval-source-map- 每个模块都执行,eval()并将SourceMap作为DataUrl添加到eval()。最初它很慢,但它提供了快速的重建速度,并产生真实的文件。行号被正确映射,因为它被映射到原始代码。它产生最好的质量SourceMaps进行开发。

cheap-eval-source-map- 类似于eval-source-map每个模块都执行eval()。它是“便宜的”,因为它没有列映射,它只映射行号。它忽略来自Loader的SourceMaps,并且仅显示与devtool类似的折叠代码eval。

cheap-module-eval-source-map- cheap-eval-source-map但是,与此类似,处理来自加载程序的源地图以获得更好的结果。然而,Loader Source Maps简化为每行一个映射。

对小到中型的项目中,eval-source-map是一个很好的选项,再次强调你只应该开发阶段使用它。
cheap-module-eval-source-map方法构建速度更快,但是不利于调试,推荐在大型项目考虑时间成本时使用。
webpack.config.js 配置
React实战之webpack搭建开发工作流_第30张图片
屏幕快照 2017-09-06 14.38.07.png
  • 代码分离及优化

介绍
  • OccurenceOrderPlugin :为组件分配ID,通过这个插件webpack可以分析和优先考虑使用最多的模块,并为它们分配最小的ID
  • UglifyJsPlugin:压缩JS代码;
  • ExtractTextPlugin:用于将 CSS 从主应用程序中分离
安装

OccurenceOrder 和 UglifyJS plugins 都是内置插件,你需要做的只是安装其它非内置插件

npm install --save-dev extract-text-webpack-plugin
webpack.config.js配置
React实战之webpack搭建开发工作流_第31张图片
webpack.config.js配置
运行
React实战之webpack搭建开发工作流_第32张图片
npm start

运行后将css文件分离到style.css文件中


React实战之webpack搭建开发工作流_第33张图片
将css文件分离到style.css文件中

运行后js文件被压缩


运行后js文件被压缩
  • 缓存

介绍

通过使用 output.filename 进行文件名替换,可以确保浏览器获取到修改后的文件。[hash] 替换可以用于在文件名中包含一个构建相关(build-specific)的 hash,但是更好的方式是使用 [chunkhash] 替换,在文件名中包含一个 chunk 相关(chunk-specific)的哈希。

webpack.config.js 配置
React实战之webpack搭建开发工作流_第34张图片
webpack.config.js 配置
  • 生产环境构建

现在,我们把 scripts 重新指向到新配置。我们将 npm start 定义为开发环境脚本,并在其中使用 webpack-dev-server,将 npm run build 定义为生产环境脚本

创建webpack.config.prod.js文件
React实战之webpack搭建开发工作流_第35张图片
创建webpack.config.prod.js文件
webpack.config.prod.js
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = {
    entry: './src/index.js',
    output: {
        filename: '[name].[chunkhash].js',
        path: path.resolve(__dirname, 'dist')
    },
    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,
                            minimize: true
                        }
                    }
                })
            },
            {
                test: /\.(png|svg|jpg|gif)$/,
                use: [
                    'file-loader'
                ]
            }
        ]
    },
    plugins: [
        new ExtractTextPlugin("[name].[contenthash].css"),
        new CleanWebpackPlugin([__dirname + "/dist"]),
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.optimize.UglifyJsPlugin(),
        new HtmlWebpackPlugin({
            template: __dirname + "/src/index.tmpl.html",//new 一个这个插件的实例,并传入相关的参数
            minify: {
                removeComments: true, //是否去掉注释
                collapseWhitespace: true, //是否去掉空格
                minifyJS: true, //是否压缩html里的js(使用uglify-js进行的压缩)
                minifyCSS: true, //是否压缩html里的css(使用clean-css进行的压缩)
            },
        })
    ],
};
webpack.config.js去除一些配置
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: '[name].[chunkhash].js',
        path: path.resolve(__dirname, 'dist')
    },
    devtool: 'eval-source-map',
    module: {
        rules: [{
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true
                        }
                    }
                ]
            },
            {
                test: /\.(png|svg|jpg|gif)$/,
                use: [
                    'file-loader'
                ]
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: __dirname + "/src/index.tmpl.html",//new 一个这个插件的实例,并传入相关的参数
            minify: {
                removeComments: true, //是否去掉注释
                collapseWhitespace: true, //是否去掉空格
                minifyJS: true, //是否压缩html里的js(使用uglify-js进行的压缩)
                minifyCSS: true, //是否压缩html里的css(使用clean-css进行的压缩)
            },
        })
    ],
    devServer: {
        //一切服务都启用gzip 压缩:
        compress: true,
        port: 8080
    },
};
package.json配置
React实战之webpack搭建开发工作流_第36张图片
package.json配置

最后


本篇文章将涵盖webpack安装、使用、plugin、开发中常用的配置、缓存等等,我在边写边跟着构建,并将每一步构建生成git记录,代码传送门,如果有疑问的地方欢迎在下面评论或者私信给我。
如果您觉得有帮助,请给我点个。

你可能感兴趣的:(React实战之webpack搭建开发工作流)