webpack从零开始搭建react开发脚手架
-
style-loader
可以给每一个模块加入一个标志。
-
less-loader
将less所写得样式代码转换为css代码, -
css-loader
解析@import()和less或者css里面的url() -
url-loader
将引入的文件转换为base64位, -
html-webpack-plugin
能自动生成一个html文件并把我们打包好的js文件放入html -
@babel/core babel-loader@8 @babel/preset-env @babel/preset-react
这几个插件可以让babel去解析jsx文件
-
webpack-dev-server
提供了对Webpack资产的快速内存访问,可提供一个热更新的开发dev环境
建立好的文件目录
build环境搭建
最简单的webpack build配置
-
创建空的文件夹命名为test-app
-
生成package.json,并安装webpack
npm init npm install webpack webpack-cli --save-dev
-
在根目录下创建webpack.config.js,填入
const path=require("path"); module.exports={ entry:'./index.js',//指定入口文件 mode:'production',// 指定打包模式 output:{ filename:'build.js',// 打包过后的名字 path:path.resolve(__dirname,'build')//打包的位置 } }
-
在package.json的scripts模块中填入build,打开控制台执行npm run build,可以在根目录下发现自动创建勒一个文件夹为build,文件里出现build,即是webpack.config.js中写好的配置。
{ "name": "test-app", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build":"webpack index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "devDependencies": { "webpack": "^4.41.0", "webpack-cli": "^3.3.9" } }
ps:npm run 原理及后面的脚本为什么能够执行?
npm run 会自动新建一个 Shell,在这个 Shell 里面执行指定的脚本命令,package.json中的scripts字段一个键值对对应一条shell命令,在我们的这个地方。npm run build 等于webpack index.js,前面安装的webpack和webpack-cli是前提,在npm run 的时候会去node_modules下的bin目录下查找相应的执行命令。
完全build环境搭建
-
在config文件夹内新建paths.js写入
const path=require('path'); const fs=require('fs'); const appDir=fs.realpathSync(process.cwd()); const resolveApp=(realPath)=>path.resolve(appDir,realPath); module.exports={ dotenv: resolveApp('.env'), appBuild: resolveApp('build'), appPublic: resolveApp('public'), appHtml: resolveApp('public/index.html'), appIndexJs: resolveApp('src/index.js'), appPackageJson: resolveApp('package.json'), appSrc: resolveApp('src'), yarnLockFile: resolveApp('yarn.lock'), testsSetup: resolveApp('src/setupTests.js'), appNodeModules: resolveApp('node_modules'), }
这里我们需要使用node的fs模块,需要在webpack.config.js中写入
"target":"node" 或 "node":{fs:"empty"}//实际使用这个方式,上面那个方式打包出来之后会报错
-
将webpack.config.js移动到config目录下并改名为webpack.config.prod.js,
-
在scripts目录下新建build.js并写入
const webpack=require('webpack'); const config=require("../config/webpack.config.prod"); build(); function build(){ console.log("开始build项目") let compier=webpack(config); compier.run((err,stats)=>{ console.log(err); }) }
-
往webpack.config.prod.js中写入less,和html-webpack-plugin,执行安装npm install html-webpack-plugin --save-dev,新的webpack.config.prod.js如下,html-webpack-plugin, 需要模板,在public下建立index.html,并在配置文件中的插件配置出指定模板为该目录下的index.html,index.html只需要在body中设立一个id为root的div即可
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const paths=require('./paths.js') module.exports = { entry: paths.appIndexJs, mode: "production", output: { path: paths.appBuild, filename: 'app.js' }, node: { fs: "empty" }, module: { rules: [ { test: /\.(css|less)$/, use: [ 'style-loader', 'css-loader' , { loader: 'less-loader', options: { strictMath: true, noIeCompat: true } }], }, { test: /\.(png|svg|jpg|gif)$/, use: ['url-loader'], include:paths.appSrc, }, { test: /\.(woff|woff2|eot|ttf|otf)$/, use: ['url-loader'], include:paths.appSrc, } ], }, plugins: [ new HtmlWebpackPlugin({ inject: true, template: paths.appHtml, minify: { removeComments: true, collapseWhitespace: true, removeRedundantAttributes: true, useShortDoctype: true, removeEmptyAttributes: true, removeStyleLinkTypeAttributes: true, keepClosingSlash: true, minifyJS: true, minifyCSS: true, minifyURLs: true, }, }), ] };
-
解析jsx文件配置
需要安装babel解析jsx文件,**注意:**按照我这里的安装方式可以实现解析jsx,安装其他的不可行,具体配置可以查看babel官方文档
npm install @babel/core babel-loader@8 @babel/preset-env @babel/preset-react --save-dev
配置babel有两种方式,一种是在package.json中填入,一种是在根目录新建.babelrc填入,
{ "presets": [ "@babel/preset-react","@babel/preset-env", ] }
在webpack.config.prod.js 中的rules中写入
{ test: /\.(js|jsx)$/, exclude: paths.appNodeModules, use: { loader: 'babel-loader', } },
-
src目录下新建index.js,写入react的入口
import React from 'react'; import ReactDom from 'react-dom'; import './styles/index.less' ReactDom.render( (<h1>hello orldasdasdasdassdaasdad</h1>), document.getElementById('root') );
-
最后一步,修改package.json文件中的scripts中的build,为
"build": "node scripts/build.js",
这样既可以build出来一个可部署的项目了。build环境搭建完成。
dev开发环境搭建
- pageage.json中的scripts添加脚本
"start": "node scripts/start.js",
-
相应目录下建立start.js,控制台执行npm install webpack-dev-server react-dev-utils --save-dev
start.js内容如下
const webpack=require('webpack'); const config=require("../config/webpack.config.dev"); const { choosePort, createCompiler, prepareProxy, prepareUrls, } = require('react-dev-utils/WebpackDevServerUtils'); const HOST = process.env.HOST || '0.0.0.0'; const paths=require("../config/paths"); const clearConsole = require('react-dev-utils/clearConsole'); const WebpackDevServer=require("webpack-dev-server"); const createDevServerConfig=require("../config/devService.config"); const isInteractive = process.stdout.isTTY; const DEFAULT_PORT=3330; choosePort(HOST,DEFAULT_PORT).then(port=>{ const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; const appName = require(paths.appPackageJson).name; const urls = prepareUrls(protocol, HOST, port); const compiler=createCompiler({webpack, config, appName, urls}); const proxySetting = require(paths.appPackageJson).proxy; const proxyConfig = prepareProxy(proxySetting, paths.appPublic); const serverConfig = createDevServerConfig( proxyConfig, urls.lanUrlForConfig ); console.log("proxyConfig",serverConfig) const devServer = new WebpackDevServer(compiler, serverConfig); // Launch WebpackDevServer. devServer.listen(port, HOST, err => { if (err) { return console.log(err); } if (isInteractive) { clearConsole(); } console.log('启动dev服务'); }); ['SIGINT', 'SIGTERM'].forEach(function(sig) { process.on(sig, function() { devServer.close(); process.exit(); }); }); })
-
在当前目录下复制webpack.config.prod.js并改名为webpack.config.dev.js并更改mode为development
-
在config文件下新建devService.config.js,填入以下内容
const config = require('./webpack.config.dev'); const paths = require('./paths'); const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; const host = process.env.HOST || '0.0.0.0'; module.exports = function(proxy, allowedHost) { return { disableHostCheck: !proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true', compress: true, clientLogLevel: 'none', contentBase: paths.appPublic, watchContentBase: true, hot: true, publicPath: config.output.publicPath, quiet: true, https: protocol === 'https', host: host, overlay: false, historyApiFallback: { disableDotRule: true, }, public: allowedHost, proxy, }; };
dev环境搭建完毕。
后言
此处搭建的脚手架完成了打包部署的任务和开发时热更新的任务,还有其他打包优化和性能提升方面的配置还没有加入,如果错误之处还望指正。搭建的这个脚手架地址是:https://gitee.com/cgsx/create-app-text。
搭建这个脚手架的过程中,收获还是挺多的,踩了一些坑,知道了一些插件的使用,以及如何利用不同的插件来完成一些自动化工程的事情,具体的插件源码没有研读。只是浅显的知道这个插件的用途,收获还是满满的
public: allowedHost, proxy,
};
};dev环境搭建完毕。 ## 后言 此处搭建的脚手架完成了打包部署的任务和开发时热更新的任务,还有其他打包优化和性能提升方面的配置还没有加入,如果错误之处还望指正。搭建的这个脚手架地址是:https://gitee.com/cgsx/create-app-text。 搭建这个脚手架的过程中,收获还是挺多的,踩了一些坑,知道了一些插件的使用,以及如何利用不同的插件来完成一些自动化工程的事情,具体的插件源码没有研读。只是浅显的知道这个插件的用途,收获还是满满的