I'm relatively new to modern JS development and I need help or advice about this situation I'm in.
Situation: We have a React-Typescript-Redux project supporting IE8 (React 0.14). Now we're upgrading to IE11 and React 16 but IE8 should be supported.
Requirement: Reduce project maintenance between browser versions by using different packages and/ or config files for each build.
Problem: From research I made so far it seems impossible to use different package.json files and node_modules folders inside the same project with selected tools: npm, Webpack, React, Redux, Typescript. Yarn seems to support multiple package.json files but we'd like to avoid migrating from npm if possible.
Current project structure:
project_root/ node_modules/ src/ components/ utils/ index.tsx components.css index.html package.json tsconfig.json webpack.config.json
What I thought might work was to introduce IE8 subfolder with its package.json and node_modules folder and then reference that folder for the build task somehow but now I'm oblivious how to tell npm to reference it on build.
Proposed project structure:
project_root/ ie8/ node_modules/ package.json node_modules/ src/ components/ utils/ index.tsx components.css index.html package.json tsconfig.json webpack.config.json
I tried different things found on web, including resolve.modules: [__dirname + "/ie8/node_modules"]
but it seems it doesn't work or I misunderstand what it does because I get Cannot find name 'require'
errors on several files and Typescript 2.8.3 is referenced in terminal output instead 2.3.4. Without it, project builds with configuration for IE11.
So, can anybody tell me with certainty it's not possible or offer some guidance? This is the closest answer I found so far but doesn't sound final. Alternatively, can project structure like this support what is required or separating project into two is the best bet?
Thanks in advance.
json file, but there is nothing inherently wrong with multiple package. json files within a repo. Some companies do use mono-repos, for which it would make total sense to have multiple package. json files.
To npm install a public project that is hosted on Github, and not the NPM registry, add the Github repo to package. json dependencies using the username/repo#branch-name format. Run npm install and npm will download the project and save it into your /node_modules/ folder.
OK, so after some more research I stumbled upon Lerna which mostly allows me to do what I wanted (from what I've seen so far). It requires specific project tree setup, like this:
project_root/ node_modules/ packages/ components/ // Components shared between projects components/ MyComponent.jsx index.jsx legacy/ output/ build.js // React 0.14 build node_modules/ package.json // project specific dependencies index.jsx // project specific entry .babelrc modern/ output/ build.js // React 16 build node_modules/ package.json // project specific dependencies index.jsx // project specific entry .babelrc package.json // contains devDependencies shared between projects lerna.json webpack.config.js index.html
Then, in components/index.jsx I specified require commands for different versions based on global variable:
if(PROJECT_SRC == "legacy"){ React = require('../legacy/node_modules/react'); ReactDOM = require('../legacy/node_modules/react-dom'); } else { React = require('../modern/node_modules/react'); ReactDOM = require('../modern/node_modules/react-dom'); }
Note: This is probably bad practice but the only way at the moment I could include different React versions in the build. I'll have to see what problems arise with this approach after the whole project changes to this model.
In webpack.config.js I configured two exports - one for modern and one for legacy. Each points to a different entry index.jsx file, uses webpack.DefinePlugin to set global variable to "legacy" or "modern", and specifies path to common components module to resolve: ['node_modules', path.resolve(__dirname, 'components')]
webpack.config for a single project output looks something like this:
{ entry: "./packages/legacy/index.jsx", target: "web", output: { filename: "build.js", path: __dirname + "/packages/legacy/dist/", libraryTarget: "var", library: "lib_name" }, devtool: "source-map", resolve: { extensions: [".js", ".jsx", ".json"], modules: ['node_modules', path.resolve(__dirname, 'components')] }, plugins: plugins_legacy, module: { loaders: [ { test: /\.jsx?$/, loader: "babel-loader", exclude: /node_modules/ } ] } }
Feel free to comment or point to problems but I hope this will help somebody in the future! :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With