【问题标题】:Webpack 3 + babel only parsing when entry is NOT higher than ./webpack.config.jsWebpack 3 + babel 仅在条目不高于 ./webpack.config.js 时解析
【发布时间】:2017-08-13 20:44:38
【问题描述】:

我正在构建一个脚手架引擎来启动 Django-backend + React-frontend 站点。我还采用了多页应用程序方法,而不是 SPA,所以事情有点……非正统。

我正在向您展示该脚手架的最终结果,因为问题似乎与我的 webpack 或 babel 配置以及我给它们的输入组件的位置有关。

首先,这个文件结构确实有效,react 组件在 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 目录中。但这不是 polyfill,并且生成的输出文件已损坏。我不只是说它丑化了,我的意思是它完全坏掉了(见下文)

有没有可能做我想做的事?

详情

我运行 '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)}/*

【问题讨论】:

    标签: javascript webpack babeljs


    【解决方案1】:

    问题在于Babel looks for a .babelrc closest to the file that is being transpiled。这意味着它在文件的目录中查找并开始向上爬目录树,直到找到一个或到达文件系统的根目录。但是由于您的 node 目录是 www 的兄弟,而您的资源所在的位置,因此无法找到您的 .babelrc,因此您的预设不会被应用。

    您可以配置options on babel-loader,无论目录如何都将使用它。不幸的是,您会遇到模块分辨率问题,默认情况下与Node module resolution 相同。当一个模块被导入时,它将在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 允许您使用 resolve.module 解决这个问题。

    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 构建。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-05
      • 2016-02-04
      • 2019-07-07
      • 2017-05-28
      • 2017-11-24
      • 2016-12-15
      • 1970-01-01
      • 2018-11-26
      相关资源
      最近更新 更多