webpack脚手架构建React项目
lesson-1主要内容:构建一套适合 React、ES6 开发的脚手架项目地址 github-react-lesson Features
前言:Webpack 是当下最热门的前端资源模块化管理和打包工具。它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。 Webpack 和 gulp 没有可比性也许你用过gulp,有了gulp你可以对css,js 文件进行压缩合并等处理,但随着前端技术不断发展,出现了前端资源模块化,资源按需
项目构建,安装必要包clone 切到 在lesson-1 的根目录下执行以下命令,安装必要包 npm install // 如果安装过 npm 淘宝镜像 cnpm install // 如果是 Mac 需要权限 sudo npm install 开发过程中你会用到以下命令进行打包编译: | lesson-1根目录下运行命令行 | 解释 | 一、 webpack 基础讲解
webpack.config.js 大致流程图:
1、entryentry: { app: APP_FILE } 指定一个入口文件,webpack将会顺藤摸瓜识别所依赖的文件,再一个个进行接下去的解析处理 2、outputoutput: { publicPath: './static/',//编译好的文件,在服务器的路径,这是静态资源引用路径 path: BUILD_PATH,//编译到当前目录 filename: '[name].js',//编译后的文件名字 chunkFilename: '[name].[chunkhash:5].min.js',}, 指定一个出口路径,当webpack处理完依赖文件后,将输出文件输出到指定路径下
指输出 js 文件名 同 entry: 的输入文件名的配置一样,这里是会输出 app.js
会对输出的文件添加后缀,一个5位的 hash 值 3、devtooldevtool: 'cheap-module-eval-source-map', 除了输出编译后的文件外,还会顺带输出一个 Source Map 。什么是 Source Map呢,Source map就是一个信息文件,里面储存着位置信息。也就是说,转换后的代码的每一个位置,所对应的转换前的位置。如转码后的 ES6文件或 React的jsx文件 当代码出错我们很难找到对应的出错位置,那 4、resolveresolve: { extensions: ['','.js','.jsx','.less','.scss','.css'],//后缀名自动补全 } 这个配置可以帮我们自动补全后缀名,当我们 import 一个 demo.js 时可以这么写不带后缀的
5、modulemodule: { loaders: [{ test: /.scss$/,exclude: /^node_modules$/,loader: ExtractTextPlugin.extract('style',['css','autoprefixer','sass']),include: [APP_PATH] },{ test: /.js$/,loader: 'babel',{ test: /.(png|jpg)$/,loader: 'url-loader?limit=8192&name=images/[hash:8].[name].[ext]',//注意后面那个limit的参数,当你图片大小小于这个限制的时候,会自动启用base64编码图片 include: [APP_PATH] },{ test: /.jsx$/,loaders: ['jsx','babel'],include: [APP_PATH] }] }, webpack 的核心部分就是各种 loader 了 ,webpack 拿到入口文件,并顺藤摸瓜解析到各种依赖文件,遇到不同的文件后缀就执行对应的loader进行处理
当依赖文件有以 .scss 后缀的文件,会先执行 sass-loader 再 执行 autoprefixer-loader(给一些css3添加后缀的loader)
当依赖文件有以 .js 后缀的文件 ,会经过 loader: 'babel',这里多做了一步跳转是 babel会找到根目录下咱们配置的一个 .babelrc文件 { "presets": [ "react","es2015","stage-0",],"plugins": [ "transform-decorators-legacy","transform-class-properties" ] } .js 文件会根据上面的配置进行解析
{ test: /.(png|jpg)$/,//注意后面那个limit的参数,当你图片大小小于这个限制的时候,会自动启用base64编码图片 include: [APP_PATH] } 图片干嘛需要 loader呢,上面也解释了 可以将一个较小的图片进行 base64转换
React 独有的 .jsx 文件 ,相对 .js文件多了一步 jsx-loader 6、pluginsplugins: [ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify('development') //定义编译环境 },'cdnUrl':JSON.stringify('http:demo.com/'),'dev': true }),new HtmlWebpackPlugin({ //根据模板插入css/js等生成最终HTML filename: '../index.html',//生成的html存放路径,相对于 path template: './src/template/index.html',//html模板路径 hash: false,}),new ExtractTextPlugin('[name].css') ], 其中:
plugins: [ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify('development') //定义编译环境 },'dev': true }) ] 定义一下全局变量,可以在模块中使用这些变量 console.log(cdnUrl); 编译后的 demo.js 输出: console.log(‘http:demo.com/’); 这个全局变量有什么作用呢,如果你有点项目经验就知道这个 plugin 的巨大好处了,举个小例子,咱们在项目开发时,线上环境 if(dev){ // dev 是 DefinePlugin 的一个全局变量 }else{ }
plugins: [ new HtmlWebpackPlugin({ //根据模板插入css/js等生成最终HTML filename: '../index.html',}) ], 依赖文件经过 webpack 编译完输出到指定的目录下 ,那怎么被 html 引用呢,那就需要 HtmlWebpackPlugin 插件。
plugins: [ new ExtractTextPlugin('[name].css') ], 我们会在 .js 文件 import .css 或 .scss 文件,webpack 编译 .js 文件时会将这个css文件打包进了 js文件里头。 编译前:
编译后:
二、开发环境下的 webpack -- 热刷新在实际开发中不可能编译一下webpack 在浏览器刷新看一下结果,编辑完再编译一下webpack,再刷新浏览器看一下效果。这样工作效率非常低 1、启动热刷新与第一节不同的是,我们不是通过命令行
执行完命令 试着改变一样 js文件或scss文件保存一下,发现浏览器页面是自动刷新的。但 build 目录下却不见得有任何输出。 2、中间件 webpack-dev-middleware上面第一小点提到一个
3、 npm run hot运行命令行 (1)、分析 server_hot.jsvar webpack = require('webpack'); var express = require('express'); var config = require('./webpack.config.hot'); var app = express(); var compiler = webpack(config); app.use(require('webpack-dev-middleware')(compiler,{ publicPath: config.output.publicPath,hot: true,historyApiFallback: true,inline: true,progress: true,stats: { colors: true,} })); app.use(require('webpack-hot-middleware')(compiler));自动刷新的消息通知依靠的是浏览器和服务器之间的web socket连接 //将其他路由,全部返回index.html app.get('*',function(req,res) { res.sendFile(__dirname + '/index.html') }); app.listen(8088,function() { console.log('正常打开8088端口') }); (2)、看一下下面例子解释一下 app.use()var express = require('express'); var app = express(); app.use(function (req,res,next) { // 没指定路径默认是 app.use('/',function(){}) 访问根路径 //会进入这个函数 console.log('Time:',Date.now()); next(); }); 也就是 当 服务端接收到一个请求时,会先被 app.use()拦截下,因为 app.use()没有指定路径,默认接收根路径, app.use()处理完事情就会交给 下面的 get 或 post 请求了: //将其他路由,全部返回index.html app.get('*',res) { res.sendFile(__dirname + '/index.html') }); 这里 get 收到请求后就给浏览器一个 响应(response) (3)、看一下 webpack-dev-middleware 中间件app.use(require('webpack-dev-middleware')(compiler,} })); 上面一小点说到了 app.use 会收到请求后先做一些处理 ,处理内容就是 webpack-dev-middleware 来完成, 其中 webpack-dev-middleware 中间件 接收两个参数,一个是 (4)、 最后看一下 webpack-hot-middlewareapp.use(require('webpack-hot-middleware')(compiler)); 如果一些文件的小改动比如 改变一个 div 的颜色啊,都有经过一大堆的编译那效率就太低了,所以 webpack-hot-middleware 可以对一些小 4、 热跟新的配置文件 webpack.config.hot.js这个配置文件其实跟第一大节讲的并无太大区别,只不过要配合热刷新需要新添加如下配置: entry: { app: [ 'webpack-hot-middleware/client',APP_FILE ] }, plugins 添加如下: plugins: [ new webpack.HotModuleReplacementPlugin(),new webpack.NoErrorsPlugin() ] 三、 线上环境下的 webpack一般呢,项目开发完要发布到服务器,是需要配合另一套的项目打包流程的,发布到服务器的项目是不需要热更新等一些辅助开发的流程, 1、npm run build在lesson-1 根目录下运行命令
运行命令 "build": "webpack --config webpack.config.build.js --progress --colors --watch -p"
2、分析 webpack.config.build.jsvar path = require('path'); var webpack = require('webpack'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); //css单独打包 var HtmlWebpackPlugin = require('html-webpack-plugin'); //生成html //定义地址 var ROOT_PATH = path.resolve(__dirname); var APP_PATH = path.resolve(ROOT_PATH,'src'); //__dirname 中的src目录,以此类推 var APP_FILE = path.resolve(APP_PATH,'app'); //根目录文件app.jsx地址 var BUILD_PATH = path.resolve(ROOT_PATH,'./build/static'); //发布文件所存放的目录/pxq/dist/前面加/报错? module.exports = { entry: { app: APP_FILE,common: [ "react",'react-dom','react-router','redux','react-redux','redux-thunk','immutable' ] },output: { //publicPath: 'http:example.cdn/',// 给资源文件添加前缀,一般会把静态资源发布的 cdn 上 path: BUILD_PATH,resolve: { extensions: ['','.css'] //后缀名自动补全 },module: { loaders: [{ test: /.js$/,loader: 'babel' },{ test: /.css$/,'autoprefixer']) },{ test: /.less$/,'less']) },{ test: /.scss$/,'sass']) },{ test: /.(eot|woff|svg|ttf|woff2|gif|appcache)(?|$)/,loader: 'file-loader?name=[name].[ext]' },{ test: /.(png|jpg|gif)$/,//注意后面那个limit的参数,当你图片大小小于这个限制的时候,会自动启用base64编码图 },{ test: /.jsx$/,'babel'] }] },plugins: [ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify('production') //定义生产环境 } }),new HtmlWebpackPlugin({ //根据模板插入css/js等生成最终HTML filename: '../index.html',//html模板路径 inject: 'body',hash: true,new ExtractTextPlugin('[name].css'),//提取出来的样式和common.js会自动添加进发布模式的html文件中,原来的html没有 new webpack.optimize.CommonsChunkPlugin("common","common.bundle.js"),new webpack.optimize.UglifyJsPlugin({ output: { comments: false,// remove all comments (移除所有注释) },compress: { // 压缩 warnings: false } }) ] }; 与前面讲的第一大节相比,并无明显区别,主要是加了一些将项目发布到服务的线上流程。 (1)、entryentry: { app: APP_FILE,common: [ "react",'immutable' ] }, 添加了 common 用来单独打包出公共部分的 js代码 (2)、pluginsplugins: [ new ExtractTextPlugin('[name].css'),new webpack.optimize.CommonsChunkPlugin("common",new webpack.optimize.UglifyJsPlugin({ output: { comments: false,// remove all comments (移除所有注释) },compress: { // 压缩 warnings: false } }) ] webpack.config.build.js 新添了几个 plugins 。首先要清楚的一点是 webpack 是将一块块的依赖打包的一个文件里头的, 总结lesson-1 主要是对 webpack 打包编译的一些讲解和梳理。
后面还有 lesson 来讲解 React 配合 Redux、 Router 在实际项目中的应用和开发,喜欢的话可以先 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |