摘要:指定啟用例如上述代碼,就使用和處理了除了以外的。設置當前的為,同樣這個配置也可以寫在中。設置目錄刪除注釋去除空格去除屬性引號復制靜態(tài)目錄將所以可能被請求的靜態(tài)文件,分別放在目錄下。結(jié)語本次從零到一,新建了一個腳手架。
react-sample-javascript
為了實現(xiàn)一個可定制化高的react工程,我們往往會自己搭建一個react工程。所以本文會從零開始搭建一個react腳手架工程。解釋webpack中配置的含義。
基于webpack 4.0 。包含 開發(fā)環(huán)境配置,生產(chǎn)環(huán)境配置,代碼分離,css提取,gzip壓縮,base64加載資源,打包分析,ssh一鍵部署等常用配置。
github項目地址
[TOC]
配置 .editorconfig 使得IDE的方式統(tǒng)一 (見代碼)
配置 .eslintrc.js 使得代碼規(guī)范統(tǒng)一 (見代碼)
預期功能管理資源: 能加載css、sccc、less、以及靜態(tài)文件
管理輸出:將打包后的靜態(tài)文件輸出至static目錄下,以各自的文件類型管理
dev:使用source map,方便調(diào)試時代碼定位
dev:配置devServer,并配置熱替換,熱加載,自動刷新,自動打開瀏覽器,并預留proxyTable
dev:設置默認打開8080,被占用則尋找下一個空接口
production:代碼分離,打包css文件,css代碼壓縮,js代碼壓縮,輸出到模板html,配置gzip
analysis::使用BundleAnalyzerPlugin 分析打包后的性能
目錄結(jié)構(gòu):. │ .babelrc #babel的規(guī)則以及插件 │ .editorconfig #IDE/編輯器相關的配置 │ .eslintignore #Eslint忽視的目錄 │ .eslintrc.js #Eslint的規(guī)則和插件 │ .gitignore #Git忽視的目錄 │ .postcssrc.js #postcss的插件 │ package-lock.json │ package.json #項目相關的包 │ README.md │ yarn.lock │ ├─build #webpack相關的配置 │ utils.js #webpack配置中的通用方法 │ webpack.base.conf.js #webpack的基礎配置 │ webpack.dev.conf.js #webpack的開發(fā)環(huán)境配置 │ webpack.prod.conf.js #webpack的生產(chǎn)環(huán)境配置 │ └─src #主目錄,業(yè)務代碼 │ app.css │ App.js │ favicon.ico │ index.ejs │ index.js │ └─assets #靜態(tài)目錄,存放靜態(tài)資源 │ config.json │ └─img logo.svg安裝依賴
eslint-loader
eslint
eslint-config-airbnb
eslint-plugin-import
eslint-friendly-formatter
eslint-plugin-flowtype
eslint-plugin-jsx-a11y
eslint-plugin-react
babel-polyfill
webpack
jest
friendly-errors-webpack-plugin 編譯提示的webpack插件
html-webpack-plugin 新建html入口文件的webpack插件
copy-webpack-plugin webpack配置合并模塊
webpack-merge webpack配置合并模塊
webpack-dev-server
webpack-bundle-analyzer
webpack-cli
portfinder 尋找接口的插件
extract-text-webpack-plugin
node-notifier
optimize-css-assets-webpack-plugin
autoprefixer
mini-css-extract-plugin
autoprefixer
css-loader
less-loader
postcss-loader
postcss-import
postcss-loader
style-loader
babel-core
babel-eslint
babel-loader
babel-plugin-transform-runtime
babel-plugin-import
babel-preset-env
babel-preset-react
babel-polyfill
url-loader
cross-env
file-loader
yarn add eslint eslint-loader eslint-config-airbnb eslint-plugin-import eslint-friendly-formatter eslint-plugin-flowtype eslint-plugin-jsx-a11y eslint-plugin-react babel-polyfill webpack jest webpack-merge copy-webpack-plugin html-webpack-plugin friendly-errors-webpack-plugin webpack-dev-server webpack-bundle-analyzer webpack-cli portfinder extract-text-webpack-plugin node-notifier optimize-css-assets-webpack-plugin autoprefixer mini-css-extract-plugin autoprefixer css-loader less-loader postcss-loader postcss-import postcss-loader style-loader babel-core babel-eslint babel-loader babel-plugin-transform-runtime babel-plugin-import babel-preset-env babel-preset-react babel-polyfill url-loader cross-env file-loader -D項目配置 webpack 基礎配置
為了控制開發(fā)環(huán)境和生產(chǎn)環(huán)境,我們可以新建build文件夾。分別書寫開發(fā)環(huán)境和生產(chǎn)環(huán)境的webpack配置文件,這樣也更可以方便我們分別控制生產(chǎn)環(huán)境和開發(fā)環(huán)境。
為了提高代碼的復用率,也為了區(qū)別 基礎配置 和 個性配置 ,可以分別新建webpack.base、webpack.dev 和 webpack.prod三個配置文件。首先配置最基礎的entry(入口)和output(出口)。
module.exports = { context: path.resolve(__dirname, "../"), //絕對路徑。__dirname為當前目錄。 //基礎目錄用于從配置中解析入口起點。因為webpack配置在build下,所以傳入 "../" entry: { app: ("./src/index.js") //項目的入口 }, output: { path: path.resolve(__dirname, "../dist"), filename: "[name].[hash:8].js", publicPath: "/", libraryTarget: "umd", }, }entry
entry可以分別為字符串、數(shù)組和對象。
倘若應用只有一個單一的入口,entry的值可以使用任意類型,不會影響輸出結(jié)果。
// entry為字符串 { entry: "./src/index.js", output: { path: "/dist", filename: "bundle.js" } } // 結(jié)果會生成 "/dist/bundle.js"
// entry為數(shù)組,可以添加多個彼此不互相依賴的文件。結(jié)合output.library選項,如果傳入數(shù)組,則只導出最后一項。 { //如果你在html文件里引入了"bable-polyfill",可以通過數(shù)組將它加到bundle.js的最后。 entry: ["./src/index.js", "babel-polyfill"] , output:{ path: "/dist", filename: "bundle.js" } }
// entry為對象,可以將頁面配置為多頁面的而不是SPA,有多個html文件。通過對象告訴webpack為每個入口,成一個bundle文件。 // 多頁面的配置,可能還要借助于HtmlWebpackPlugin,來指定每個html需要引入的js { entry: { index: "./src/index.js" main: "./src/index.js" login: "./src/login.js" } output:{ path: "/dist/pages" filename: "[name]-[hash:5].js" //文件名取自"entry"對象的鍵名,為了防止推送代碼后瀏覽器讀緩存,故再生成的文件之后加上hash碼。 } } // 會分別生成index.js,main.js,login.js三個文件
關于 webpack構(gòu)建多頁面 可以參考這篇文章。不過現(xiàn)在webpack4.x也是一次斷崖式升級,感興趣的同學可以自行搜索。
// entry也可以傳入混合類型 { entry:{ vendor: ["jquery","amap","babel-polyfill"] //也可以借助CommonsChunkPlugin提取vendor的chunk。 index: "./src/index.js" } output: { path: "/dist" filename: "[name]-[hash:5].js" } }
CommonsChunkPlugin在webpack4.0之后移除了,可以使用splitChunksPlugin代替。output可以參閱如下鏈接:optimization.splitChunks
output最基礎的兩個配置為 path 和 filename :
path 告訴 webpack的輸出目錄在那里,一般我們會設置在根目錄的 dist 文件夾;
filename 用于指定輸出文件的文件名,如果配置了創(chuàng)建了多個多帶帶的 chunk 則可以使用 [name].[hash] 這種占位符來確保每個文件有唯一的名稱;
另一個常見配置 publicPath 則是用于更加復雜的場景。舉例:在本地時,你可能會使用 ../assets/test.png 這種url來載入圖片。而在生產(chǎn)環(huán)境下,你可能會使用CDN或者圖床的地址。那么就需要配置 publicPath = "http://cdn.example.com/assets/" 來實現(xiàn)生產(chǎn)模式下編譯輸出文件時自動更新url。
output: { path: path.resolve(__dirname, "../dist"), filename: "[name].[hash:8].js", publicPath: "/", },resolve
resolve常用的兩個配置為 alias 和 extensions :
alias 創(chuàng)建import或者require的別名
extensins 自動解析文件拓展名,補全文件后綴
resolve: { // 自動解析文件擴展名(補全文件后綴)(從左->右) // import hello from "./hello" (!hello.js? -> !hello.jsx? -> !hello.json) extensions: [".js", ".jsx", ".json"], alias: { "@": resolve("src") } },module
module的選項決定了如何處理項目中的不同類型的模塊。其中常用的有 rules 和 noParese 兩個配置項。
noParese 是為了防止weback解析與所有與rule相匹配的文件。目的是,忽略大型的library可以提高構(gòu)建性能。
noParse: function(content) { return /jquery|lodash/.test(content); }
rules 用于在創(chuàng)建模塊是,匹配規(guī)則數(shù)組,以確定哪些規(guī)則能夠?qū)odule應用loader,或者是修改parser。
module: { rules: [ { test: /.(js|jsx)$/, exclude: /node_modules/, enforce: "pre", use: [{ loader: "babel-loader", }, { loader: "eslint-loader", // 指定啟用eslint-loader options: { formatter: require("eslint-friendly-formatter"), emitWarning: false } }] }, { test: /.css$/, include: /node_modules/, use: [ MiniCssExtractPlugin.loader, "css-loader", { loader: "postcss-loader", options: { plugins: () => [autoprefixer({ browsers: "last 5 versions" })], sourceMap: false, }, }, ], }, { test: /.(png|jpe?g|gif|svg)(?.*)?$/, loader: "url-loader", options: { limit: 10000, name: ("assets/img/[name].[hash:7].[ext]") } }, { test: /.(mp4|webm|ogg|mp3|wav|flac|aac)(?.*)?$/, loader: "url-loader", options: { limit: 10000, name: ("assets/media/[name].[hash:7].[ext]") } }, { test: /.(woff2?|eot|ttf|otf)(?.*)?$/, loader: "url-loader", options: { limit: 10000, name: ("assets/fonts/[name].[hash:7].[ext]") } } ] }
例如上述代碼,就使用eslint-lodaer 和 babel-loader 處理了除了node_modules 以外的 js||jsx。同時配置了,解析圖片、視頻、字體文件等的解析,當rules匹配到的文件時,小于10000 byte 時,采用url-loader解析文件。
Webpack開發(fā)配置因為在webpack 4.X 中使用了流行的 ”約定大于配置“ 的做法,所以在新加入配置項 mode ,可以告知webpack使用相應模式的內(nèi)置優(yōu)化。
選項 | 描述 |
---|---|
development | 會將process.env.NODE_ENV 的值設為 development 。啟用 NamedChunksPlugin 和 NamedMoudulesPlugin。 |
production | 會將process.env.NODE_ENV 的值設為 production 。啟用 FlagDependencyUsagePlugin,FlagIncludedChunksPlugin,ModuleConcatenationPlugin,NoEmitOnErrorsPlugin,OccurrenceOrderPlugin,SideEffectsFlagPlugin 和UglifyJsPlugin。 |
如果我們只設置NODE_ENV,則不會自動設置 mode
在開發(fā)時,我們往往希望能看到當前開發(fā)的頁面,并且能熱加載。這時,我們可以借助webpack-dev-server 這個插件,來在項目中起一個應用服務器。
// package.json "scripts": { "start": "webpack-dev-server --mode development --config build/webpack.dev.conf.js", } // 設置當前的mode為development,同樣這個配置也可以寫在webpack.dev.conf.js中。然后使用build目錄下的webpack.dev.conf.js 來配置相關的webpack。
devServer: { clientLogLevel: "warning", historyApiFallback: true, //在開發(fā)單頁應用時非常有用,它依賴于HTML5 history API,如果設置為true,所有的跳轉(zhuǎn)將指向index.html contentBase: path.resolve(__dirname, "../src"), compress: true, hot: true, // 熱加載 inline: true, //自動刷新 open: true, //自動打開瀏覽器 host: HOST||"localhost", port: PORT, overlay: { warnings: false, errors: true }, // 在瀏覽器上全屏顯示編譯的errors或warnings。 publicPath: "/", proxy: {}, quiet: true, // necessary for FriendlyErrorsPlugin // 終端輸出的只有初始啟動信息。 webpack 的警告和錯誤是不輸出到終端的 watchOptions: { poll: false } }, plugins: [ new webpack.DefinePlugin({ ...process.env }), //開啟HMR(熱替換功能,替換更新部分,不重載頁面!) new webpack.HotModuleReplacementPlugin(),// HMR shows correct file names in console on update. //顯示模塊相對路徑 new webpack.NamedModulesPlugin(), //不顯示錯誤信息 new webpack.NoEmitOnErrorsPlugin(), // https://github.com/ampedandwired/html-webpack-plugin ]
其實在開發(fā)時,我們可以設置 contentBase: "/src" ,contentBase 指定了devServer能訪問的資源地址。因為我們開發(fā)時,資源大部分都放在src目錄下,所以可以直接指定資源路徑為src目錄。因為我們在webpack基礎配置時,配置了 output 輸出為 dist 目錄,所以我們也可以在devServer里,設置 contentBase 為 dist 目錄。不過此時需要使用copyWebpackPlugin將一些靜態(tài)資源復制到 dist 目錄下,手動新建dist目錄,并復制也可以。
另外,當使用 history 路由時,要配置 historyApiFallback = true ,以此讓服務器放棄路由權(quán)限,交由前端路由。而是用 hash 路由則不需要此配置。
項目進階 生產(chǎn)環(huán)境配置在使用webpack 4.x 的 mode 配置之后,需要我們手動配置的項已經(jīng)減少了很多,像js代碼壓縮這種工具 UglifyJsPlugin 就已經(jīng)不用手動去配置。但是像很多前面提到的 代碼分離 、css代碼提取和壓縮 、html的生成 以及 復制靜態(tài)資源 還需要我們手動配置。
代碼分離// 設置代碼分離的輸出目錄 output: { path: path.resolve(__dirname, "../dist"), filename: ("js/[name].[hash:8].js"), chunkFilename: ("js/[name]-[id].[hash:8].js") }, // 代碼分離 optimization: { runtimeChunk: { name: "manifest" }, splitChunks: { chunks: "all" } },
可以參閱如下鏈接:optimization.splitChunkscss代碼壓縮
借助 MiniCssExtractPlugin 來實現(xiàn)壓縮css和提取css。因為 MiniCssExtractPlugin 無法與style-loader 共存,所以我們需要判斷當前環(huán)境是生成環(huán)境還是開發(fā)環(huán)境。
我們可以新建一個util.js的文件,在webpack當中一些共用的方法。考慮使用個別配置字段 extract 來配置使用何種方式來配置css-loader。參見 util.js 代碼。
new MiniCssExtractPlugin({ filename: "css/[name].[hash:8].css", chunkFilename: "css/[name]-[id].[hash:8].css", }),生成HTML
使用htmlWebpackPlugin,配合ejs。可以使控制html 的生成。通過配置的方式,生成html。因為 HtmlWebpackPlugin 本身可以解析ejs,所以不需要多帶帶引入ejs的loader。
new HtmlWebpackPlugin({ filename: "index.html", template: "./src/index.ejs", // 設置目錄 title: "React Demo", inject: true, // true->"head" || false->"body" minify: { //刪除Html注釋 removeComments: true, //去除空格 collapseWhitespace: true, //去除屬性引號 removeAttributeQuotes: true // more options: // https://github.com/kangax/html-minifier#options-quick-reference }, // necessary to consistently work with multiple chunks via CommonsChunkPlugin chunksSortMode: "dependency" }),
復制靜態(tài)目錄<%= htmlWebpackPlugin.options.title %> <% for (var chunk in htmlWebpackPlugin.files.css) { %> <% } %> <% for (var chunk in htmlWebpackPlugin.files.chunks) { %> <% } %>
將所以可能被請求的靜態(tài)文件,分別放在assets目錄下。那么在打包后,為了保證目錄能正常訪問(不使用CDN等加載靜態(tài)資源時),我們可以配置 publicPath = "/" 。然后借助于 CopyWebpackPlugin 實現(xiàn)資源復制。
new CopyWebpackPlugin([{ from: "./src/assets/", to: "assets" }]),
將 src/assets 復制到 dist/assets 目錄下。
開啟打包分析借助插件 BundleAnalyzerPlugin 直接在plugins中創(chuàng)建該插件:
// webpack.prod.conf.js const BundleAnalyzerPlugin = process.env.NODE_ENV=== "analysis" ? require("webpack-bundle-analyzer").BundleAnalyzerPlugin:null process.env.NODE_ENV=== "analysis" ? new BundleAnalyzerPlugin() : ()=>{}
在package.json 中可做如下配置:
"scripts": { "analysis": "cross-env NODE_ENV=analysis webpack -p --mode production --progress --config ./build/webpack.prod.conf.js ", },
通過注入環(huán)境變量,來控制是否運行打包分析。
ssh部署打包后的dist文件夾,可以直接借助 node 的 ssh-node ,直接部署到服務器指定的目錄下。 ssh-node既支持ssh,也支持密碼登錄。建議可以為在每個項目下,新建一個.ssh文件,存放項目的私鑰。代碼如下:
// usage: https://www.npmjs.com/package/node-ssh var path, node_ssh, ssh, fs, opn, host fs = require("fs") path = require("path") node_ssh = require("node-ssh") opn = new require("opn") ssh = new node_ssh() host = "localhost" var localDir = "./dist" var remoteDir = "/opt/frontend/new" var removeCommand = "rm -rf ./*" var pwdCommand = "pwd" ssh.connect({ host: host, username: "root", port: 22, // password, privateKey: "./.ssh/id_rsa", }) .then(function() { ssh.execCommand(removeCommand, { cwd:remoteDir }).then(function(result) { console.log("STDOUT: " + result.stdout) console.log("STDERR: " + result.stderr) ssh.putDirectory(localDir, remoteDir).then(function() { console.log("The File thing is done") ssh.dispose() opn("http://"+host, {app:["chrome"]}) }, function(error) { console.log("Something"s wrong") console.log(error) ssh.dispose() }) }) })
此時,在命令行直接 node deploy.js 就可以運行以上腳本,我們也可以添加一個build + deploy的script腳本,便于啟動。
"scripts": { "depoly": "npm run build && node ./deploy.js", }結(jié)語
本次從零到一,新建了一個react腳手架。過程中有很多問題,也參考了不少大牛的解釋。代碼里也有諸多問題。還望各位看官,不吝指教。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/108085.html
摘要:廢話不多話,來上車安裝或者簡述使用創(chuàng)建全局的樣式首先創(chuàng)建一個文件,例如引全局包里面為項目需要的內(nèi)容在組件內(nèi)把引入的當做標簽寫入創(chuàng)建一個局部的樣式引局部包里面為項目需要的內(nèi)容在組件內(nèi)把引入的當做標簽寫入類嵌套類似于用法大同小異列舉 廢話不多話,來上車! 安裝: npm install --save styled-components (或者 yarn add styled-com...
摘要:原文從零到一,擼一個在線斗地主上篇作者背景朋友來深圳玩,若說到在深圳有什么好玩的,那當然是宅在家里斗地主了可是天算不如人算,撲克牌丟了幾張不全大熱天的,誰愿意出去買牌啊。 原文:從零到一,擼一個在線斗地主(上篇) | AlloyTeam作者:TAT.vorshen 背景:朋友來深圳玩,若說到在深圳有什么好玩的,那當然是宅在家里斗地主了!可是天算不如人算,撲克牌丟了幾張不全……大熱天的,...
閱讀 865·2021-10-11 10:59
閱讀 2801·2019-08-30 15:43
閱讀 2133·2019-08-30 11:08
閱讀 1656·2019-08-29 15:20
閱讀 1011·2019-08-29 13:53
閱讀 489·2019-08-26 13:24
閱讀 1637·2019-08-26 13:24
閱讀 2825·2019-08-26 12:08