我正在构建一个脚手架引擎来启动Django-backend + React-frontend站点。我也采用了多页应用程序方法,而不是SPA,所以事情有点......非正统。
我向你展示了脚手架的最终结果,因为问题似乎是我的webpack或babel配置,以及我给它们的输入组件的位置。
首先,这个文件结构正常工作,反应组件在Django的服务器上渲染得很漂亮。
node/
package.json
.babelrc
webpack.config.js
/src
/Home.js (<- the react component)
...
www/
manage.py
www/
templates/
home.html
dist/
home.js (<- webpack's output)
...
但我更喜欢这样,组件更接近django template.html文件:
node/
package.json
.babelrc
webpack.config.js
...
www/
manage.py
www/
templates/
home.html
react/
components/
containers/
Home.js (<- the react component)
dist/
home.js (<- webpack's output)
然而,我现在得到一个构建错误,它在看到JSX时会抱怨 - 好像babel根本没有填充它。
我唯一改变的是是组件不再位于node /目录下(显然我更新了webpack.config.js中的路径以反映它)
我认为这不是webpack寻找合适途径的问题。因为它正在读取模板目录中的组件,并且它仍然正确地将包放在dist目录中。但它不是polyfilling,结果输出文件被破坏了。我不仅仅意味着它被丑化了,我的意思是它完全崩溃了(见下文)
甚至可以做我想做的事情吗?
详情
运行'npm run build'运行webpack时的错误:
ERROR in ../www/www/templates/react/containers/HomeContainer.js
Module build failed: SyntaxError: Unexpected token (6:2)
4 | const Home = props => {
5 | return (
> 6 | <div>
babelrc
{
"presets": ["env", "react"]
}
webpack.config.js
const webpack = require('webpack'); //to access built-in plugins
const path = require('path');
// This one works
// let ent = "./HomeContainer.js"
// This one does NOT work
let ent = "../www/www/templates/react/containers/HomeContainer.js"
let out = "../www/www/static/dist/js/Home"
module.exports = {
entry: {
[out]: ent
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, './'),
},
module: {
rules: [
{ test: /\.css$/, exclude: /node_modules/, use: 'css-loader' },
{ test: /\.scss$/, exclude: /node_modules/, use: 'sass-loader' },
{ test: /\.(js|jsx)$/, exclude: /node_modules/, loader: "babel-loader" }
],
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
],
}
的package.json
{
"name": "frontend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo 'Error: no test specified' && exit 1",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"babel-cli": "^6.24.1",
"babel-core": "^6.25.0",
"babel-loader": "^7.1.1",
"babel-preset-env": "^1.6.0",
"babel-preset-react": "^6.24.1",
"css-loader": "^0.28.4",
"node-sass": "^4.5.3",
"sass-loader": "^6.0.6",
"webpack": "^3.1.0"
},
"dependencies": {
"react": "^15.6.1",
"react-dom": "^15.6.1"
}
}
破碎的dist / home.js
!function(m){function t(e){if(n[e])return n[e].exports;var r=n[e]={i:e,l:!1,exports:{}};return m[e].call(r.exports,r,r.exports,t),r.l=!0,r.exports}var n={};t.m=m,t.c=n,t.d=function(m,n,e){t.o(m,n)||Object.defineProperty(m,n,{configurable:!1,enumerable:!0,get:e})},t.n=function(m){var n=m&&m.__esModule?function(){return m.default}:function(){return m};return t.d(n,"a",n),n},t.o=function(m,t){return Object.prototype.hasOwnProperty.call(m,t)},t.p="",t(t.s=0)}([function(m,t){throw new Error("Module build failed: SyntaxError: Unexpected token (6:2)\n\n[0m [90m 4 | [39m[36mconst[39m [33mHome[39m [33m=[39m props [33m=>[39m {\n [90m 5 | [39m\t[36mreturn[39m (\n[31m[1m>[22m[39m[90m 6 | [39m\t\t[33m<[39m[33mdiv[39m[33m>[39m\n [90m | [39m\t\t[31m[1m^[22m[39m\n [90m 7 | [39m\t\t\t[33m<[39m[33mh1[39m[33m>[39m[33mHome[39m page [36mfor[39m { window[33m.[39mprops[33m.[39mproject_title }[33m<[39m[33m/[39m[33mh1[39m[33m>[39m\n [90m 8 | [39m\t\t\t[33m<[39m[33mp[39m[33m>[39m[33mTo[39m edit [36mthis[39m page[33m,[39m you[32m'll find the react component at /frontend/src/root/Home.js</p>[39m\n [90m 9 | [39m\t\t[33m<[39m[33m/[39m[33mdiv[39m[33m>[39m[0m\n")}]);
有效的dist / home.js
!function(e){function t(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,t),r.l=!0,r.exports}var n={};t.m=e,t.c=n,t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:o})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=81)}([function(e,t){function n(){throw new Error("setTimeout has not been defined")}function o(){throw new Error("clearTimeout has not been defined")}function r(e){if(l===setTimeout)return setTimeout(e,0);if((l===n||!l)&&setTimeout)return l=setTimeout,setTimeout(e,0);try{return l(e,0)}catch(t){try{return l.call(null,e,0)}catch(t){return l.call(this,e,0)}}}function i(e){if(p===clearTimeout)return clearTimeout(e);if((p===o||!p)&&clearTimeout)return p=clearTimeout,clearTimeout(e);try{return p(e)}catch(t){try{return p.call(null,e)}catch(t){return p.call(this,e)}}}function a(){m&&f&&(m=!1,f.length?h=f.concat(h):v=-1,h.length&&s())}function s(){if(!m){var e=r(a);m=!0;for(var t=h.length;t;){for(f=h,h=[];++v<t;)f&&f[v].run();v=-1,t=h.length}f=null,m=!1,i(e)}}function u(e,t){this.fun=e,this.array=t}function c(){}var l,p,d=e.exports={};!function(){try{l="function"==typeof setTimeout?setTimeout:n}catch(e){l=n}try{p="function"==typeof clearTimeout?clearTimeout:o}catch(e){p=o}}();var f,h=[],m=!1,v=-1;d.nextTick=function(e){var t=new Array(arguments.length-1);if(arguments.length>1)for(var n=1;n<arguments.length;n++)t[n-1]=arguments[n];h.push(new u(e,t)),1!==h.length||m||r(s)},u.prototype.run=function(){this.fun.apply(null,this.array)},d.title="browser",d.browser=!0,d.env={},d.argv=[],d.version="",d.versions={},d.on=c,d.addListener=c,d.once=c,d.off=c,d.removeListener=c,d.removeAllListeners=c,d.emit=c,d.prependListener=c,d.prependOnceListener=c,d.listeners=function(e){return[]},d.binding=function(e){throw new Error("process.binding is not supported")},d.cwd=function(){return"/"},d.chdir=function(e){throw new Error("process.chdir is not supported")},d.umask=function(){return 0}},function(e,t,n){"use strict";(function(t){function n(e,t,n,r,i,a,s,u){if(o(t),!e){var c;if(void 0===t)c=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var l=[n,r,i,a,s,u],p=0;c=new Error(t.replace(/%s/g,function(){return l[p++]})),c.name="Invariant Violation"}throw c.framesToPop=1,c}}var o=function(e){};"production"!==t.env.NODE_ENV&&(o=function(e){if(void 0===e)throw new Error("invariant requires an error message argument")}),e.exports=n}).call(t,n(0))},function(e,t,n){"use strict";(function(t){var o=n(9),r=o;if("production"!==t.env.NODE_ENV){var i=function(e){for(var t=arguments.length,n=Array(t>1?t-1:0),o=1;o<t;o++)n[o-1]=arguments[o];var r=0,i="Warning: "+e.replace(/%s/g,function(){return n[r++]});"undefined"!=typeof console&&console.error(i);try{throw new Error(i)}catch(e){}};r=function(e,t){if(void 0===t)throw new Error("`warning(condition, format, ...args)` requires a warning message argument");if(0!==t.indexOf("Failed Composite propType: ")&&!e){for(var n=arguments.length,o=Array(n>2?n-2:0),r=2;r<n;r++)o[r-2]=arguments[r];i.apply(void 0,[t].concat(o))}}}e.exports=r}).call(t,n(0))},function(e,t,n){"use strict";function o(e){for(var t=arguments.length-1,n="Minified React error #"+e+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+e,o=0;o<t;o++)n+="&args[]="+encodeURIComponent(arguments[o+1]);n+=" for the full message or use the non-minified dev environment for full errors and additional helpful warnings.";var r=new Error(n);throw r.name="Invariant Violation",r.framesToPop=1,r}e.exports=o},function(e,t,n){"use strict";function o(e){if(null===e||void 0===e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}/*
答案 0 :(得分:2)
问题在于Babel looks for a .babelrc
closest to the file that is being transpiled。这意味着它查找文件的目录并开始爬上目录树,直到找到一个或到达文件系统的根目录。但由于您的node
目录是www
的兄弟,您的来源所在,因此无法找到您的.babelrc
,因此您的预设将不会被应用。
您可以配置options on babel-loader
,无论目录如何,都将使用该Node module resolution。不幸的是,您将遇到模块解析的问题,默认情况下与resolve.module
相同。导入模块时,将在node_modules
目录中搜索该模块,如果在该目录中未找到该模块,则会在父目录(即../node_modules
)中查找,依此类推。这与Babel使用的行为相同,这对于Node中的工具来说非常常见。
可以在配置中导入预设,因此不会从正在编译的文件中解析它们。
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
// Need to require them, so they are resolved from this config,
// otherwise they are resolved from the directory of the file that
// is being transpiled.
require('babel-preset-env'),
require('babel-preset-react')
]
}
}
除此之外,您将面临解决使用npm安装的任何模块的问题,因为它们再次位于同级目录中并且将无法找到。 Webpack允许您使用DRY解决该问题。
resolve: {
modules: [
// Also look for modules next to the webpack config, because dependencies
// like `react` are installed here, not where the components are.
path.resolve(__dirname, 'node_modules'),
'node_modules'
],
}
尽管有效,但我强烈反对这种结构。毕竟这是webpack中的一种解决方法,如果你想添加任何其他工具,你很可能会遇到问题。
最重要的部分是节点模块应该位于项目的根目录中,任何想要使用它们的东西都在子目录中。像这样:
.
├─ .babelrc
├─ manage.py
├─ package.json
├─ webpack.config.js
└─ www
├─ dist
│ └─ bundle.js
└─ templates
├─ home.html
└─ react
├─ components
└─ containers
└─ Home.js
有了这个,你不需要解决任何问题,你可以确定从npm安装的任何模块都可以工作。此外,您可以从项目的根目录运行所有内容,无论是安装npm包,运行webpack还是运行python构建。