源码地址:https://github.com/remmlqw/we...
注意:本文是从 Webpack3 搭建 兼容 Webpack4css
新建项目
一、新建一个文件夹html
npm init
一直回车,最后yes,生成package.json前端
二、文件夹中新建如下文件node
src --源码 index.html --入口首页 webpack.config.js --webpack开发环境配置 webpack.production.config.js --webpack生产环境配置
下载依赖包
先下载几个基本的包,后续还会用到其余包。react
打包工具
webpack webpack
辅助开发的服务器(该服务器能热加载代码,自动刷新页面,代理服务器解决前端开发时跨域问题)
webpack-dev-server git
在webpack 3中,webpack自己和它的CLI之前都是在同一个包中,但在第4版中,他们已经将二者分开来更好地管理它们。因此还要安装:
webpack-cli
注:这里除了本地安装外,还需全局安装 npm i webpack-cli -g
es6
react用到es6语法,因此要安装es6转码器babel相关的包
babel-core
babel-loader
babel-preset-env
babel-preset-reactgithub
webpack须要处理样式文件打包的处理器
css-loader
style-loader
less-loaderweb
webpack须要处理图片文件打包的处理器
file-loader
url-loader
以上包的下载使用 npm i XXX --save-dev
--save-dev 是写入开发环境的依赖
react项目的两个基础包
react
react-dom
这两个包下载使用 npm i XXX --save
--save 是写入生产环境的依赖
package.json中的scripts
在package.json中的scripts加上两个key
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "cross-env NODE_ENV=dev webpack-dev-server --inline --progress --colors --mode development", "build": "cross-env NODE_ENV=production webpack --config ./webpack.production.config.js --progress --colors --mode production" },
这里须要安装的一个包 npm i cross-env --save-dev
有何用?
windows不支持 NODE_ENV=development
的设置方式,这个包可以提供一个设置环境变量的scripts,让你可以以unix方式设置环境变量,而后在windows上也能兼容运行。cross-env
让这一切变得简单,不一样平台使用惟一指令,无需担忧跨平台问题。
--progress
显示打包过程当中的进度--colors
打包信息带有颜色显示--inline
自动刷新的配置--mode development/production
webpack 4引入了生产和开发模式,自动根据开发和生产两种模式进行优化
webpack --config ./webpack.production.config.js
这个命令是制定webpack的配置文件,由于默认的是webpack.config.js
,而这里是打包命令,应该使用webpack.production.config.js
。
开发环境配置 --webpack.config.js
先上完整代码
const path=require('path'); const webpack = require('webpack') var HtmlWebpackPlugin = require('html-webpack-plugin'); var OpenBrowserPlugin = require('open-browser-webpack-plugin'); // 配置文件的内容须要经过module.exports暴露 module.exports = { // 配置须要打包的入口文件,值能够是字符串、数组、对象。 // 1. 字符串: entry: './entry' // 2. 字符串: entry:[ './entry1','entry2'] (多入口) // 3. 对象: entry: {alert/index': path.resolve(pagesDir, `./alert/index/page`)} // 多入口书写的形式应为object,由于object,的key在webpack里至关于此入口的name, entry : './src/js/index.js', output : { // 输出文件配置,output 输出有本身的一套规则,经常使用的参数基本就是这三个 // path: 表示生成文件的根目录 须要一个**绝对路径** path仅仅告诉Webpack结果存储在哪里 path : path.resolve(__dirname,'dist'), // filename 属性表示的是如何命名出来的入口文件 filename : './js/bundle.js' }, resolve: { //自动扩展文件后缀名,意味着咱们require模块能够省略不写后缀名 extensions: ['*', '.js', '.json', '.less','.jsx'], //模块别名定义,方便后续直接引用别名,无须多写长长的地址 alias: { '@components': path.resolve(__dirname,'src/js/components') } }, module : { // 这里就是Loader,经过Loader,webpack可以针对每一种特定的资源作出相应的处理 // 1.test参数用来指示当前配置项针对哪些资源,该值应是一个条件值(condition)。 // 2.exclude参数用来剔除掉须要忽略的资源,该值应是一个条件值(condition)。 // 3.include参数用来表示本loader配置仅针对哪些目录/文件,该值应是一个条件值(condition)。 // 而include参数则用来指示目录;注意同时使用这二者的时候,其实是and的关系。 // 4.use参数,用来指示用哪一个或哪些loader来处理目标资源。 rules : [ { test: /\.(js|jsx)$/, use : { loader : "babel-loader", options : { presets : ['env','react'] } }, exclude : /node_modules/ }, { test: /\.less$/, exclude: /node_modules/, use : [{loader : "style-loader"},{loader : "css-loader"},{loader : "less-loader"}] }, { test : /\.css$/, use : [{loader : "style-loader"},{loader : "css-loader"}] }, { test: /\.(png|gif|jpg|jpeg|bmp)$/i, use : { loader : 'url-loader', options : { limit : '8192' } } }, { test: /\.(woff|woff2|svg|ttf|eot)($|\?)/i, use: { loader: 'url-loader', options: { limit: '8192' } } } ] }, plugins: [ // html 模板插件 new HtmlWebpackPlugin({ template: __dirname + '/index.html' }), // 热加载插件 new webpack.HotModuleReplacementPlugin(), // 打开浏览器 new OpenBrowserPlugin({ url: 'http://localhost:8080' }), // 可在业务 js 代码中使用 __DEV__ 判断是不是dev模式(dev模式下能够提示错误、测试报告等, production模式不提示) new webpack.DefinePlugin({ __DEV__: JSON.stringify(JSON.parse((process.env.NODE_ENV == 'dev') || 'false')) }), ], //咱们在这里对webpack-dev-server进行配置 devServer: { contentBase:"./",// 本地服务器在哪一个目录搭建页面,通常咱们在当前目录便可; historyApiFallback:true,//当咱们搭建spa应用时很是有用,它使用的是HTML5 History Api,任意的跳转或404响应能够指向 index.html 页面; inline:true,//用来支持dev-server自动刷新的配置,webpack有两种模式支持自动刷新,一种是iframe模式,一种是inline模式;使用iframe模式是不须要在devServer进行配置的,只需使用特定的URL格式访问便可;不过咱们通常仍是经常使用inline模式,在devServer中对inline设置为true后,当咱们启动webpack-dev-server时仍要须要配置inline才能生效 hot:true,// 启动webpack热模块替换特性,这里是个坑 port:8080,//配置服务端口号 host:'localhost',//服务器的IP地址,可使用IP也可使用localhost compress:true,//服务端压缩是否开启 } }
相关参数配置的说明已经写在代码的注释里。
这里对于上面使用的插件我在作一下说明:
html-webpack-plugin
:html-webpack-plugin能够根据你设置的模板,在每次运行后生成对应的模板文件,同时所依赖的CSS/JS也都会被引入,若是CSS/JS中含有hash值,则html-webpack-plugin生成的模板文件也会引入正确版本的CSS/JS文件。详细介绍https://www.npmjs.com/package...
webpack.HotModuleReplacementPlugin
:模块热替换(HMR - Hot Module Replacement)功能会在应用程序运行过程当中替换、添加或删除模块,而无需从新加载整个页面。主要是经过如下几种方式,来显著加快开发速度:
保留在彻底从新加载页面时丢失的应用程序状态。
只更新变动内容,以节省宝贵的开发时间。
调整样式更加快速 ,几乎至关于在浏览器调试器中更改样式。
详细介绍https://doc.webpack-china.org...
open-browser-webpack-plugin
: 则在webpack 启动成功后会打开浏览器。详细介绍https://www.npmjs.com/package...
webpack.DefinePlugin
: 可在业务 js 代码中使用 DEV 判断是不是dev模式。详细介绍https://doc.webpack-china.org...
好比
if(__DEV__) { console.log("如今是开发环境"); } else { console.log("如今是生产环境"); }
这里须要额外安装的包:
html-webpack-plugin
open-browser-webpack-plugin
生产环境配置 --webpack.production.config.js
一样的,先上完整代码:
var path = require('path') var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var autoprefixer = require('autoprefixer'); var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); module.exports = { entry: { app: path.resolve(__dirname, './src/js/index.js'), // 将 第三方依赖 单独打包 vendor: ['react', 'react-dom'] }, output: { path: __dirname + "/dist", // filename 属性表示的是如何命名出来的入口文件,规则是一下三种: // [name] 指代入口文件的name,也就是上面提到的entry参数的key,所以,咱们能够在name里利用/,便可达到控制文件目录结构的效果。 // [hash],指代本次编译的一个hash版本,值得注意的是,只要是在同一次编译过程当中生成的文件,这个[hash].js //的值就是同样的;在缓存的层面来讲,至关于一次全量的替换。 filename: "js/[name].[chunkhash:8].js", // publicPath 参数表示的是一个URL 路径(指向生成文件的跟目录),用于生成css/js/图片/字体文件 // 等资源的路径以确保网页能正确地加载到这些资源. // “publicPath”项则被许多Webpack的插件用于在生产模式下更新内嵌到css、html文件里的url值. // 例如,在localhost(即本地开发模式)里的css文件中边你可能用“./test.png”这样的url来加载图片, // 可是在生产模式下“test.png”文件可能会定位到CDN上而且你的Node.js服务器多是运行在HeroKu上边的。 // 这就意味着在生产环境你必须手动更新全部文件里的url为CDN的路径。 //开发环境:Server和图片都是在localhost(域名)下 //.image { // background-image: url('./test.png'); //} // 生产环境:Server部署下HeroKu可是图片在CDN上 //.image { // background-image: url('https://someCDN/test.png'); //} publicPath: './' }, resolve: { //自动扩展文件后缀名,意味着咱们require模块能够省略不写后缀名 extensions: ['*', '.js', '.json', '.less','.jsx'], //模块别名定义,方便后续直接引用别名,无须多写长长的地址 alias: { '@components': path.resolve(__dirname,'src/js/components') } }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { loader: "babel-loader", options: { presets: ['env', 'react'] } } }, { test: /\.less$/, exclude: /node_modules/, use: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'postcss-loader', 'less-loader'] }) }, { test: /\.css$/, // exclude: /node_modules/, 删掉次行 否则打包会报错 由于antd.css 在node_modules中 use: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'postcss-loader'] }) }, { test: /\.(png|gif|jpg|jpeg|bmp)$/i, use: { loader: 'url-loader', options: { limit: '8192', outputPath: 'images/', publicPath : '/images' } } }, { test: /\.(woff|woff2|svg|ttf|eot)($|\?)/i, use: { loader: 'url-loader', options: { limit: '8192', outputPath: 'font/' } } } ] }, plugins: [ // webpack 内置的 banner-plugin new webpack.BannerPlugin("Copyright by 765745342@qq.com"), // html 模板插件 new HtmlWebpackPlugin({ template: __dirname + '/index.html' }), // 定义为生产环境,编译 React 时压缩到最小 new webpack.DefinePlugin({ 'process.env': { 'NODE_ENV': JSON.stringify(process.env.NODE_ENV) } }), // 为组件分配ID,经过这个插件webpack能够分析和优先考虑使用最多的模块,并为它们分配最小的ID new webpack.optimize.OccurrenceOrderPlugin(), new webpack.optimize.UglifyJsPlugin({ compress: { //supresses warnings, usually from module minification warnings: false } }), // 分离CSS和JS文件 new ExtractTextPlugin('css/[name].[chunkhash:8].css'), // 提供公共代码 new webpack.optimize.CommonsChunkPlugin({name: 'vendor', filename: 'js/[name].[chunkhash:8].js'}), // 可在业务 js 代码中使用 __DEV__ 判断是不是dev模式(dev模式下能够提示错误、测试报告等, production模式不提示) new webpack.DefinePlugin({ __DEV__: JSON.stringify(JSON.parse((process.env.NODE_ENV == 'dev') || 'false')) }), new OptimizeCssAssetsPlugin({ assetNameRegExp: /\.css$/g, cssProcessor: require('cssnano'), cssProcessorOptions: { discardComments: {removeAll: true } }, canPrint: true }) ] }
有些地方和 webpack.config.js
的配置是同样的我就不作说明了。
extract-text-webpack-plugin
: 开发环境下,css 代码是放在整个打包出来的那个 bundle.js 文件中的,发布环境下固然不能混淆在一块儿。该插件的主要是为了抽离css样式,防止将样式打包在js中引发页面样式加载错乱的现象。详细介绍https://www.npmjs.com/package...
webpack.optimize.CommonsChunkPlugin
: 将第三方依赖单独打包。即将 node_modules 文件夹中的代码打包为 vendor.js 将咱们本身写的业务代码打包为 app.js。这样有助于缓存,由于在项目维护过程当中,第三方依赖不常常变化,而业务代码会常常变化。详细介绍https://doc.webpack-china.org...
webpack.optimize.UglifyJsPlugin
: 压缩你的JS代码。详细介绍https://doc.webpack-china.org...
optimize-css-assets-webpack-plugin
: CSS代码压缩。详细介绍https://www.npmjs.com/package...
autoprefixer
: Autoprefixer是一个后处理程序,你能够同Sass,Stylus或LESS等预处理器共通使用。它适用于普通的CSS,而你无需关心要为哪些浏览器加前缀,只需全新关注于实现,并使用W3C最新的规范。详细介绍https://www.npmjs.com/package...
这是一个自动给你加上css浏览器前缀,好比
你只需写:
a { display: flex; }
这个插件自动给你添加厂商前缀:
a { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; }
这个插件请注意,你须要下载 postcss-loader
而且新建文件postcss.config.js
文件内容:
module.exports = { plugins: { 'autoprefixer': {browsers: 'last 5 version'} } }
这里须要额外安装的包:
postcss-loader
extract-text-webpack-plugin
optimize-css-assets-webpack-plugin
启动项目
npm start
打包项目
npm run build